tensorflowで遊びはじめました
世間で流行っているtensorflow
で遊び始めました。記録がてらに遊んだことをまとめてみます。
世の中の記事はどうもtensorflowのチュートリアルの「MNISTをやってみた」とか、「CNNを実行してみた。」などの記事が多い印象があります。
一方で「手書き文字を認識するアプリを作ろう」といった具体的にアプリを作ると必要になってくる情報が少ない印象があるのでまとめてみます。
- Tensorflowの学習のさせかた(Estimator)
- Tensorflowの学習結果の利用方法(SavedModel & tensorflow serving)
を中心にまとめてみます。
自分の tensorflow や DeepLearning との付き合い方
自分は数学の天才でも無いのでニューラルネットワークや深層学習の専門家を目指すつもりはないので
- ネットワークは誰か(論文など)を参考に作る
- ネットワークを自分でこねくり回したりはしない
- 学習は自前のPCで実施したりする
- 学習結果を利用してアプリは公開する(かも)
くらいの立ち位置です。
あと、tensorflowを使うにあたって決まりは無いのですが、contribの下にあるパッケージは極力使わない方針でやってみようと考えています。
contribの下にあるパッケージはどうも節操なく色々なものが入ってそうで、流行り廃りも速そうなので近寄りたくないのです……。
TensorFlow’s high-level machine learning API (Estimator )
tensorflowは以前はとてもプリミティブなAPIしか提供していない印象があったのですが、現在は割と高水準なAPIも提供しているようです。
特にestimatorは、tensorflowのsessionなどを隠蔽してくれて、モデルの構築、学習、評価のフローを隠蔽してくれるので利用すると色々楽です。
使い方としては、公式のチュートリアルを参考にするのが良いと思います。
この記事に書いてある内容は基本的にこのチュートリアルの抜粋です。
Tensorflowが提供してくれているEstimatorとしては以下のものがあります。
- tf.estimator.LinearClassifier
- tf.estimator.LinearRegressor
- tf.estimator.DNNClassifier
- tf.estimator.DNNRegressor
- tf.estimator.DNNLinearCombinedClassifier
- tf.estimator.DNNRegressor
これらを利用する場合は、それぞれのモジュールの説明を見れば使えるかと思います。
Estimatorを自作する
上記のモジュールを使わずに自前でネットワークを組む場合(この場合が多い?)は、Estimator
を自分で作ることになります。
Estimator
はtf.estimator.Estimator で作ります。
引数の詳細はマニュアルを読むのが良いと思いますが、とりあえずmodel_fn
とparams
だけ知っていれば使えるようになると思います。
nn = tf.estimator.Estimator(model_fn=model_fn, params=model_params)
# model_fnは、EstimatorSpecを返す関数を指定します。
# paramsには学習時のハイパーパラメータを指定します。
model_fnの作成
ここで、model_fnは実際どうやって作るのか?ということになると思います。
model_fnはmodeとfeatureとparamsの3つを引数に取って、それらの情報からEstimatorSpecを作成して返す関数です。
引数はそれぞれ
- modeはこれから実行するものが、予測なのか学習なのかを示す値です( tf.estimator.ModeKeys.PREDICTなど)
- featureは名前の通り入力データです
- paramsは
tf.estimator.Estimator
で渡したハイパーパラメータが渡って来ます
となります。
返り値のEstimatorSpecの作成方法を次は見てみます。
EstimatorSpecの作成方法
EstimatorSpecは、tf.estimator.EstimatorSpec で作成できます。
tf.estimator.EstimatorSpec(mode=mode,
predictions=predictions,
loss=loss,
train_op=train_op,
eval_metric_ops=eval_metric_ops,
export_outputs=export_outputs,
training_chief_hooks=None,
training_hooks=None,
scaffold=None)
この関数の引数をそれぞれmodel_fn内で設定していくことになります。
具体的には、
- train_op
- loss
- predictions
の三つをとりあえず指定しておけば良いです。
例として
- 3層の隠れ層からなるネットワーク
- crossentropyをloss 関数
- 最適化手法はGradientDescentOptimizer
というものを作成してみます
def model_fn(features, labels, mode, params):
# ここで渡ってくるparamsというのはEstimator作成時の引数のparamsです
hidden1 = tf.layers.dense(inputs=feature['x'], units=10, activation=tf.nn.relu)
hidden2 = tf.layers.dense(inputs=hidden1,units=20, activation=tf.nn.relu)
hidden3 = tf.layers.dense(inputs=hidden2, units=10, activation=tf.nn.relu)
y = tf.layers.dense(inputs=hidden3, units=3, activation=tf.nn.softmax)
loss = None
train_op = None
# 予測を実行する場合はmodeがtf.estimator.ModeKeys.PREDICTが指定されています。
# この時は訓練が実行されないようにしておきます。
# 要は、lossとtrain_opはNoneのままです。
if mode != tf.estimator.ModeKeys.PREDICT:
y_ = tf.one_hot(labels, depth=3)
loss = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
train_op = tf.train.GradientDescentOptimizer(0.01).minimize(loss, global_step=tf.train.get_global_step())
predictions = y
spec = tf.estimator.EstimatorSpec(mode=mode,
predictions=predictions,
loss=loss,
train_op=train_op)
return spec
Estimatorの作成
ここまでで、Estimatorを作成する準備が出来たのでEstimatorを作ってみます。
上の関数では特にハイパーパラメータの指定が無い(酷い!)ので、適当に渡してEstimatorを作ります。
model_params = {}
nn = tf.estimator.Estimator(model_fn=model_fn, params=model_params)
無事Estimator
を作ることが出来たはずです。
それでは、このEstimatorを使って学習、評価、予測を実行してみます。
Estimatorを使った学習、評価、予測
Estimatorを使って学習をする場合は、作成したEstimatorのtrain
メソッドを呼べば自動的に学習してくれます。
trainの第一引数は、教師データを返すような関数を指定します。
例えば以下のような関数です。
# 訓練データを返す関数
train_input_fn = tf.estimator.inputs.numpy_input_fn(
x={"x": np.array(train_x, dtype='float32')} ,
y=np.array(train_y, dtype='int32'),
num_epochs=None,
shuffle=True)
上記の関数を入力として、stepsは5000にして学習を行なう場合は以下のようになります。
# Train
nn.train(input_fn=train_input_fn, steps=5000)
評価を実行する場合は、evaluate
メソッドを呼ぶことになります。
引数としては、train
メソッドと同様に入力データを返す関数を指定します。
# テストデータを返す関数
test_input_fn = tf.estimator.inputs.numpy_input_fn(
x={"x": np.array(test_x, dtype='float32')},
y=np.array(test_y, dtype='int32'),
num_epochs=1,
shuffle=False)
ev = nn.evaluate(input_fn=test_input_fn)
# 評価結果を出力してみる
for key in sorted(ev):
print("%s: %s" % (key, ev[key]))
予測を実行する場合には、predict
メソッドを呼べば良いです。
引数としては、train
メソッドと同様に入力データを返す関数を指定します。
# Print out predictions
predict_input_fn = tf.estimator.inputs.numpy_input_fn(
x={"x": np.array(test_x,dtype='float32')},
num_epochs=1,
shuffle=False)
predictions = nn.predict(input_fn=predict_input_fn)
for i, j in enumerate(predictions):
print(i, j)
Estimatorのまとめ
Estimator
という学習、評価、予測をまとめてくれる便利なフレームワークがありますEstimator
を作成するには、EstimatorSpec
を返すmodel関数を定義します- model関数には実行モードとデータとハイパーパラメータが渡ってきます
- model関数はmodeと予測結果、誤差関数、最適化手法を定義し、これらの情報からEstimatorSpecを作成します
Estimator
を作成すれば、train, evaluate, predictの関数で学習、評価、予測が実行できます- それぞれのメソッドには、入力を与える関数を定義する必要があります
tf.estimator.inputs.numpy_input_fn
などを利用すれば手軽に実装できます
savedmodelについて
書くのに疲れたので、明日以降に別記事にします。