Archives

TensorFlowをec2のgpuインスタンスで実行するまでの手順

Python、データ分析界隈はTensorFlowの登場でにわかに沸き立っていますが、実はTensorFlowはデフォルトでサポートしているgpuに制限があり、Nvidia Compute Capability 3.5 以上のgpuしか使えません。そして大体のひとが使うであろうawsのgpuインスタンスの GRID K520 のNvidia Compute Capabilityは3.0です。ドラゴンボールだと一般人以下です。つまりゴミ以下なのでTensorFlowは使えません。

もちろん既にGitHubでもissueが立っており、公式に対応してくれています。

https://github.com/tensorflow/tensorflow/issues/25

configure時に

TF_UNOFFICIAL_SETTING=1 ./configure

とすればNvidia Compute Capability選択させたるで!とのこと。やったね!

ってbuild必要なんかい!というわけで環境構築を行います。なお、途中でcuDNNが必要になりますが、cuDNNのダウンロードはnvdiaに登録後、1日ぐらい審査に時間がかかるので、早めに申請することをおすすめします。

前準備

awsのリージョンはオレゴンとかの田舎にしましょう。安いので。Ubuntu 14.04のインスタンスを起動します。


# localeをtokyoに変更
sudo cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
sudo locale-gen ja_JP.UTF-8

# rootになる
sudo su -

# 各種ツールをインストール。
# linux-image-extra-virtualのインストールでは、"install the package maintainer's version"を選択する。(cudaのインストールに必要。)
apt-get update && apt-get install -y build-essential linux-image-extra-virtual wget git default-jdk zip zlib1g-dev swig

# cudaをインストールする前に既存のドライバ(nouveau)を無効化する
vi /etc/modprobe.d/blacklist-nouveau.conf
# 下記を書いて保存 ----------------------
blacklist nouveau
blacklist lbm-nouveau
options nouveau modeset=0
alias nouveau off
alias lbm-nouveau off
# ---------------------------------------

echo options nouveau modeset=0 | sudo tee -a /etc/modprobe.d/nouveau-kms.conf
update-initramfs -u
reboot


# 再起動後、anaconda pythonをインストール
sudo su -
wget --quiet https://repo.continuum.io/archive/Anaconda-2.3.0-Linux-x86_64.sh && /bin/bash Anaconda-2.3.0-Linux-x86_64.sh -b -p /opt/conda

# pathの設定
vi /etc/profile.d/path.sh
# ---------------------------------------
export PATH=/opt/conda/bin:$PATH
# ---------------------------------------

# path設定を読み込む
source /etc/profile.d/path.sh
# default encodingをutf-8にする。(TensorFlowには関係ないけど、やっといた方が後々助かる)
vi /opt/conda/lib/python2.7/sitecustomize.py
# ---------------------------------------
import sys
sys.setdefaultencoding('utf-8')
# ---------------------------------------

# CUDA 7.0のインストール (7.5は未サポート)
apt-get install -y linux-source linux-headers-$(uname -r)
export CUDA_MAJOR=7.0
export CUDA_VERSION=7.0.28
export CUDA_MAJOR_U=7_0
cd /tmp && wget http://developer.download.nvidia.com/compute/cuda/${CUDA_MAJOR_U}/Prod/local_installers/cuda_${CUDA_VERSION}_linux.run && chmod +x cuda_*_linux.run && ./cuda_*_linux.run -extract=`pwd` &&   ./NVIDIA-Linux-x86_64-*.run -s
modprobe nvidia
./cuda-linux64-rel-*.run
./cuda-samples-linux-*.run

# 確認 (これをしないと/dev/以下にデバイスファイルが出てこない)
cd /usr/local/cuda/samples/1_Utilities/deviceQuery
make
./deviceQuery
# ls /dev/ すると、nvdia系のデバイスが見えるようになっている。

# cudnn 6.5
# cudnn-6.5-linux-x64-v2.tgzはnvdiaのサイトに登録して自分でダウンロードしてくる
tar xvzf cudnn-6.5-linux-x64-v2.tgz
cp cudnn-6.5-linux-x64-v2/cudnn.h /usr/local/cuda/include
cp cudnn-6.5-linux-x64-v2/libcudnn* /usr/local/cuda/lib64
reboot

# 再起動後、buildに必要なbazelをインストール
git clone https://github.com/bazelbuild/bazel.git
cd bazel
# バージョンは0.1.0のみサポート
git checkout tags/0.1.0
./compile.sh
sudo cp output/bazel /usr/bin

TensorFlowのインストール


# install tensorflow
cd ~/
# submoduleとしてprotocol buffersを使うので、オプションが必要
git clone --recurse-submodules https://github.com/tensorflow/tensorflow
cd tensorflow

# configureで、Nvidia Compute Capability に3.0を許可する。
TF_UNOFFICIAL_SETTING=1 ./configure

