- 投稿日:2019-09-29T23:04:36+09:00
tensorflow+kerasを扱うためのPython仮想環境はvenvとAnacondaどちらを使うべきか
結論
Anacondaを使おう
環境
OS:Ubuntu 18.04
背景
今日のディープラーニング界隈では技術の進化が飛躍的に早く、それに合わせて
tensorflowやkerasといったフレームワークの更新が頻繁に行われている。
ここで問題となるのが各モジュール間のバージョンには依存関係があり、適切なバージョンの組み合わせでないとプログラムが動作しないといったことが頻繁に発生する。
特にCUDA,cuDNN,tensorflow-gpu間の依存関係はかなりシビアで、バッチレベルが少しでも異なると平気で動かなくなる。
tensorflow公式がテスト済みの依存関係を発表しているが、このバージョンに合わせてライブラリをインストールしてもうまく動作しないことがある。
現にtensorflow-gpu-1.31.1, cuDNN-7.4, CUDA-10.0, Python3.6の組み合わせだとうまく動作しなかった。
特に厄介なのが、一見うまく動いているようで実はうまく動いていない場合がある。
たとえばtensorflow-gpuを使っているのにもかかわらず、GPUが認識されずCPUでモデルの学習が行われてしまうといった症状がある。
これは一見正常に学習が進んでいるように見えるのだが、実際はCPUで学習が行われてしまうため、学習に莫大な時間がかかってしまう。
fit()した際に以下のメッセージが表示されている場合はGPUで学習が行われていない。2019-09-22 14:52:41.548583: E tensorflow/stream_executorcuda /cuda_dnn.cc:329] Could not create cudnn handle: CUDNN_STATUS_INTERNAL_ERRORなぜ仮想環境を使うのか
こういった背景がある中で、仮想環境を使っていない場合、
特定のモジュールを更新した際に過去に作成したプログラムのモジュールバージョンの依存関係を満たせなくなり動かなくなる。といったことがある。
そのため、Pythonを使う場合仮想環境を使うことが一般的である。
仮想環境といってもVMwareやVirtualBoxのようなハイパーバイザー型仮想環境とは異なり、
venvやAnacondaはライブラリのパスの切り方を変えているだけなので、ホストマシンの性能を最大限に活かすことができる。なぜAnacondaを使うのか
Pythonの仮想環境といえばvenvを使うのが一般的だが、ディープラーニングをやりたいのであればAnacondaが最良だという結論に至った。
Anacondaを使う理由は次の通り。
- 環境構築が楽
- モジュールのバージョン変更が楽
- 複数バージョンのCUDAを扱うことができる
特に大きな理由が3番目の"複数バージョンのCUDAを扱うことができる"部分である。
Anacondaを使わずに複数バージョンのCUDAを同一環境で共存させようとすると環境変数の管理が大変なことになる。
更にCUDAのバージョンアップさせる際にも癖があり、最悪ホストマシンが起動しなくなるといったこともある(経験済み)。
そのため、同一環境でCUDAを複数管理したい場合はAnacondaが最良の選択となる。
venvではこれが実現できない(パスの切り方工夫したらできるかも?)。Anacondaを扱う上で注意する点
- pipは使わない
- conda install "モジュール名"ではモジュールが見つからない時がある。
Anaconda環境下でpipを使うと環境が壊れてしまうことがあるため、Anaconda環境下ではpipは使わない方が良い
これに関しては以下の記事が参考になる。
condaとpip:混ぜるな危険
また、conda installでモジュールが見つからない場合はAnaconda Cloudで探せば大抵見つかる。
現時点ではAnaconda Cloudで使いたいモジュールが見つからなかったことはない。Anacondaでモジュールのバージョンを変更する
Anacondaで仮想環境作成済み、モジュールインストール済みを前提として説明する。
以下のコマンドでAnaconda-Navigatorを起動するanaconda-navigatorEnvironments→作成した仮想環境を選択→右側のコンボボックスが"Installed"になっていることを確認し、バージョンを変更したいモジュール名をSearch Packagesから検索する
モジュールがインストールされていれば表示されるので、☑のところを右クリックし、"mark for specific version installation"内から変更先のバージ
ョンを選択する。すると☑がオレンジ色になるのでApply→Applyを選択するとバージョンの変更が完了となる。
2019/09/29時点でのおすすめ組み合わせ
上記でも述べた通り、各モジュールには依存関係があるため、tensorflow(-gpu), cudatoolkit, cudnnの組み合わせは適切なバージョン同士でなければ動作しない。
そのため、最新のモジュールを入れても動作しないことがある。
また、公式発表のテスト済みの依存関係の表通りに導入しても動かないことがある。
Anaconda環境下で動作確認済み(GPU環境)のバージョンの組み合わせは次の通り
モジュール名 バージョン keras-gpu 2.2.4 tensorflow-gpu 1.12.0 cudatoolkit 9.0 cudnn 7.3.1 ※Python3.6を使用
- 投稿日:2019-09-29T17:41:54+09:00
Dockerコンテナで、Keras + TensorFlow / Jupyter notebook環境を簡単にデプロイする
Kerasを活用して、デープラーニングを動作させようと考えた場合、環境整備に手間取るのがめんどくさいですよね。
今回は、Dockerコンテナから、Keras + tensorFlow / Jupyter notebook環境を簡単に整備できるようになりました。
私の個人リポジトリ"ttsubo/study_of_deeplearning_with_keras"と、このQiita記事にて、作業履歴を共有しておきます。⬛︎ 事前準備
Dockerコンテナを動かすUbuntuサーバから、GPUが扱えるようにしておく必要があります。
(1) Ubuntuサーバ側の環境セットアップ
具体的には、Qiita記事: "Dockerで、GPU対応なコンテナ環境を整備する"のセットアップが終わっているものとします。
(2) "study_of_deeplearning_with_keras"リポジトリの取得
Dockerコンテナから、Keras + tensorFlow / Jupyter notebook環境を整備できるように、事前にリポジトリを用意しておきましたので、以下の要領で、リポジトリを取得しておいてください。
$ git clone https://github.com/ttsubo/study_of_deeplearning_with_keras.git(3) cuDNNファイルを別途、入手する
Dockerコンテナ内にcnDNNパッケージをインストールする必要があるので、cuDNN Archive から
cuDNN v7.6.2 (July 22, 2019), for CUDA 10.0
をダウンロードしておいてください。なお、ダウンロードするためには事前にメンバー登録が必要です。
- cuDNN Runtime Library for Ubuntu18.04 (Deb)
- cuDNN Developer Library for Ubuntu18.04 (Deb)
- cuDNN Code Samples and User Guide for Ubuntu18.04 (Deb)
そして、
build/download
フォルダに配置しておいてください。$ cd build/download/ $ ls -l total 314384 -rw-r--r-- 1 ttsubo ttsubo 164426244 Sep 29 14:36 libcudnn7_7.6.2.24-1+cuda10.0_amd64.deb -rw-r--r-- 1 ttsubo ttsubo 152045132 Sep 29 14:36 libcudnn7-dev_7.6.2.24-1+cuda10.0_amd64.deb -rw-r--r-- 1 ttsubo ttsubo 5442884 Sep 29 14:36 libcudnn7-doc_7.6.2.24-1+cuda10.0_amd64.deb(4) Dockerイメージをビルドします
$ docker-compose buildちなみに、Dockerfileファイルは、こんな感じです。
DockerfileFROM nvidia/cuda:10.0-devel-ubuntu18.04 MAINTAINER Toshiki Tsuboi <t.tsubo2000@gmail.com> RUN apt update \ && apt install -y \ git-core \ build-essential \ python-dev \ python-openssl \ libssl-dev \ libbz2-dev \ libffi-dev \ libsqlite3-dev \ libreadline-dev \ zlib1g-dev \ libsm6 \ libxext6 \ libxrender-dev \ libblas-dev \ curl \ vim \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # install pyenv ENV HOME /root ENV PYENV_ROOT $HOME/.pyenv ENV PATH $PYENV_ROOT/bin:$PATH RUN git clone https://github.com/pyenv/pyenv.git $HOME/.pyenv RUN echo 'eval "$(pyenv init -)"' >> $HOME/.bashrc \ && eval "$(pyenv init -)" # install python using pyenv RUN apt update \ && apt install -y libssl1.0-dev \ && pyenv install anaconda3-5.3.1 \ && pyenv global anaconda3-5.3.1 # install pip WORKDIR / ADD https://bootstrap.pypa.io/get-pip.py / RUN python get-pip.py \ && rm get-pip.py # install python package WORKDIR /root COPY requirements.txt /root RUN /root/.pyenv/shims/pip install -r requirements.txt # install cuDNN COPY download /root/debian_packages RUN cd /root/debian_packages \ && dpkg -i \ libcudnn7_7.6.2.24-1+cuda10.0_amd64.deb \ libcudnn7-dev_7.6.2.24-1+cuda10.0_amd64.deb \ libcudnn7-doc_7.6.2.24-1+cuda10.0_amd64.deb #setup jupyter RUN /root/.pyenv/shims/jupyter notebook --generate-config \ && sed -i -e "s/#c.NotebookApp.ip = 'localhost'/c.NotebookApp.ip = '0.0.0.0'/" /root/.jupyter/jupyter_notebook_config.py \ && sed -i -e "s/#c.NotebookApp.allow_remote_access = False/c.NotebookApp.allow_remote_access = True/" /root/.jupyter/jupyter_notebook_config.py \ && sed -i -e "s/#c.NotebookApp.token = '<generated>'/c.NotebookApp.token = ''/" /root/.jupyter/jupyter_notebook_config.py EXPOSE 8888 ENTRYPOINT ["sh", "-c", "/root/.pyenv/shims/jupyter notebook --allow-root"]⬛︎ 実際に、動かしてみる
今回、動かしてみるデープラーニング用Pythonスクリプトは、Keras repoが提供しているサンプルアプリです。
keras/examples/mnist_cnn.py'''Trains a simple convnet on the MNIST dataset. Gets to 99.25% test accuracy after 12 epochs (there is still a lot of margin for parameter tuning). 16 seconds per epoch on a GRID K520 GPU. ''' from __future__ import print_function import keras from keras.datasets import mnist from keras.models import Sequential from keras.layers import Dense, Dropout, Flatten from keras.layers import Conv2D, MaxPooling2D from keras import backend as K batch_size = 128 num_classes = 10 epochs = 12 # input image dimensions img_rows, img_cols = 28, 28 # the data, split between train and test sets (x_train, y_train), (x_test, y_test) = mnist.load_data() if K.image_data_format() == 'channels_first': x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols) x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols) input_shape = (1, img_rows, img_cols) else: x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1) x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1) input_shape = (img_rows, img_cols, 1) x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 print('x_train shape:', x_train.shape) print(x_train.shape[0], 'train samples') print(x_test.shape[0], 'test samples') # convert class vectors to binary class matrices y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical(y_test, num_classes) model = Sequential() model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape)) model.add(Conv2D(64, (3, 3), activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(128, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(num_classes, activation='softmax')) model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.Adadelta(), metrics=['accuracy']) model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_test, y_test)) score = model.evaluate(x_test, y_test, verbose=0) print('Test loss:', score[0]) print('Test accuracy:', score[1])(1) Dockerコンテナを起動する
Docker-composeを使って、Dockerコンテナを起動します。
この段階で、Dockerコンテナ内では、Jupyter notebook環境も常駐するようになっています。$ docker-compose up Creating Keras ... done Attaching to Keras Keras | [I 05:43:15.263 NotebookApp] Writing notebook server cookie secret to /root/.local/share/jupyter/runtime/notebook_cookie_secret Keras | [W 05:43:15.379 NotebookApp] All authentication is disabled. Anyone who can connect to this server will be able to run code. Keras | [I 05:43:15.403 NotebookApp] JupyterLab extension loaded from /root/.pyenv/versions/anaconda3-5.3.1/lib/python3.7/site-packages/jupyterlab Keras | [I 05:43:15.404 NotebookApp] JupyterLab application directory is /root/.pyenv/versions/anaconda3-5.3.1/share/jupyter/lab Keras | [I 05:43:15.406 NotebookApp] Serving notebooks from local directory: /root Keras | [I 05:43:15.406 NotebookApp] The Jupyter Notebook is running at: Keras | [I 05:43:15.406 NotebookApp] http://(Keras or 127.0.0.1):8888/ Keras | [I 05:43:15.406 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation). Keras | [W 05:43:15.407 NotebookApp] No web browser found: could not locate runnable browser.(2) Dockerコンテナ内に、入って、サンプルアプリを起動する
まずは、Dockerコンテナに入ります
$ docker exec -it Keras bashそして、サンプルアプリを起動します。
$ python examples/mnist_cnn.py
root@Keras:~# python examples/mnist_cnn.py Using TensorFlow backend. x_train shape: (60000, 28, 28, 1) 60000 train samples 10000 test samples ... (snip) Train on 60000 samples, validate on 10000 samples Epoch 1/12 2019-09-29 06:00:43.489125: I tensorflow/stream_executor/dso_loader.cc:152] successfully opened CUDA library libcublas.so.10.0 locally 60000/60000 [==============================] - 8s 127us/step - loss: 0.2654 - accuracy: 0.9186 - val_loss: 0.0628 - val_accuracy: 0.9785 Epoch 2/12 60000/60000 [==============================] - 7s 115us/step - loss: 0.0888 - accuracy: 0.9736 - val_loss: 0.0430 - val_accuracy: 0.9849 Epoch 3/12 60000/60000 [==============================] - 7s 112us/step - loss: 0.0677 - accuracy: 0.9802 - val_loss: 0.0394 - val_accuracy: 0.9871 Epoch 4/12 60000/60000 [==============================] - 7s 114us/step - loss: 0.0566 - accuracy: 0.9832 - val_loss: 0.0321 - val_accuracy: 0.9885 Epoch 5/12 60000/60000 [==============================] - 7s 114us/step - loss: 0.0480 - accuracy: 0.9860 - val_loss: 0.0350 - val_accuracy: 0.9882 Epoch 6/12 60000/60000 [==============================] - 7s 110us/step - loss: 0.0450 - accuracy: 0.9864 - val_loss: 0.0274 - val_accuracy: 0.9897 Epoch 7/12 60000/60000 [==============================] - 7s 113us/step - loss: 0.0395 - accuracy: 0.9883 - val_loss: 0.0292 - val_accuracy: 0.9903 Epoch 8/12 60000/60000 [==============================] - 7s 114us/step - loss: 0.0351 - accuracy: 0.9890 - val_loss: 0.0309 - val_accuracy: 0.9893 Epoch 9/12 60000/60000 [==============================] - 7s 112us/step - loss: 0.0342 - accuracy: 0.9892 - val_loss: 0.0288 - val_accuracy: 0.9906 Epoch 10/12 60000/60000 [==============================] - 7s 111us/step - loss: 0.0328 - accuracy: 0.9900 - val_loss: 0.0264 - val_accuracy: 0.9918 Epoch 11/12 60000/60000 [==============================] - 7s 112us/step - loss: 0.0305 - accuracy: 0.9901 - val_loss: 0.0280 - val_accuracy: 0.9916 Epoch 12/12 60000/60000 [==============================] - 7s 117us/step - loss: 0.0289 - accuracy: 0.9911 - val_loss: 0.0268 - val_accuracy: 0.9917 Test loss: 0.026753987711756782 Test accuracy: 0.9916999936103821GPUを使用した場合、1エポック当たり、7秒程度で、学習が進んでいく様子が確認できますね。
ちなみに、CPUを使用した場合は、1エポック当たり、41秒程度で学習が進んでいきました。
私のGPU環境GeForce GTX 1060 3GB
だと、CPUよりも、約6倍も、学習に要する時間が短縮できるようです。root@Keras:~# python examples/mnist_cnn.py Using TensorFlow backend. Downloading data from https://s3.amazonaws.com/img-datasets/mnist.npz 11493376/11490434 [==============================] - 8s 1us/step x_train shape: (60000, 28, 28, 1) 60000 train samples 10000 test samples ... (snip) Train on 60000 samples, validate on 10000 samples Epoch 1/12 60000/60000 [==============================] - 41s 679us/step - loss: 0.2666 - accuracy: 0.9189 - val_loss: 0.0607 - val_accuracy: 0.9819 Epoch 2/12 60000/60000 [==============================] - 41s 677us/step - loss: 0.0895 - accuracy: 0.9733 - val_loss: 0.0402 - val_accuracy: 0.9866 Epoch 3/12 60000/60000 [==============================] - 41s 677us/step - loss: 0.0673 - accuracy: 0.9798 - val_loss: 0.0365 - val_accuracy: 0.9879 Epoch 4/12 60000/60000 [==============================] - 41s 677us/step - loss: 0.0550 - accuracy: 0.9835 - val_loss: 0.0341 - val_accuracy: 0.9885 Epoch 5/12 60000/60000 [==============================] - 41s 678us/step - loss: 0.0477 - accuracy: 0.9857 - val_loss: 0.0293 - val_accuracy: 0.9908 Epoch 6/12 60000/60000 [==============================] - 41s 677us/step - loss: 0.0424 - accuracy: 0.9871 - val_loss: 0.0283 - val_accuracy: 0.9913 Epoch 7/12 60000/60000 [==============================] - 41s 678us/step - loss: 0.0387 - accuracy: 0.9881 - val_loss: 0.0275 - val_accuracy: 0.9906 Epoch 8/12 60000/60000 [==============================] - 41s 678us/step - loss: 0.0340 - accuracy: 0.9897 - val_loss: 0.0261 - val_accuracy: 0.9909 Epoch 9/12 60000/60000 [==============================] - 41s 677us/step - loss: 0.0319 - accuracy: 0.9902 - val_loss: 0.0291 - val_accuracy: 0.9906 Epoch 10/12 60000/60000 [==============================] - 41s 676us/step - loss: 0.0307 - accuracy: 0.9906 - val_loss: 0.0287 - val_accuracy: 0.9918 Epoch 11/12 60000/60000 [==============================] - 41s 676us/step - loss: 0.0277 - accuracy: 0.9916 - val_loss: 0.0282 - val_accuracy: 0.9917 Epoch 12/12 60000/60000 [==============================] - 41s 676us/step - loss: 0.0271 - accuracy: 0.9915 - val_loss: 0.0267 - val_accuracy: 0.9921 Test loss: 0.026685928908488858 Test accuracy: 0.9921000003814697(3) 最後に、jupyter notebook経由で、サンプルアプリを起動してみる
Web browserから、
http://(Keras or 127.0.0.1):8888/
にアクセスします。
そして、notebookを起動すると、こんな感じの結果が確認できました。
⬛︎ 終わりに、、、
Keras + TensorFlow / Jupyter notebook環境が簡単に、デプロイできるようになりました。
デープラーニング動作検証を通じて知識を習得する場合には、デープラーニング環境を色々とスクラップ&ビルドできるのが望ましいと思うので、まさに、Dockerコンテナ活用のわかりやすい事例だと思います。