Ubuntu 18.04 LTSにDockerを入れて機械学習環境を構築

前回の続き。

Ubuntuが無事(?)に入ったところで、いよいよDocker入れてTensorFlow入れて機械学習をゴリゴリやりたいところですが、その前にはやっぱり準備が必要です。

参考: Docker  |  TensorFlow

やったこと

もたもたとアプデ確認
Dockerのインストール
TensorFlowのDockerイメージを取得?
Dockerイメージを適用して環境構築?
動作確認?

もたもた

諸事情で前回作業から間が空きまくってしまったので、アップデートの確認とか色々します。

パッケージ一覧取得
$ sudo apt update
パッケージの更新
$ sudo apt dist-upgrade
不要になったパッケージの削除
$ sudo apt autoremove

Ubuntuのバージョン管理ツールも入れます。(多分最初から入っているけど念の為)
$ sudo apt install update-manager-core

Ubuntuのアップグレードチェック
$ do-release-upgrade -c
おっと、Ubuntuの最新版は19.10でしたが、LTSはまだなかったみたいです。
There is no development version of an LTS available. To upgrade to the latest non-LTS develoment release set Prompt=normal in /etc/update-manager/release-upgrades.

画面の解像度?表示倍率?がおかしかったのでNVIDIAのドライバを再インストール

古いドライバ削除
$ sudo apt --purge remove nvidia-*
パッケージ情報更新
$ sudo apt update
推奨ドライバ確認
$ ubuntu-drivers devices
 (略) nvidia-driver-435 がrecommended
あれ?公式のドライバ検索だと440なんだけど……??

ウーンPPA。
$ sudo add-apt-repository ppa:graphics-drivers/ppa
パッケージ情報更新
$ sudo apt update
推奨ドライバを再度確認
$ ubuntu-drivers devices
 (略)  nvidia-driver-440 がrecommended
公式のドライバ検索と同じ結果になった。

インストール
$ sudo apt install nvidia-driver-440
再起動
$ sudo reboot
……解像度なおったわ!!!

nvidiaの情報チェック
$ nvidia-smi
 (略) 問題なさげ

これでやっとまともにUbuntuのセットアップ作業ができる……
参考: Ubuntu Linux 18.04にGPUドライバをインストールする|setoyama60jp|note

Dockerインストール

アプデチェックはこの辺にして、Dockerを入れます。どっか~んっ!

参考: Get Docker Engine – Community for Ubuntu | Docker Documentation

パッケージ一覧を更新
$ sudo apt update

HTTPSでdocker repositoryを利用するためのパッケージを導入

$ sudo apt install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common

Dockerの公式のGPG Keyを追加
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

repositoryを追加

$ sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"

パッケージ一覧を再度更新
$ sudo apt update

Dockerのインストール
$ sudo apt install docker-ce

インストールできたらDockerのバージョン確認
$ docker version

Client: Docker Engine - Community
Version: 19.03.4
API version: 1.40
Go version: go1.12.10
Git commit: 9013bf583a
Built: Fri Oct 18 15:54:09 2019
OS/Arch: linux/amd64
Experimental: false
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.40/version: dial unix /var/run/docker.sock: connect: permission denied

Linux で GPU サポートを有効にするため、nvidia-dockerをインストール

# Add the package repositories
$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
$ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

# Install package and restart docker
$ sudo apt update && sudo apt install -y nvidia-container-toolkit
$ sudo systemctl restart docker

TensorFlowセットアップ

TensorFlow の Docker イメージをダウンロード

latest stable release versionのイメージを取得
$ docker pull tensorflow/tensorflow

参考: Docker | TensorFlow

TensorFlow Docker コンテナを起動確認

$ sudo docker run --rm -it -p 8888:8888 tensorflow/tensorflow:latest-py3

~~~~(略)~~~~
Status: Downloaded newer image for tensorflow/tensorflow:latest-py3

________                               _______________
___  __/__________________________________  ____/__  /________      __
__  /  _   \  __ \_  ___/  __ \_  ___/  /   __  /_  __ \_ | /| / /
_  /   /  __/  / / /(__  )/ /_/ /  /   _  __/    / / // /_ |/ |/ /
/_/    \___/// ///____/ \____///    //      /_/  \____/____/|__/