# 以下のような出力が出るので、書いたとおりに入力する
Do you wish to build TensorFlow with GPU support? [y/n]  -> y エンター
GPU support will be enabled for TensorFlow

Please specify the location where CUDA 7.0 toolkit is installed. Refer to README.md for more details. [Default is /usr/local/cuda]: -> エンター
Please specify the location where CUDNN 6.5 V2 library is installed. Refer to README.md for more details. [Default is /usr/local/cuda]: -> エンター

WARNING: You are configuring unofficial settings in TensorFlow. Because some external libraries are not backward compatible, these settings are largely untested and unsupported.

Please specify a list of comma-separated Cuda compute capabilities you want to build with.
You can find the compute capability of your device at: https://developer.nvidia.com/cuda-gpus.
Please note that each additional compute capability significantly increases your build time and binary size.
[Default is: "3.5,5.2"]: -> 3.0 エンター
Setting up Cuda include
Setting up Cuda lib64
Setting up Cuda bin
Setting up Cuda nvvm
# ---------------------------------------

# ビルド時のデフォルトのincludeディレクトリは /usr/include/python2.7 になっているので、
# includeディレクトリをanaconda pythonのものに変更 (ソースを変更するのでも良いと思う)
sudo ln -s /opt/conda/include/python2.7 /usr/include/python2.7
sudo ln -s /opt/conda/lib/python2.7/site-packages/numpy/core/include/numpy /opt/conda/include/python2.7/numpy

