TensorFlowを使った開発
このフレームワークの一番の特徴は使い始めの敷居の低さです。インストールに関してはPythonのパッケージインストーラーのpipコマンドだけで可能です。これ以上簡単にはならないという感じです。
そしてコーディングも極めてシンプルな原理で行えます。例えば、非常に単純な例ですが、簡単な行列の掛け算を行うコードを見てみましょう:
# TensorFlowをインポート import tensorflow as tf # 行列1(1x2)を定義 matrix1 = tf.constant([[3., 3.]]) # 行列2(2x1)を定義 matrix2 = tf.constant([[2.],[2.]]) # 掛け算を行う product = tf.matmul(matrix1, matrix2) # セッションを開始し計算を行う sess = tf.Session() result = sess.run(product) print result # ==> [[ 12.]] # セッション終了 sess.close()
この例では2x1の行列などのシンプルなデータを扱っていますが、これが画像になると、ピクセル分の2次元の配列になります。テンソル表現はそういったデータをすべて同じ種類のデータとして取り扱うことができるため、コーディング上は同じくシンプルです。またここでは「掛け算」という一層の処理を定義しましたが、深層学習ネットワークではこれがどんどん複雑になります。例えば、TensorFlow発表後すぐ話題になった「TensorFlowでアニメゆるゆりの制作会社を識別する」からコードを一部抜粋すると:
# 畳み込み層1の作成
with tf.name_scope('conv1') as scope:
W_conv1 = weight_variable([5, 5, 3, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
# プーリング層1の作成
with tf.name_scope('pool1') as scope:
h_pool1 = max_pool_2x2(h_conv1)
# 畳み込み層2の作成
with tf.name_scope('conv2') as scope:
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
# プーリング層2の作成
with tf.name_scope('pool2') as scope:
h_pool2 = max_pool_2x2(h_conv2)
# 全結合層1の作成
with tf.name_scope('fc1') as scope:
W_fc1 = weight_variable([7*7*64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
# dropoutの設定
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
# 全結合層2の作成
with tf.name_scope('fc2') as scope:
W_fc2 = weight_variable([1024, NUM_CLASSES])
b_fc2 = bias_variable([NUM_CLASSES])
# ソフトマックス関数による正規化
with tf.name_scope('softmax') as scope:
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
# 各ラベルの確率のようなものを返す
return y_conv
このようにして、x_image(入力画像)→ h_conv1 → h_pool1→ h_conv2 → h_pool2 → h_pool2_flat → h_fc1 → h_fc1_drop → y_conv(予測結果)という長いネットワークを経てデータが変換され、最終的な予測に形を変えます。
TensorFlowって誰のためのツール? イベントを通じて思ったこと
上記のとおり、TensorFlowでは非常にきれいに複雑なネットワークを記述できるため、今までよりもはるかに簡単に深層学習を使いはじめることができます。今回のハッカソンでも多くの人がチュートリアルを動かし、「大変勉強になった」という声は多く聞かれました。
しかし、実際にその場で深層学習ネットワークを構築し、成果を発表できた方は少数でした。また、成果発表した方も多くは、既存のコードにほんの少しだけ手を加えたというケースが多かったようです。平日の短時間のイベントだったこともありますが、仮に時間があったとしても、上記のような複雑なネットワークを専門知識のないエンジニアやデータサイエンティストが構築していくというのは非現実的な気がしました。
多くの人々は機械学習をツールとして使ったことはあっても、その中身に手を入れるようなことをする人はごく一部でしょう。Pythonの場合、scikit-learnというライブラリには、深層学習こそありませんが、リグレッションや決定木など非常にたくさんのアルゴリズムが実装されており、インポートするだけで簡単に呼び出すことができる上、データの前処理や、結果のスコアリングなどを行う上で便利なツールが詰め込まれています。
実はTensorFlowで作られた深層学習ネットワークをscikit-learnのインターフェースで使えるskflowというライブラリがすでに登場しています。タイタニックの乗船者名簿のデータを分析して生存者を予測する例を見てみましょう:
import skflow
train = pandas.read_csv('tf_examples/data/titanic_train.csv')
y, X = train['Survived'], train[['Age', 'SibSp', 'Fare']].fillna(0)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
#Scikit-Learnのロジスティックリグレッションを使う
lr = LogisticRegression()
lr.fit(X_train, y_train)
print accuracy_score(lr.predict(X_test), y_test)
#TensorFlowの3層型深層学習分類器を使う
# 3 layer neural network with rectified linear activation.
random.seed(42)
classifier = skflow.TensorFlowDNNClassifier(hidden_units=[10, 20, 10],
n_classes=2, batch_size=128, steps=500, learning_rate=0.05)
classifier.fit(X_train, y_train)
print accuracy_score(classifier.predict(X_test), y_test)
このレベルであれば、一般のエンジニアやデータサイエンティストが扱うこともできそうです。実際にこの例を走らせて見ましたが、外側からネットワークのパラメーターを変える程度では効果的なチューニングを行えないようです。まだこのような形での利用は時期尚早なのかもしれません。
では深層学習の専門家がネットワークの構築やチューニングにおいてどれだけの理論体系を持っているのかというと、実は結構試行錯誤の世界のようです。深層学習の父として知られるトロント大学のヒントン教授は、今後研究とともに理論を確立させられると考えているようですが、実際にはまだ多くの研究者が職人芸で試行錯誤の中からチューニングを行って新しい発見につながっていくという状況のようです。
そう考えると、今回のGoogleのTensorFlow公開はより大きな意味を持っているように感じられます。深層学習には門外漢的なエンジニアやデータサイエンティストがTensorFlowをいじっていたら、なんだかよく分からないけどすごいものを作ってしまった。そんなことも今なら可能なのかもしれません。GitHub上では、TensorFlow関係のレポジトリだけでもすでに200以上を数え、その中には以前から強い人気のあったツールのTensorFlowへの移植(例えばKerasもTensorFlowに対応)も多く見られます。