WARNING: You are running this container as root, which can cause new files in
mounted volumes to be created as the root user on your host machine.
To avoid this, run the container by specifying your user's userid:
$ docker run -u $(id -u):$(id -g) args...

なんかでた。

外部からAIサーバとして使うために固定IPアドレスを指定

参考: Ubuntu 18.04 LTSで固定IPアドレスの設定 – Qiita

参考: Ubuntu18.04 LTSでネットワークの設定方法 – ちゃんおぎのメモ置き場

元の

# Let NetworkManager manage all devices on this system
network:
version: 2
renderer: NetworkManager

変更後

# Let NetworkManager manage all devices on this system
network:
version: 2
renderer: NetworkManager

ethernets:
enp3s0:
dhcp4: n
addresses: [192.168.x.xxx/24]
gateway4: 192.168.x.1
nameservers:
addresses: [192.168.x.1]
dhcp6: n

PuTTYでSSHログインのテストしてちゃんと繋がったので、とりあえずこんな感じで作業終了。疲れた。

参考

How to build mapbox-gl-js stand-alone on Windows

実質作業メモ。Windowsでの話です。

追記

ビルド作業が初めてではない(下記本編の内容を実施済み等)場合、ツール群のインストールは不要なため、下記手順のみ行う。

  1. cmd開いて cd mapbox-gl-js (ディレクトリ移動)して
  2. SET MAPBOX_ACCESS_TOKEN={YOUR MAPBOX ACCESS TOKEN} して
  3. yarn install して(必要なら)
  4. ファイル生成
    yarn run build-prod-min → dist/mapbox-gl.js
    yarn run build-css → dist/mapbox-gl.css

本編

下記のページに手順が書いてあるので実施していきます。

mapbox-gl-js/CONTRIBUTING.md at master · mapbox/mapbox-gl-js · GitHub

必要なツール群をインストール

Install gitnode.js (version 4 or greater), yarnnpm and node-gyp.

と書いてあるので、それぞれインストールしていきましょう。

git

もう入ってた。

node.js

ダウンロード | Node.js からWindows用のインストーラーをDLして実行して終わり。

Yarn 

Installation | Yarn からWindows用のStable(安定版) ver.のインストーラーをDLして実行して終わり。

npm and node-gyp.

nodejs-guidelines/windows-environment.md at master · microsoft/nodejs-guidelines · GitHub に詳しい。

  1. Windows PowerShell を管理者権限で起動
  2. npm install -g windows-build-tools を実行し、
    windows-build-tools をインストール
    ※トラブルシューティング情報も上記ページに記載あり
  3. Visual Studio Build Tools あるいは Visual Studio 2017 Community より、Visual C++ ビルド環境をインストール
  4. https://www.python.org/downloads/ よりPython2.7をインストール
  5. npm config set python python2.7 を実行
  6. npm config set msvs_version 2017 を実行

リポジトリをクローンする

git clone git@github.com:mapbox/mapbox-gl-js.git とコマンドを打ってもいいし、適当なGitHubクライアントでCloneしてもいい。

※特定のバージョンや安定版がほしい場合は、下記ページからzip等でファイルを取得する。
https://github.com/mapbox/mapbox-gl-js/releases

node moduleの依存関係をインストールする

  1. cd mapbox-gl-js (ディレクトリ移動)して
  2. yarn install を実行してインストール

warning "@mapbox/dr-ui > @mapbox/mapbox-gl-supported@1.4.1" has unmet peer dependency "mapbox-gl@>=0.32.1 <2.0.0". とかみたいなエラーが出たら、cmdを閉じて開き直してインストールコマンドを再実行すると多分解決する。

headless-gl の依存関係をインストールする