# cuda, cnnのライブラリをシンボリックリンク (pipのパッケージを作成するときに必要。)
# バッドノウハウっぽいのでもっとスマートなやり方があれば知りたい
sudo ln -s /usr/local/cuda/lib64/* /opt/conda/lib

# build
bazel build -c opt --config=cuda //tensorflow/cc:tutorials_example_trainer

# テスト実行
# エラーが出なければおk
/usr/local/cuda/samples/1_Utilities/deviceQuery/deviceQuery
bazel-bin/tensorflow/cc/tutorials_example_trainer --use_gpu


# pipパッケージをbuild
sudo /opt/conda/bin/pip install --upgrade pip
sudo /opt/conda/bin/pip install wheel

bazel build -c opt --config=cuda //tensorflow/tools/pip_package:build_pip_package
bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
sudo /opt/conda/bin/pip install /tmp/tensorflow_pkg/tensorflow-0.5.0-py2-none-any.whl

# pythonからの動作テスト(mnist)
cd tensorflow/models/image/mnist
python convolutional.py

こんな感じでなんとかインストールして実行出来ました。
マイami化しておくと、次に使う時は便利です。
早くpipのパッケージでもec2サポートしてくれれば良いのですが。。。

ほんとに速くなるのか

Python – TensorFlow 畳み込みニューラルネットワークで手書き認識率99.2%の分類器を構築 – Qiita

この記事で使われているCNNのサンプルを、gpuバージョンとそうでないバージョン(どちらもg2.2xlarge)で実行したところ、

gpuアリ: 10分ぐらい

gpuナシ: 50分ぐらい

で学習終了しました。最初に上げたGitHub issueでは、「そもそもawsのgpuインスタンスは速くない」みたいな話が出てました。まあこんなところかなという気がします。

lstmで自然な受け答えができるボットをつくった

(2016-12-11 追記) この記事で紹介している学習済モデルは、現行のchainerのバージョンでは使用できなくなっているので、chainer 1.4.1 をインストールしたdocker imageを使う方法を追記しました。新しく学習される方は最新のchainerを使うことをおすすめします。

 

コードを理解する程度のスキルがあればDeep Learningが使える世の中になっているので、試しに自然な受け答えができるボットを作ってみた。

学習

自然な受け答えを行う日本語のデータセットということで、ask.fmをクロールしたデータを用いる。

ask.fmのディレクトリは”ask.fm/アカウント名”のようになっていて、ask.fmのアカウント名のリストがないことにはクロールしようがない。今回は、トップページに訪れた際に表示されるアカウントのリストを定期的に収集することでアカウント名のリストを作った。

Ask_fm

負荷をかけすぎないよう、30分に1回ぐらいトップページにアクセスすること1ヶ月、1,600ぐらいのアカウント名が取得できた。各アカウントのページには最新の質問と答えがいくつか表示されているので、それらを取得する。データ量は8MBぐらいになった。(ちなみに10日ぐらいで600ぐらいのアカウント、学習データは4MBぐらいになるのでそれでも十分)

中身はこんな感じ。

lstm-input

質問と答えの後に1行空白行を入れている。

ChainerでLanguage ModelをLSTMで使うコードがあったので、ありがたく使わせてもらう。

https://github.com/yusuketomoto/chainer-char-rnn

askfmをクロールしたデータをinput.txtとした。パラメータはDeepDazaiを参考にして、隠れ層のノード数を増やした。

前に作ったCUDAとDockerをインストール済のAMIをオレゴンに作り、cudaとchainerをインストールしてあるDocker imageをpullして学習させる。


# gpuの有効化
/usr/local/cuda/samples/1_Utilities/deviceQuery/deviceQuery

# docker imageの起動
DOCKER_NVIDIA_DEVICES=”–device /dev/nvidia0:/dev/nvidia0 –device /dev/nvidiactl:/dev/nvidiactl –device /dev/nvidia-uvm:/dev/nvidia-uvm”
sudo docker run –name chainer -v $PWD:/notebook -p 8888:8888 -d $DOCKER_NVIDIA_DEVICES drunkar/cuda-caffe-anaconda-chainer

# deep-dazaiのbranchを取ってくる
git clone https://github.com/longjie/chainer-char-rnn.git
cd chainer-char-rnn
git checkout -b new-branch origin/new-branch

# cv/askfm、data/askfmディレクトリを作る
# 学習データをinput.txtとしてdata/askfmに置く

# 学習の実行
python train.py --data_dir data/askfm --checkpoint_dir cv/askfm --rnn_size 1024

4MBの学習データなら8時間ぐらい、8MBのデータなら20時間ぐらい学習にかかったと思う。オレゴンのgpuインスタンスで2000円ぐらい。高い。

学習途中にモデルデータがどんどん溜まっていくので、インスタンスの容量が少ない場合は適宜消さないと学習が途中で終わってしまうので注意。時は金なり(切実)。

hubotにしゃべらせる

モデルの学習が終わったら、それを使ってhubotにしゃべってもらう。getリクエストのパラメータに文字列を渡すと、続きを予測して表示してくれるAPIをtornadoで作り、hubotからAPIでアクセスする。hubot側の返答パターンは2通り。

  • askfmは「質問と答え」という特殊な文字列なので、「?」の後には回答が来やすくなる。なのでhubotは質問をメンションで受け取り、クエスチョンマークを末尾につけてAPIをコールするようにした。
  • たまに自然に会話に参加してほしいので、全発言をhearして、メンション以外の全発言に対して10%の確率で返答するようにした。APIは発言の続きを予測するので、2文目以降をhubotの発言とした。

しばらくしゃべってもらって調整したのは以下の2点。

  • クエスチョンマークの後にはクエスチョンマークがかなりの確率でやってきてしまう (「??」みたいな聞き方が多いため)ので、”?¥n”をAPI側でlstripした。
  • あまり意味が通じないとしても、hubotの発言は短ければそれなりに破綻しない発言として人間に解釈されやすい。ので、hubotの発言は1文か2文(ランダム)に制限した。

tornadoで作ったAPIとhubotスクリプトはgithubに上げてます。1,600アカウント分のデータを学習した学習済モデルも含まれているので、dockerがインストールしてあるマシンなら今すぐにでもしゃべらせられます。

https://github.com/Drunkar/japanese_talk_api


# apiデータをclone
git clone https://github.com/Drunkar/japanese_talk_api.git

# tornadoを動かすdocker containerを起動
# entrypointではjupiter notebookが走るけど気にしない
docker run --name japanese_talk_api -d -p 80:8787 -v japanese_talk_api:/app drunkar/cuda-caffe-anaconda-chainer

# (2016-12-11 追記)
# 学習済モデルを使う場合は、以下のコマンドでdockerを起動してください。
docker run --name japanese_talk_api -d -p 80:8787 -v japanese_talk_api:/app drunkar/cuda-caffe-anaconda-chainer1.4.1

# tornadoを起動するための別プロセスを走らせる
docker exec -it japanese_talk_api bash
# sampleモデルをダウンロード
cd /app/tornado/models ./download_sample_model.sh
# tornadoを起動
cd /app python tornado/app.py --port=8787 --debug=True
# プロセスを走らせたままcontainerから抜ける
ctrl+p, ctrl+q 

pickleモデル(chainermodel)のロードに30秒ぐらいかかるので、ちょっと待ってからAPIと試す。

http://localhost/?q=こんにちは

なんか適当にjsonが返ってきたらおk。後は付属のhubot scriptでアクセスしましょう。

名言集

hyohyoがボット。(名前は『カイバ』から。アイコンは忍野扇(女))

  • 出演を断る

hyohyo1__1_

  • ツイ廃

hyohyo2_2

 

  • 独特の世界観

hyohyo3

ask.fmがツイッターを中心としたメディアなので、やたらとツイッターのことを言ってくるし、淫夢厨だったりゲスかったりします。日本からask.fmにアクセスしているとはいえ、日本語以外のアカウントもまあまあ紛れているので英語や韓国語も話せます。

わかったこと

  • 人工無能でもAIは愛しい: 予想の斜め上をいく発言をしたり、うまく発言してくれなかったりすることもあって妙に可愛いです。AIBOがヒットする理由もなんとなく分かりましたし、ヒューマノイドが話相手になるということに確信が持てました。
  • チャットが和む: 普通に会話している時に突如パンツの話とかをしだすので、チャットが和みます。