まだTesorBoardで可視化出来ていない上に作成途中ですが、長くなってきましたので…。
TensorFlowのアップデート
TensorFlowにKerasが同梱されてからしばらく経ったのでアップデートしようとしました。結果、できませんでした。
顛末は長くなりましたのでこちらの記事をご参照ください。
Keras入門
今回はTensorFlow付属のKerasを使っていきます。もちろん、Kerasを普通にインストールしても良いと思います。
なぜKerasを使おうとしているのか
TensorFlowを素で使うのは時に辛い場合があります。MNISTで隠れ層2層のNeural Networkを以前に定義したとき、こんなコードを書きました。
# vanilla TensorFlow (v1.0)
batch_size = 128
hidden_layer_size = 1024
input_layer_size = 28*28
output_layer_size = 10
graph = tf.Graph()
with graph.as_default():
# Input data. For the training data, we use a placeholder that will be fed
# at run time with a training minibatch.
tf_train_dataset = tf.placeholder(tf.float32, shape=(batch_size, image_size * image_size))
tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels))
tf_valid_dataset = tf.constant(valid_dataset)
tf_test_dataset = tf.constant(test_dataset)
# Variables
weight1 = weight_variable( (input_layer_size, hidden_layer_size) )
bias1 = bias_variable( [hidden_layer_size] )
# Hidden Layer
hidden_layer = tf.nn.relu(tf.matmul(tf_train_dataset, weight1) + bias1)
# Variables
weight2 = weight_variable( (hidden_layer_size, output_layer_size) )
bias2 = bias_variable( [output_layer_size] )
logits = tf.matmul(hidden_layer, weight2) + bias2
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=tf_train_labels))
# optimizer
optimizer = tf.train.AdamOptimizer(0.001).minimize(loss)
# optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)
# prediction
train_prediction = tf.nn.softmax(logits)
valid_prediction = tf.nn.softmax(tf.matmul(tf.nn.relu(tf.matmul(tf_valid_dataset, weight1) + bias1), weight2) + bias2)
test_prediction = tf.nn.softmax(tf.matmul(tf.nn.relu(tf.matmul(tf_test_dataset, weight1) + bias1), weight2) + bias2)
まず目につくのはコード量の多さだと思います。こちらについては、tf.layer
が導入されたことにより大分解決されました。tf.layer
を用いると次のようになります。
# tf.layer
def nn_model(images, drop_rate, variable_scope, reuse=False):
with tf.variable_scope(variable_scope, reuse=reuse):
net = tf.layers.dense(images, 512, activation=tf.nn.relu) # Dense Layer (1st hidden layer)
net = tf.layers.dropout(net, rate=drop_rate)
net = tf.layers.dense(net, 512, activation=tf.nn.relu) # Dense Layer (2nd hidden layer)
net = tf.layers.dropout(net, rate=drop_rate)
net = tf.layers.dense(net, 10, activation=tf.nn.relu) # Readout Layer
return net
x = tf.placeholder(tf.float32, [None, 784])
y = tf.placeholder(tf.float32, [None, 10])
keep_prob = tf.placeholder(tf.float32)
drop_rate = 1 - keep_prob
mlp_pred = nn_model(x, drop_rate, variable_scope='mlp')
loss = tf.losses.softmax_cross_entropy(y, mlp_pred)
train_step = tf.train.AdamOptimizer().minimize(loss)
correct_prediction = tf.equal(tf.argmax(mlp_pred, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
かなりコード量が減っていることがわかります。一方、これでも不十分だと感じるケースがあります。
例えば上記のコードで次のようなタイプミスをした場合、エラーの原因が分かりにくいです。
#
def nn_model(images, drop_rate, variable_scope, reuse=False):
with tf.variable_scope(variable_scope, reuse=reuse):
net = tf.layers.dense(images, 512, activation=tf.nn.relu) # Dense Layer (1st hidden layer)
net = tf.layers.dropout(net, rate=drop_rate)
net = tf.layers.dense(net, 512, activation=tf.nn.relu) # Dense Layer (2nd hidden layer)
net = tf.layers.dropout(net, rate=drop_rate)
# Wrong, '512' should be '10'
net = tf.layers.dense(net, 512, activation=tf.nn.relu) # Readout Layer
この場合のエラー出力は次のようになります。どこを直せばいいのか大変分かりにくいです。
ValueErrorTraceback (most recent call last)
<ipython-input-36-96111e522d26> in <module>()
15 drop_rate = 1 - keep_prob
16 mlp_pred = nn_model(x, drop_rate, variable_scope='mlp2')
---> 17 loss = tf.losses.softmax_cross_entropy(y, mlp_pred)
18 train_step = tf.train.AdamOptimizer().minimize(loss)
19
/usr/local/lib/python3.5/dist-packages/tensorflow/python/ops/losses/losses_impl.py in softmax_cross_entropy(onehot_labels, logits, weights, label_smoothing, scope, loss_collection, reduction)
631 logits = ops.convert_to_tensor(logits)
632 onehot_labels = math_ops.cast(onehot_labels, logits.dtype)
--> 633 logits.get_shape().assert_is_compatible_with(onehot_labels.get_shape())
634
635 if label_smoothing > 0:
/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/tensor_shape.py in assert_is_compatible_with(self, other)
735 """
736 if not self.is_compatible_with(other):
--> 737 raise ValueError("Shapes %s and %s are incompatible" % (self, other))
738
739 def most_specific_compatible_shape(self, other):
ValueError: Shapes (?, 512) and (?, 10) are incompatible
エラーの原因はShapeが正しく設定できていないからなのですが、そもそもShapeは自動的に推定できるはずです。それをエラーのないように人手で設定するのは大変つらい作業です(過去2敗)。正直なんとかして欲しい。
また、トレーニング用に次のようなコードを書いたとします。
# this code dosen't work well
num_steps = 3000
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for step in range(num_steps):
# make batch datasets with size 128
offset = (step * batch_size) % (X_train.shape[0] - batch_size)
# Generate a minibatch.
X_batch = X_train[offset:(offset + batch_size), :]
y_batch = y_train[offset:(offset + batch_size), :]
if step % 100 == 0:
train_accuracy = accuracy.eval(feed_dict={x : X_batch, y: y_batch, keep_prob: 1.0})
print('step %d, training accuracy %g' % (step, train_accuracy))
train_step.run(feed_dict={x : X_batch, y: y_batch, keep_prob: 0.5})
print('test accuracy %g' % accuracy.eval(feed_dict={x : X_test, y : y_test, keep_prob: 1.0}))
実行結果は次のようになりました。
step 0, training accuracy 0.0625
step 100, training accuracy 0.359375
step 200, training accuracy 0.460938
step 300, training accuracy 0.523438
:
:
step 2800, training accuracy 0.578125
step 2900, training accuracy 0.617188
test accuracy 0.585
結果は正直よくないのですが、どこを改善すればいいのか、被疑箇所が多すぎます…。また、こんなコードでも書くのにはそれなりに時間がかかります。比較のために今回書いてみましたが、結構時間がかかりました。
Kerasで書き直し
このあたりをKerasを使ってみるとこうなります。
# Keras
# Model
model = Sequential([
Dense(512, input_shape=(X_train.shape[1], )), # Dense Layer (1st hidden layer)
Activation('relu'),
Dropout(0.2),
Dense(512), # Dense Layer (2nd hidden layer)
Activation('relu'),
Dropout(0.2),
Dense(10), # Readout Layer
Activation('softmax') ])
# Train
model.compile(loss="categorical_crossentropy", optimizer=Adam(), metrics=['accuracy'])
model.fit(X_train, y_train, batch_size=batch_size, epochs=nb_epoch, verbose=1, validation_data=(X_test, y_test))
# Inference
y_estimated = model.predict_classes(X_test)
たったこれだけのコードでこれだけの結果が出ます。
Train on 60000 samples, validate on 10000 samples
Epoch 1/20
60000/60000 [==============================] - 7s - loss: 0.2512 - acc: 0.9250 - val_loss: 0.1101 - val_acc: 0.9659
Epoch 2/20
60000/60000 [==============================] - 7s - loss: 0.1010 - acc: 0.9695 - val_loss: 0.0786 - val_acc: 0.9753
:
:
Epoch 20/20
60000/60000 [==============================] - 13s - loss: 0.0162 - acc: 0.9946 - val_loss: 0.0809 - val_acc: 0.9818
これはすごい。
今更Kerasに着手した理由
KerasがTensorFlowに付属しているからです。階層が大分深い上に、場所はまだまだ変更されていく模様ですが、次のようにimportできます。
# loading keras included tensorflow v1.3
from tensorflow.contrib.keras.api.keras.datasets import mnist
from tensorflow.contrib.keras.api.keras.models import Sequential
from tensorflow.contrib.keras.api.keras.layers import Dense, Dropout, Activation
from tensorflow.contrib.keras.api.keras.optimizers import Adam
from tensorflow.contrib.keras.api.keras.utils import to_categorical
from tensorflow.contrib.keras.api.keras import backend as K
そしてDocumentもTensorFlowの公式サイトで見られます。詳細はKeras公式を見てねって書いてありますね。
つまりこれですね。
Keras on TensorBoard
TensorFlowに付属しているということはTensorBoardにも対応しているはずです。Callbackを使えばうまくいくはずです!
試してみます。
# Doesn't work
# build model with names
old_session = K.get_session()
with tf.Graph().as_default():
with tf.Session() as session:
K.set_session(session)
K.set_learning_phase(1)
model = Sequential()
model.add(Dense(512, input_shape=(X_train.shape[1], ), name="Dense1")) # Dense Layer (1st hidden layer)
model.add(Activation('relu', name="Relu1"))
model.add(Dropout(0.2, name="Dropout1"))
model.add(Dense(512, name="Dense2")) # Dense Layer (2nd hidden layer)
model.add(Activation('relu', name="Relu2"))
model.add(Dropout(0.2, name="Dropout2"))
model.add(Dense(10, name="Dense3")) # Readout Layer
model.add(Activation('softmax', name="Softmax"))
model.summary()
model.compile(loss="categorical_crossentropy", optimizer=Adam(), metrics=['accuracy'])
tensorboard_callback = TensorBoard(log_dir=log_dir, histogram_freq=1)
callbacks = [tensorboard_callback]
history = model.fit(X_train,
y_train,
batch_size=batch_size,
epochs=nb_epoch, verbose=1,
validation_data=(X_test, y_test),
callbacks=callbacks
)
score = model.evaluate(X_test, y_test, verbose=0)
print('Test score', score[0])
print('Test accuracy', score[1])
K.set_session(old_session)
実行結果はこうなってます。
TypeErrorTraceback (most recent call last)
<ipython-input-15-eb62e6893019> in <module>()
10 model.add(Dense(512, input_shape=(X_train.shape[1], ), name="Dense1")) # Dense Layer (1st hidden layer)
11 model.add(Activation('relu', name="Relu1"))
---> 12 model.add(Dropout(0.2, name="Dropout1"))
13 model.add(Dense(512, name="Dense2")) # Dense Layer (2nd hidden layer)
14 model.add(Activation('relu', name="Relu2"))
/usr/local/lib/python3.5/dist-packages/tensorflow/contrib/keras/python/keras/models.py in add(self, layer)
507 output_masks=[None])
508 else:
--> 509 output_tensor = layer(self.outputs[0])
510 if isinstance(output_tensor, list):
511 raise TypeError('All layers in a Sequential model '
/usr/local/lib/python3.5/dist-packages/tensorflow/contrib/keras/python/keras/engine/topology.py in __call__(self, inputs, **kwargs)
394
395 # Actually call the layer (optionally building it).
--> 396 output = super(Layer, self).__call__(inputs, **kwargs)
397
398 # Handle mask computation.
/usr/local/lib/python3.5/dist-packages/tensorflow/python/layers/base.py in __call__(self, inputs, *args, **kwargs)
448 # Check input assumptions set after layer building, e.g. input shape.
449 self._assert_input_compatibility(inputs)
--> 450 outputs = self.call(inputs, *args, **kwargs)
451
452 # Apply activity regularization.
/usr/local/lib/python3.5/dist-packages/tensorflow/contrib/keras/python/keras/layers/core.py in call(self, inputs, training)
113 if training is None:
114 training = K.learning_phase()
--> 115 output = super(Dropout, self).call(inputs, training=training)
116 if training is K.learning_phase():
117 output._uses_learning_phase = True # pylint: disable=protected-access
/usr/local/lib/python3.5/dist-packages/tensorflow/python/layers/core.py in call(self, inputs, training)
262 return utils.smart_cond(training,
263 dropped_inputs,
--> 264 lambda: array_ops.identity(inputs))
265
266
/usr/local/lib/python3.5/dist-packages/tensorflow/python/layers/utils.py in smart_cond(pred, fn1, fn2, name)
206 raise TypeError('`fn2` must be callable.')
207
--> 208 pred_value = constant_value(pred)
209 if pred_value is not None:
210 if pred_value:
/usr/local/lib/python3.5/dist-packages/tensorflow/python/layers/utils.py in constant_value(pred)
236 pred_value = tensor_util.constant_value(pred)
237 else:
--> 238 raise TypeError('`pred` must be a Tensor, a Variable, or a Python bool.')
239 return pred_value
TypeError: `pred` must be a Tensor, a Variable, or a Python bool.
ダメでした(未解決)このあたり見るとできそうなんですけど…。
- [TF]KerasからTensorboardを使用する方法 - Qiita
- Kerasのcallbackを試す(modelのsave,restore/TensorBoard書き出し/early stopping) - Qiita
- How do I use the Tensorboard callback of Keras? - Stack Overflow
もっと仕様理解した上で挑んでみます。あとはPythonのデバッグ方法を知りたい…!
おまけ
たまたま見つけたStackoverflowの「Scipyってなんて略す?」の議論が面白かったです。