依存関係は下記。  https://github.com/stackgl/headless-gl#windows

  • Python 2.7
    ※ 先ほどの手順でインストール済
  • Microsoft Visual Studio
    ※ Visual C++ ビルド環境がほしいだけなので先程の手順でインストール済
  • d3dcompiler_47.dll
    c:\windows\system32に入っているのでOK
  • ES6 (モダンnode.js向け。オプション)
    ※ オプションなので多分不要

最終的にやりたいことは下記コマンドの通り。
copy node_modules/headless-gl/deps/windows/dll/x64/*.dll c:\windows\system32

headless-glをクローンする

stackgl/headless-gl: 🎃 Windowless WebGL for node.js をクローンする。

※特定のバージョンや安定版がほしい場合は、下記ページからzip等でファイルを取得する。
https://github.com/stackgl/headless-gl/releases

dllファイルをコピー

headless-gl\deps\windows\dll\x64\以下のdllファイルをc:\windows\system32 にコピーする。

ビルドに使うデバッグサーバの用意

mapboxアクセストークンの取得

  1. Mapbox のアカウントを作成
  2. Account | Mapbox > Tokens > Create a token からアクセストークンを作成
  3. Tokens にて、作成したトークンをコピー

デバッグサーバ起動確認

  1. cmdを起動して cd mapbox-gl-js (ディレクトリ移動) して
  2. SET MAPBOX_ACCESS_TOKEN={YOUR MAPBOX ACCESS TOKEN} を実行
    ※ここでSETした環境変数は、このセッションでのみ有効。cmdを終了すると消去される。
  3. yarn run start-debug を実行

デバッグサーバ http://localhost:9966/debug にアクセスできることを確認する。

スタンドアロンビルドを作成

以下のコマンドを実行する。
yarn run build-prod-min
yarn run build-css

dist/mapbox-gl.jsdist/mapbox-gl.css が生成されるので確認する。
HTMLではこの2つのファイルを読み込んで利用する。

余談

yarn run build-prod-min 実行時の出力が下記である。
なにやら警告?エラー?がいっぱい出ている。

mapbox-gl-js>yarn run build-prod-min
yarn run v1.19.0
$ rollup -c --environment BUILD:production,MINIFY:true

src/index.js, src/source/worker.js → rollup/build/mapboxgl...
(!) Circular dependency: src\util\ajax.js -> src\util\mapbox.js -> src\util\ajax.js
(!) Circular dependency: src\style-spec\expression\parsing_context.js -> src\style-spec\expression\compound_expression.js -> src\style-spec\expression\parsing_context.js
(!) Circular dependency: src\style-spec\validate\validate.js -> src\style-spec\validate\validate_function.js -> src\style-spec\validate\validate.js
(!) Circular dependency: src\style-spec\validate\validate.js -> src\style-spec\validate\validate_function.js -> src\style-spec\validate\validate_object.js -> src\style-spec\validate\validate.js
(!) Circular dependency: src\style-spec\validate\validate.js -> src\style-spec\validate\validate_function.js -> src\style-spec\validate\validate_array.js -> src\style-spec\validate\validate.js
(!) Circular dependency: src\style-spec\validate\validate.js -> src\style-spec\validate\validate_layer.js -> src\style-spec\validate\validate_paint_property.js -> src\style-spec\validate\validate_property.js -> src\style-spec\validate\validate.js
(!) Circular dependency: src\style-spec\validate\validate.js -> src\style-spec\validate\validate_layer.js -> src\style-spec\validate\validate.js
(!) Circular dependency: src\style-spec\validate\validate.js -> src\style-spec\validate\validate_light.js -> src\style-spec\validate\validate.js
(!) Circular dependency: src\style\style_layer\symbol_style_layer.js -> src\data\bucket\symbol_bucket.js -> src\style\style_layer\symbol_style_layer.js
(!) Circular dependency: src\geo\lng_lat.js -> src\geo\lng_lat_bounds.js -> src\geo\lng_lat.js
(!) Circular dependency: src\source\tile.js -> src\data\feature_index.js -> src\source\source_state.js -> src\source\tile.js
(!) Circular dependency: src\index.js -> src\ui\map.js -> src\style\style.js -> src\util\global_worker_pool.js -> src\util\worker_pool.js -> src\util\browser\web_worker.js -> src\index.js
created rollup/build/mapboxgl in 11.7s

rollup/mapboxgl.js → dist/mapbox-gl.js...
created dist/mapbox-gl.js in 2s
Done in 14.43s.

「Circular dependency」って何??
直訳すると「循環依存」 となるのでやんわりと察した。
AがBに依存し、BはAに依存しているのでウロボロスって話。

警告は出ているけど mapbox-gl.js は生成されているし、HTML側で読み込んでも(おそらく)正常に動いている(ように見える)。

とりあえず様子見。

Ghost Inspector テストの共通化

弊社では、製品の自動テストにGhost Inspectorを利用しています。

ある日のことです。

「この画面消して新しい画面に置き換えるからテストの方も修正しといてよ」

OKまかせろ。

意気揚々とGhost Inspectorのダッシュボードを開きます。

コピペで複製されたものに微妙に改変が加わったり加わらなかったり無造作に乱立したガバガバテスト群を目撃したぼく「がっでむ」

キレた

プログラミングを行う際、共通の処理は関数化を行うなど、なるべく記述を重複させないという方針がございます。
いわゆるDRY原則というやつですね。(厳密には、よく聞くDRY原則は誤認されたものだと言われていますが、話が逸れるので適当なネット記事に任せます)

コードを書いている感覚の少ないGhost Inspectorだって、共通した処理の再利用は重要です。

  • メンテナンスコストの軽減
  • テスト修正時の修正漏れの防止
  • 再利用性の向上
  • 似ているテスト同士の差分確認の容易化

あたりの利点はパッと思いつきますね。特に上2つが現場的には嬉しいところです。

本題

実際に共通化を行っていきます。
今回は、「元々(ほぼ)同じ内容のテストがコピペ乱立していたものを、1つの共通テストを再利用する形に修正し、メンテナンスコストを軽減する」といったシナリオです。泥臭い箇所もございます。

0. 作業フローの確認

  1. 共通化を行いたいテスト内容を持つ、テストA, Bの差分を確認する。
  2. 共通部分を別の「共通テスト」とし、可能なら差分箇所を抽象化する。
  3. テストA, Bは共通テストを参照してテストを行う形に変更する。抽象化した箇所(認証情報やアドレス等)を適宜指定してテストが走るようにする。

1. テスト内容の差分確認

いきなり技術力のカケラも感じないアナログチェックです。

2つのテスト内容を見比べます。

差分のチェックにはdifff《デュフフ》を利用しました。

差分が存在しない場合は、素直にテストを DuplicateMoveしてしまえばOKだと判断できます。

テストの内容に差分が生じている(=異なるテスト項目がある)場合は、内容を吟味して共通テストが吸収したりしなかったりするだけです。何も恐れることはありません。

2. 「共通テスト」の作成

差分の確認ができたら、次は共通で利用するテストを作成します。

共通のテスト項目となる箇所を、個別のテストとして保存します。
DuplicateMoveするなりうまくやりましょう。
わかりやすく「共通テスト」などといったTest Suiteに放り込むと良いでしょう。

テストA, Bそれぞれで利用することになるため、ログイン認証など、テストごとに異なる可能性のある箇所は変数を利用して抽象化します。

参考:Creating and Using Variables – Ghost Inspector

  • テストAとテストBで、同じ名前の変数に値を入れる。
  • 共通テストでは、変数を参照するのみにする(値を入れない)。

このようにすることで、「共通したテスト項目を、複数のアカウントでテストする」といったことが簡単に実現できます。

3. 共通テストを利用したテストの実行

「共通テスト」の作成が完了したら、作成した共通テストを読み込んでテストを実行しましょう。

参考:Modularizing Tests – Reusing Test Steps – Ghost Inspector

Import steps from testすれば、他のテストからテスト項目を読み込んでテストを走らせることができます。

これにより、ログイン情報のみテストA, Bで入力(変数に値を設定)し、画面上のフォームへ値を投入する共通の処理は共通テストで一本化するといったことが可能になります。

このとき、変数に値を設定する処理をテストごとに記述してもいいのですが、Test Suite単位で使うアカウントがほぼ固定であるようなケースも多いと思います。
そういったケースでは、Suite-level Variablesを設定しましょう。より管理が簡単になります。

変数を指定して問題なく動けば作業完了です。

4. その他

テスト毎のStart URLを個別に指定するのも煩雑です。
Suite SettingsTest Defaultsから、Suite単位で共通のStart URLを設定することができます。

※各テストでStart URLを指定しなかった場合のデフォルトの値を指定するだけなので、テストによって別途Start URLを指定している場合でも問題は生じません。

Ghost Inspectorのテスト管理がぐちゃぐちゃで参った人は参考にしてみてください。

※もちろん、ログイン認証部分のテストも共通化してImport steps from testするとよりスマートなのだろうと思いますが、弊社はそこまで綺麗に整えていません……

Ubuntu 18.04 LTS Desktop 日本語Remix セットアップ

ひどい頭痛眼痛に悩まされながら泥沼セットアップを行ったので備忘録的に記事化。

やったこと

  1. UbuntuインストールDVDの作成
  2. インストールDVDからUbuntuをインストール
  3. GPUを積んだので、NVIDIAのドライバをインストール

1. インストールDVDの作成

  1. Ubuntu 18.04 LTS Desktop 日本語Remixのisoイメージダウンロード。
    ubuntu-ja-18.04.2-desktop-amd64.isoを使いました。
  2. 書き込み可能な空のDVDを用意して書き込み可能なドライブに挿入。
  3. isoイメージを右クリック→ディスクへ書き込み→挿入したDVDを選択。
  4. 書き込みが完了したら内容を確認して終了。

参考: Ubuntu 15.10 インストールDVDの作成

2. Ubuntuのインストール

沼①

  1. インストールDVDをセット。
  2. 起動時にF11を長押ししてブートメニューを開く。
    • BIOSがASRockだったため。ブートメニューがBIOS設定内に存在する種類なら、ブートの順位でディスクを入れたドライブを最優先にするだけでOK。
  3. ディスクからの起動を選択し、インストールDVDからUbuntuを起動。
  4. あとはこちらの記事を参考にポチポチとメニューを進めていく。
    Ubuntu 18.04 LTSインストールガイド【スクリーンショットつき解説】
    • このとき、USB起動かUEFIかといった選択肢が出てきたが、UEFIではないので(BIOSなので) USBを選択した。選択肢が「USB」であったのは、DVDドライブがUSB接続の外付けドライブだったことによると思われる。
    • 差分や選択肢の進み方をメモしておく。
      • モード選択
        今回はUbuntuを単体でクリーンインストールするので「Ubuntuをインストール」を選択。
      • インストールタイプ
        通常のインストール。
        アップデートをダウンロード → ✖(ネットワーク接続してなかったので)
        追加のソフトウェア類 → ✖
      • ストレージ設定
        ディスクを削除してインストール。
        インストールの暗号化 → ✖
        LVMを使用 → ✖
  5. インストールが完了するまで待ち、再起動のメニューが出たら再起動。
  6. ログイン後、初期設定
    1. 新機能はスルー。
    2. Livepatchは設定しても良かったかもしれない (特に設定しなかった)。
    3. 改善支援のデータ送信 → ✖

参考: Ubuntu 18.04 LTSインストールガイド【スクリーンショットつき解説】

3. NVIDIAのドライバダウンロード

Windowsマシンなら付属のCDを入れるだけで良さそうなのに、Ubuntuはこのあたり面倒。

※apt-getでドライバをインストールする方法(「NVIDIA apt-get」🔍)もある。今回入れるドライバは、まだダウンロード可能なドライバリストになかったので、runファイルを落としてきて入れる方針。

  1. 積んでいるGPUの種類を調べる。(購入した商品の箱とかに型番書いてあるのでそれ見てもOK)
    1. 情報更新 sudo update-pciids
    2. 情報表示 lspci | grep -i nvidia あるいは lspci | grep -i VGA
      後ろの方の[ ]で挟まれた部分が知りたい情報
  2. NVIDIAのサイトからドライバをダウンロード
    https://www.nvidia.co.jp/Download/index.aspx?lang=jp
    型番選んでダウンロードタイプを選んで検索→ダウンロード。
    ダウンロードタイプはGRDにした(SDがなかった)
  3. NVIDIA-Linux-x86_64-430.14.runというファイルがダウンロードされた。

4. NVIDIAのドライバインストール

沼②

  1. nouveauドライバの無効化
    参考: Ubuntu 18.04 LTS : NVIDIAドライバーをインストール : Server World
    1. 下記コマンドを実行。
      vi /etc/modprobe.d/blacklist-nouveau.conf
    2. 最終行に以下を追記。
      blacklist nouveau options nouveau modeset=0
    3. 下記コマンドを実行。
      update-initramfs -u
    4. 下記コマンドを実行(再起動)。
      reboot
  2. gccのインストール
    ※runファイルの実行時に必要だったのでインストール
    1. 下記コマンドの実行。
      sudo apt install build-essential
    2. 下記コマンドの実行(gccの動作確認)。
      gcc --version
  3. ドライバのインストール
    1. 下記コマンドの実行。
      sudo ~/Downloads/NVIDIA-Linux-x86_64-430.14.run
    2. 途中度々選択肢が出るが、基本OK連打になる。
      参考[1]: Deep Learning 用 Workstation 構築記録 その3(OS / ドライバ / CUDA&cuDNN インストール) – Qiita
      参考[2]: Ubuntu 16.04にNVIDIAドライバをインストールする方法 : 回れ右の内輪差
    3. インストールが完了し、黒いターミナルの画面に戻ったら、以下のコマンドを実行(再起動)して終了。
      sudo reboot
  4. 下記のコマンドを実行し、接続が正常に認識されているか確認する。
    nvidia-smi

以上。疲れた。

AWS S3 フォルダの作成……?

弊社サービスでは、ユーザーのアップロードしたファイル群を Amazon S3 に保管しています。

元々は自社サーバに保存していたのですが、とある仕事でAWSに縁があり、なんやかんやあってS3使おうぜ!ということになりました。

ある日の開発者は思います。

「ファイルの保存先フォルダをユーザーごとに分けたいなぁ」

「そのためには動的にフォルダを生成する必要があるなぁ」

「あれ?いちいちS3にフォルダの存在確認したりフォルダ生成したりする必要があるんじゃ……? 」

うっわこれめんどいやつっぽいぞ

……と、既存の実装からイメージして勝手にうわぁと思っていたのですが、調べてみると、どうやらそうでもなさそうなんですよね。

S3 バケット内でフォルダを使用する方法 – Amazon Simple Storage Service

なるほどね。

つまるところ、実務上の要点は以下のようです。

  • S3はフラットな構造であり、内部的に階層はない。(=いわゆるディレクトリは実在しない)
  • 利便性のためにフォルダという概念をサポートしており、UI上ではフォルダ構造があるように見せている
  • ファイルをアップロードする際、ファイル名に区切り文字/を含ませれば、自動的に階層構造として処理される……?

3つ目。怪しいですね。確認しましょう。

例えば、アップロードする際のファイル名を、以下のように記述したとします。

'file_name' => 'user_image/' . $user_id . '/' . $file_name

このとき、file_nameuser_image/0123/hogehoge.pngのようになります。

さて、アップロードを実行してみましょう……

やったぜ

問題なくアップロードされましたね。
フォルダの階層構造も意図したとおりに表現されています。

この結果から、S3にファイルをアップロードする際、フォルダを作ってファイルを整理したい~といった場合には、特にフォルダの作成とかについて考える必要はないことがわかりました。楽ちん。

おさらい

  • S3はフラットな構造であり、内部的に階層はない。(=いわゆるディレクトリは実在しない)
  • 利便性のためにフォルダという概念をサポートしており、UI上ではフォルダ構造があるように見せている
  • ファイルをアップロードする際、ファイル名に区切り文字/を含ませれば、自動的に階層構造として処理される

参考