はじめまして、データ分析部の島田です。今日はGoogleが先日公開したTensorFlowについて書かせていただきます。既に、動かしてみた系の記事は出ていますので、サンプルコードを使ったコードの特徴の説明とChainerとの速度比較を中心に書きました。
記事アウトライン
- TensorFlowとは
- TensorFlowで出来ること
- TensorFlowのコードの特徴
- TensorFlowとChainerの速度比較
- まとめ
TensorFlowとは
以下の記事ををご参照ください。
TensorFlow – Google’s latest machine learning system, open sourced for everyone
Googleの内部ツールだったDistBeliefをインフラの依存性を排除しつつ、性能を高めてオープンソース化したものです。自社比較ではDistBeliefの2倍速くなったそうです。
TensorFlowで出来ること
以下の記事をご参照ください。
TensorFlow: Large-Scale Machine Learning on Heterogeneous Distributed Systems
株式会社ネクストさんのBlog:Googleの公開した人工知能ライブラリTensorFlowを触ってみた
既存ツールとの違いはdata flow graphなどがWEBインターフェースで見ることが可能となっていることでしょうか。
TensorBoardを使用した可視化についてはネクストさんのブログやこちらを参照願います。
他、Multi-Deviceでの処理も行えると記載がありますが、検証出来ておりませんので今回の記事の対象からは除外します。
TensorFlowのコードの特徴
TensorFlowのgithub上に公開されているMNISTの手書き文字認識のコードを抜粋しつつ説明いたします。
大まかな特徴
- 基本モデルの記述はシンボル
- weightとbiasを各層で定義する必要がある
- モデルはinference(構造定義), loss(ロス関数定義), training, evaluationの大きく4つのブロックに分けて記述出来る
- flags/FLAGSを使ってmodelで使用する定数をハンドリングする(使用は必須ではない)
- tf.Graph().as_default()内にモデルの記述をすることでdata flow graphを作成
- tf.name_scopeを使用して定義した名前がdata flow graph内に表示される
- tf.Session()で記述した処理の実行管理を行う
- tf.Session()で作成したセッション(sessとする)をsess.run()することにより、シンボルで記述された処理を実行する
- tf.train.Saver()に途中経過をrestoreする(別途saver.save()する必要あり)
- tf.train.SummaryWriter()でmodelの収束具合などの概要データを保存する
- tf.app.run()でmain()を実行
続いて、TensorFlowに独特な記述部分について説明します。
model定義に使用する定数の記述(tf.app.flags)
まずflags/FLAGSを作成します。
# 定義用のflagsを作成 flags = tf.app.flags # 値取得用のFLAGSを作成 FLAGS = flags.FLAGS
これを使用して定義と値の取得を行います。
# int型でバッチサイズの定義 flags.DEFINE_integer('batch_size', 100, 'Batch size. Must divide evenly into the dataset sizes.') # batch_sizeを取得して利用 images_feed, labels_feed = data_set.next_batch(FLAGS.batch_size, FLAGS.fake_data)
sessionとsaver
sessionで処理を管理しsaverで変数の値を保存します。
ファイルはdefaultで直近5チェックポイント分保存されます。チェックポイント毎に保存を行い、保存されるファイル数を制限する事によってstorageが圧迫される事を防いでいるという説明がドキュメントに書かれています。
# sessionの生成 sess = tf.Session() # saverの生成 saver = tf.train.Saver() # 値の初期化 init = tf.initialize_all_variables() sess.run(init) # <- ここで初期化を実行している # チェックポイント毎に値をファイルに書き出す # global_stepオプションをつけるとstepの番号がファイル名に記入される if (step + 1) % 1000 == 0 or (step + 1) == FLAGS.max_steps: saver.save(sess, FLAGS.train_dir, global_step=step)
TensorFlow vs Chainer
ChainerのMNISTのexampleを元にTensorFlowのexampleと構造を合わせて実行してみました。
Chainerのコードの変更箇所は以下のとおりです。
- 訓練データ数を変更(60000 -> 55000)
- epoch数を1に変更
- 最適化手法の変更(Adam -> SGD)
- 各層のユニット数を変更
# 各階層のユニット数がunits=1000となっていたのですが n_units = 1000 model = chainer.FunctionSet(l1=F.Linear(784, n_units), l2=F.Linear(n_units, n_units), l3=F.Linear(n_units, 10)) # 以下に変更 model = chainer.FunctionSet(l1=F.Linear(784, 128), l2=F.Linear(128, 32), l3=F.Linear(32, 10))
- dropoutを除外
# dropoutを行うようになっていましたが x, t = chainer.Variable(x_data), chainer.Variable(y_data) h1 = F.dropout(F.relu(model.l1(x)), train=train) h2 = F.dropout(F.relu(model.l2(h1)), train=train) y = model.l3(h2) # 以下のとおりにdropoutの処理を外しました x, t = chainer.Variable(x_data), chainer.Variable(y_data) h1 = F.relu(model.l1(x)) h2 = F.relu(model.l2(h1)) y = model.l3(h2)
速度比較結果
1batch(=100個の画像データ)当たりの処理速度で比較を行いました。
Chainerはコンスタントに0.004sec前後の値で処理が終了しており、平均処理速度は0.0044sec/batch。
一方TensorFlowの平均処理速度は0.0062sec/batchでした。データsaveの部分は計測から除外しているため単純に演算速度の差が現れているはずです。
極端な例ですが今回と同じ構造で同じデータを処理した場合、300万回mini batch処理をすると100分程度の差が出る結果となります。
TensorFlowはDistBeliefの2倍の速いそうなのですが、Chainerはそれを上回っていました。速いですね。
ちなみに私のマシンのスペックは以下のとおりです。
- Mac OS X v10.11(EI Capitan)
- プロセッサ 2.7GHz Intel Core i5
- メモリ 16GB(DDR3)
まとめ
記述量的にはそこまで変わらないですし個人的にはChainerの方が扱い易いというのが感想です(慣れの問題だとは思いますが。)。
まだMulti-Device ExecutionやDistributed Executionは検証出来ておりませんので、TensorFlowの真価はわかっていない可能性も高いです。
ただ、本格的にTensorFlowに時間を費やすのはもう少し様子を見てからでも遅くないような気もしています。