Join us at TensorFlow World, Oct 28-31. Use code TF20 for 20% off select passes. Register now

Keras

View on TensorFlow.org Run in Google Colab View source on GitHub

Kerasは、深層学習モデルを構築・学習するための高水準APIです。
迅速なプロトタイピングから先端研究、実運用にも使用されており、3つの特徴があります:

  • ユーザーフレンドリー
    一般的なユースケースに最適化したKerasのAPIは、シンプルで統一性があります。誤った使い方をした場合のエラー出力も明快で、どう対応すべきか一目瞭然です。
  • モジュール性
    Kerasのモデルは、設定可能なモジュールをつなぎ合わせて作られます。モジュールのつなぎ方には、ほとんど制約がありません。
  • 拡張性
    簡単にモジュールをカスタマイズできるため、研究の新しいアイデアを試すのに最適です。新しい層、損失関数を自作し、最高水準のモデルを開発しましょう。

tf.keras のインポート

tf.keras は、TensorFlow版 Keras API 仕様 です。 モデルを構築・学習するための高水準APIであり、TensorFlow特有の機能である Eagerモードtf.data パイプライン、 Estimators にも正式に対応しています。 tf.keras は、TensorFlowの柔軟性やパフォーマンスを損ねることなく使いやすさを向上しています。

TensorFlowプログラムの準備として、先ずは tf.keras をインポートしましょう:

!pip install -q tensorflow=="1.*"
!pip install -q pyyaml  # YAML形式でモデルを保存する際に必要です。
from __future__ import absolute_import, division, print_function, unicode_literals

import tensorflow as tf
from tensorflow.keras import layers

print(tf.version.VERSION)
print(tf.keras.__version__)
1.14.0
2.2.4-tf

tf.keras ではKerasと互換性のあるコードを実行できますが、注意点もあります:

  • 最新リリースのTensorFlowに同梱されている tf.keras のバージョンと、pipインストールした最新の keras のバージョンが同一とは限りません。バージョンは tf.keras.__version__ の出力をご確認ください。
  • モデルの重みを保存する場合、 tf.keras のデフォルトの保存形式は チェックポイント形式です。 HDF5形式にて保存する場合は、 save_format='h5' オプションを指定してください。

単純なモデルの構築

シーケンシャル モデル

Kerasでは、を組み合わせてモデルを構築します。 モデルは通常、複数の層から成るグラフ構造をしています。 最も一般的なモデルは、単純に層を積み重ねる類の tf.keras.Sequential モデルです。

単純な全結合ネットワーク(いわゆる マルチ レイヤー パーセプトロン)を構築してみましょう:

model = tf.keras.Sequential()
# ユニット数が64の全結合層をモデルに追加します:
model.add(layers.Dense(64, activation='relu'))
# 全結合層をもう一つ追加します:
model.add(layers.Dense(64, activation='relu'))
# 出力ユニット数が10のソフトマックス層を追加します:
model.add(layers.Dense(10, activation='softmax'))
WARNING: Logging before flag parsing goes to stderr.
W0802 20:24:42.012985 139968846919424 deprecation.py:506] From /tmpfs/src/tf_docs_env/lib/python3.5/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor

層の設定

tf.keras.layers はさまざまな層を提供していますが、共通のコンストラクタ引数があります:

  • activation: 層の活性化関数を設定します。組み込み関数、もしくは呼び出し可能オブジェクトの名前で指定します。デフォルト値は、活性化関数なし。
  • kernel_initializerbias_initializer: 層の重み(カーネルとバイアス)の初期化方式。名前、もしくは呼び出し可能オブジェクトで指定します。デフォルト値は、 "Glorot uniform"
  • kernel_regularizerbias_regularizer:層の重み(カーネルとバイアス)に適用する、L1やL2等の正則化方式。デフォルト値は、正則化なし。

コンストラクタ引数を使って tf.keras.layers.Dense 層をインスタンス化する例を以下に示します:

# シグモイド層を1層作る場合:
layers.Dense(64, activation='sigmoid')
# 別の記法:
layers.Dense(64, activation=tf.sigmoid)

# カーネル行列に係数0,01のL1正則化を課した全結合層:
layers.Dense(64, kernel_regularizer=tf.keras.regularizers.l1(0.01))

# バイアスベクトルに係数0,01のL2正則化を課した全結合層:
layers.Dense(64, bias_regularizer=tf.keras.regularizers.l2(0.01))

# カーネルをランダム直交行列で初期化した全結合層:
layers.Dense(64, kernel_initializer='orthogonal')

# バイアスベクトルを2.0で初期化した全結合層:
layers.Dense(64, bias_initializer=tf.keras.initializers.constant(2.0))
<tensorflow.python.keras.layers.core.Dense at 0x7f4cb1b7e6a0>

学習と評価

学習の準備

モデルを構築したあとは、compile メソッドを呼んで学習方法を構成します:

model = tf.keras.Sequential([
# ユニット数64の全結合層をモデルに追加する:
layers.Dense(64, activation='relu', input_shape=(32,)),
# もう1層追加する:
layers.Dense(64, activation='relu'),
# 出力ユニット数10のソフトマックス層を追加する:
layers.Dense(10, activation='softmax')])

model.compile(optimizer=tf.train.AdamOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

tf.keras.Model.compile には3つの重要な引数があります:

  • optimizer: このオブジェクトが訓練方式を規定します。 tf.train モジュールから tf.train.AdamOptimizertf.train.RMSPropOptimizertf.train.GradientDescentOptimizer等のオプティマイザ インスタンスを指定します。
  • loss: 最適化の過程で最小化する関数を指定します。平均二乗誤差(mse)やcategorical_crossentropybinary_crossentropy等が好んで使われます。損失関数は名前、もしくは tf.keras.losses モジュールから呼び出し可能オブジェクトとして指定できます。
  • metrics: 学習の監視に使用します。 名前、もしくはtf.keras.metrics モジュールから呼び出し可能オブジェクトとして指定できます。

学習用モデルの構成例を2つ、以下に示します:

# 平均二乗誤差 回帰モデルを構成する。
model.compile(optimizer=tf.train.AdamOptimizer(0.01),
              loss='mse',       # 平均二乗誤差
              metrics=['mae'])  # 平均絶対誤差

# 多クラス分類モデルを構成する。
model.compile(optimizer=tf.train.RMSPropOptimizer(0.01),
              loss=tf.keras.losses.categorical_crossentropy,
              metrics=[tf.keras.metrics.categorical_accuracy])

NumPy データの入力

小規模なデータセットであれば、モデルを学習・評価する際にインメモリの NumPy配列を使いましょう。 モデルは fit メソッドを使って学習データに適合させます。

import numpy as np

def random_one_hot_labels(shape):
  n, n_class = shape
  classes = np.random.randint(0, n_class, n)
  labels = np.zeros((n, n_class))
  labels[np.arange(n), classes] = 1
  return labels

data = np.random.random((1000, 32))
labels = random_one_hot_labels((1000, 10))

model.fit(data, labels, epochs=10, batch_size=32)
W0802 20:24:42.341299 139968846919424 deprecation.py:506] From /tmpfs/src/tf_docs_env/lib/python3.5/site-packages/tensorflow/python/training/rmsprop.py:119: calling Ones.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor

Epoch 1/10
1000/1000 [==============================] - 0s 140us/sample - loss: 2.3394 - categorical_accuracy: 0.0980
Epoch 2/10
1000/1000 [==============================] - 0s 40us/sample - loss: 2.3219 - categorical_accuracy: 0.0960
Epoch 3/10
1000/1000 [==============================] - 0s 41us/sample - loss: 2.3122 - categorical_accuracy: 0.1080
Epoch 4/10
1000/1000 [==============================] - 0s 40us/sample - loss: 2.3033 - categorical_accuracy: 0.1060
Epoch 5/10
1000/1000 [==============================] - 0s 38us/sample - loss: 2.3061 - categorical_accuracy: 0.1220
Epoch 6/10
1000/1000 [==============================] - 0s 37us/sample - loss: 2.2988 - categorical_accuracy: 0.1330
Epoch 7/10
1000/1000 [==============================] - 0s 39us/sample - loss: 2.2835 - categorical_accuracy: 0.1260
Epoch 8/10
1000/1000 [==============================] - 0s 35us/sample - loss: 2.2578 - categorical_accuracy: 0.1590
Epoch 9/10
1000/1000 [==============================] - 0s 39us/sample - loss: 2.2381 - categorical_accuracy: 0.1690
Epoch 10/10
1000/1000 [==============================] - 0s 37us/sample - loss: 2.2036 - categorical_accuracy: 0.1880

<tensorflow.python.keras.callbacks.History at 0x7f4cb11515f8>

tf.keras.Model.fit は3つの重要な引数があります:

  • epochs: エポック は学習の構成単位で、(バッチに分割した)全入力データを一巡したものを1エポックと換算します。
  • batch_size: NumPyデータを渡されたモデルは、データをバッチに分割し、それを順繰りに舐めて学習を行います。一つのバッチに配分するサンプル数を、バッチサイズとして整数で指定します。全サンプル数がバッチサイズで割り切れない場合、最後のバッチだけ小さくなる可能性があることに注意しましょう。
  • validation_data: モデルの試作中に評価データを使って簡単にパフォーマンスを監視したい場合は、この引数に入力とラベルの対を渡すことで、各エポックの最後に推論モードで評価データの損失と評価指標を表示することができます。

validation_data の使用例:

import numpy as np

data = np.random.random((1000, 32))
labels = random_one_hot_labels((1000, 10))

val_data = np.random.random((100, 32))
val_labels = random_one_hot_labels((100, 10))

model.fit(data, labels, epochs=10, batch_size=32,
          validation_data=(val_data, val_labels))
Train on 1000 samples, validate on 100 samples
Epoch 1/10
1000/1000 [==============================] - 0s 70us/sample - loss: 2.3316 - categorical_accuracy: 0.1070 - val_loss: 2.3167 - val_categorical_accuracy: 0.0300
Epoch 2/10
1000/1000 [==============================] - 0s 37us/sample - loss: 2.2994 - categorical_accuracy: 0.1150 - val_loss: 2.3586 - val_categorical_accuracy: 0.0600
Epoch 3/10
1000/1000 [==============================] - 0s 38us/sample - loss: 2.2927 - categorical_accuracy: 0.1190 - val_loss: 2.3230 - val_categorical_accuracy: 0.1000
Epoch 4/10
1000/1000 [==============================] - 0s 43us/sample - loss: 2.2684 - categorical_accuracy: 0.1450 - val_loss: 2.3058 - val_categorical_accuracy: 0.1300
Epoch 5/10
1000/1000 [==============================] - 0s 44us/sample - loss: 2.2353 - categorical_accuracy: 0.1730 - val_loss: 2.2795 - val_categorical_accuracy: 0.1600
Epoch 6/10
1000/1000 [==============================] - 0s 38us/sample - loss: 2.2210 - categorical_accuracy: 0.1820 - val_loss: 2.3302 - val_categorical_accuracy: 0.1000
Epoch 7/10
1000/1000 [==============================] - 0s 40us/sample - loss: 2.1948 - categorical_accuracy: 0.2020 - val_loss: 2.3672 - val_categorical_accuracy: 0.1200
Epoch 8/10
1000/1000 [==============================] - 0s 43us/sample - loss: 2.1519 - categorical_accuracy: 0.2180 - val_loss: 2.4261 - val_categorical_accuracy: 0.1000
Epoch 9/10
1000/1000 [==============================] - 0s 44us/sample - loss: 2.1207 - categorical_accuracy: 0.2290 - val_loss: 2.3817 - val_categorical_accuracy: 0.1600
Epoch 10/10
1000/1000 [==============================] - 0s 40us/sample - loss: 2.0963 - categorical_accuracy: 0.2440 - val_loss: 2.4482 - val_categorical_accuracy: 0.1100

<tensorflow.python.keras.callbacks.History at 0x7f4d005bfe48>

tf.data データセットの入力

大規模なデータセット、もしくは複数デバイスを用いた学習を行う際は Datasets API を使いましょう。 fitメソッドにtf.data.Dataset インスタンスを渡します:

# データセットのインスタンス化の例:
dataset = tf.data.Dataset.from_tensor_slices((data, labels))
dataset = dataset.batch(32)
dataset = dataset.repeat()

# `fit` にデータセットを渡す際は、`steps_per_epoch` の指定をお忘れなく:
model.fit(dataset, epochs=10, steps_per_epoch=30)
W0802 20:24:43.540982 139968846919424 training_utils.py:1300] Expected a shuffled dataset but input dataset `x` is not shuffled. Please invoke `shuffle()` on input dataset.

Epoch 1/10
30/30 [==============================] - 0s 3ms/step - loss: 2.0586 - categorical_accuracy: 0.2490
Epoch 2/10
30/30 [==============================] - 0s 1ms/step - loss: 2.0170 - categorical_accuracy: 0.2788
Epoch 3/10
30/30 [==============================] - 0s 1ms/step - loss: 1.9696 - categorical_accuracy: 0.3013
Epoch 4/10
30/30 [==============================] - 0s 1ms/step - loss: 1.9198 - categorical_accuracy: 0.3173
Epoch 5/10
30/30 [==============================] - 0s 1ms/step - loss: 1.8869 - categorical_accuracy: 0.3269
Epoch 6/10
30/30 [==============================] - 0s 1ms/step - loss: 1.8265 - categorical_accuracy: 0.3504
Epoch 7/10
30/30 [==============================] - 0s 1ms/step - loss: 1.7613 - categorical_accuracy: 0.3611
Epoch 8/10
30/30 [==============================] - 0s 1ms/step - loss: 1.7262 - categorical_accuracy: 0.3750
Epoch 9/10
30/30 [==============================] - 0s 1ms/step - loss: 1.6784 - categorical_accuracy: 0.3996
Epoch 10/10
30/30 [==============================] - 0s 1ms/step - loss: 1.6249 - categorical_accuracy: 0.4145

<tensorflow.python.keras.callbacks.History at 0x7f4d01be8ef0>

fit メソッドの引数 steps_per_epoch には、1エポックあたりの学習ステップ数を指定します。 Dataset がバッチを生成するため batch_sizeの指定は不要です。

Dataset は評価データにも使えます:

dataset = tf.data.Dataset.from_tensor_slices((data, labels))
dataset = dataset.batch(32).repeat()

val_dataset = tf.data.Dataset.from_tensor_slices((val_data, val_labels))
val_dataset = val_dataset.batch(32).repeat()

model.fit(dataset, epochs=10, steps_per_epoch=30,
          validation_data=val_dataset,
          validation_steps=3)
W0802 20:24:44.046090 139968846919424 training_utils.py:1300] Expected a shuffled dataset but input dataset `x` is not shuffled. Please invoke `shuffle()` on input dataset.

Epoch 1/10
30/30 [==============================] - 0s 4ms/step - loss: 1.6284 - categorical_accuracy: 0.4146 - val_loss: 2.6582 - val_categorical_accuracy: 0.1354
Epoch 2/10
30/30 [==============================] - 0s 1ms/step - loss: 1.5322 - categorical_accuracy: 0.4541 - val_loss: 2.8227 - val_categorical_accuracy: 0.1250
Epoch 3/10
30/30 [==============================] - 0s 1ms/step - loss: 1.4738 - categorical_accuracy: 0.4744 - val_loss: 2.8841 - val_categorical_accuracy: 0.1354
Epoch 4/10
30/30 [==============================] - 0s 1ms/step - loss: 1.4494 - categorical_accuracy: 0.4786 - val_loss: 2.8874 - val_categorical_accuracy: 0.1562
Epoch 5/10
30/30 [==============================] - 0s 1ms/step - loss: 1.4225 - categorical_accuracy: 0.4744 - val_loss: 3.0400 - val_categorical_accuracy: 0.1458
Epoch 6/10
30/30 [==============================] - 0s 1ms/step - loss: 1.3599 - categorical_accuracy: 0.5256 - val_loss: 3.4032 - val_categorical_accuracy: 0.0938
Epoch 7/10
30/30 [==============================] - 0s 1ms/step - loss: 1.3207 - categorical_accuracy: 0.5385 - val_loss: 3.0239 - val_categorical_accuracy: 0.1875
Epoch 8/10
30/30 [==============================] - 0s 1ms/step - loss: 1.3113 - categorical_accuracy: 0.5331 - val_loss: 3.1151 - val_categorical_accuracy: 0.1146
Epoch 9/10
30/30 [==============================] - 0s 1ms/step - loss: 1.3021 - categorical_accuracy: 0.5256 - val_loss: 3.6585 - val_categorical_accuracy: 0.1146
Epoch 10/10
30/30 [==============================] - 0s 1ms/step - loss: 1.2351 - categorical_accuracy: 0.5801 - val_loss: 3.6765 - val_categorical_accuracy: 0.0938

<tensorflow.python.keras.callbacks.History at 0x7f4d005bf710>

評価と推論

tf.keras.Model.evaluatetf.keras.Model.predict メソッドは、NumPyデータとtf.data.Datasetに使えます。

推論モードでデータの損失と評価指標を評価する例を示します:

data = np.random.random((1000, 32))
labels = random_one_hot_labels((1000, 10))

model.evaluate(data, labels, batch_size=32)

model.evaluate(dataset, steps=30)
1000/1000 [==============================] - 0s 42us/sample - loss: 4.1114 - categorical_accuracy: 0.0950
30/30 [==============================] - 0s 2ms/step - loss: 1.7046 - categorical_accuracy: 0.4437

[1.704619711637497, 0.44375]

推論 結果を最終層のNumPy配列として出力する例を示します:

result = model.predict(data, batch_size=32)
print(result.shape)
(1000, 10)

高度なモデルの構築

Functional API

tf.keras.Sequential モデルは層を積み重ねる単純なつくりであり、あらゆるモデルに対応しているわけではありません。 以下に挙げる複雑な構成のモデルを構築するには Keras functional API を使いましょう:

  • 入力ヘッドが複数あるモデル
  • 出力ヘッドが複数あるモデル
  • 共有層(おなじ層が複数回呼び出される)を含むモデル
  • (残差結合のように)データの流れが分岐するモデル

Functional API を用いたモデル構築の流れ:

  1. 層のインスタンスは呼び出し可能で、テンソルを返します。
  2. 入力テンソルと出力テンソルを使ってtf.keras.Modelインスタンスを定義します。
  3. モデルはSequentialモデルと同様の方法で学習します。

Functional API を使って全結合ネットワークを構築する例を示します:

inputs = tf.keras.Input(shape=(32,))  # プレイスホルダのテンソルを返します。

# 層のインスタンスは呼び出し可能で、テンソルを返します。
x = layers.Dense(64, activation='relu')(inputs)
x = layers.Dense(64, activation='relu')(x)
predictions = layers.Dense(10, activation='softmax')(x)

inputsとoutputsを引数にモデルをインスタンス化します。

model = tf.keras.Model(inputs=inputs, outputs=predictions)

# コンパイル時に学習方法を指定します。
model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# 5エポック学習します。
model.fit(data, labels, batch_size=32, epochs=5)
Epoch 1/5
1000/1000 [==============================] - 0s 87us/sample - loss: 2.3631 - acc: 0.0950
Epoch 2/5
1000/1000 [==============================] - 0s 42us/sample - loss: 2.3419 - acc: 0.0960
Epoch 3/5
1000/1000 [==============================] - 0s 40us/sample - loss: 2.3206 - acc: 0.1020
Epoch 4/5
1000/1000 [==============================] - 0s 37us/sample - loss: 2.3073 - acc: 0.1150
Epoch 5/5
1000/1000 [==============================] - 0s 36us/sample - loss: 2.2995 - acc: 0.1170

<tensorflow.python.keras.callbacks.History at 0x7f4cb1bd4b38>

モデルの派生

tf.keras.Model を継承し順伝播を定義することでカスタムモデルを構築できます。 __init__ メソッドにクラス インスタンスの属性として層をつくります。 call メソッドに順伝播を定義します。

順伝播を命令型で記載できるため、モデルの派生は Eagerモード でより威力を発揮します。

キーポイント:目的にあったAPIを選択しましょう。派生モデルは柔軟性を与えてくれますが、その代償にモデルはより複雑になりエラーを起こしやすくなります。目的がFunctional APIで賄えるのであれば、そちらを使いましょう。

tf.keras.Modelを継承して順伝播をカスタマイズした例を以下に示します:

class MyModel(tf.keras.Model):

  def __init__(self, num_classes=10):
    super(MyModel, self).__init__(name='my_model')
    self.num_classes = num_classes
    # 層をここに定義します。
    self.dense_1 = layers.Dense(32, activation='relu')
    self.dense_2 = layers.Dense(num_classes, activation='sigmoid')

  def call(self, inputs):
    # (`__init__`)にてあらかじめ定義した層を使って
    # 順伝播をここに定義します。
    x = self.dense_1(inputs)
    return self.dense_2(x)

  def compute_output_shape(self, input_shape):
    # 派生モデルを使用する場合、
    # このメソッドをオーバーライドすることになります。
    # 派生モデルを使用しない場合、このメソッドは省略可能です。
    shape = tf.TensorShape(input_shape).as_list()
    shape[-1] = self.num_classes
    return tf.TensorShape(shape)

今定義した派生モデルをインスンス化します。

model = MyModel(num_classes=10)

# コンパイル時に学習方法を指定します。
model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# 5エポック学習します。
model.fit(data, labels, batch_size=32, epochs=5)
W0802 20:24:45.667503 139968846919424 deprecation.py:323] From /tmpfs/src/tf_docs_env/lib/python3.5/site-packages/tensorflow/python/ops/math_grad.py:1250: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.where in 2.0, which has the same broadcast rule as np.where

Epoch 1/5
1000/1000 [==============================] - 0s 111us/sample - loss: 2.3138 - acc: 0.1110
Epoch 2/5
1000/1000 [==============================] - 0s 42us/sample - loss: 2.3125 - acc: 0.1130
Epoch 3/5
1000/1000 [==============================] - 0s 43us/sample - loss: 2.3084 - acc: 0.1130
Epoch 4/5
1000/1000 [==============================] - 0s 42us/sample - loss: 2.3048 - acc: 0.1190
Epoch 5/5
1000/1000 [==============================] - 0s 42us/sample - loss: 2.3010 - acc: 0.1190

<tensorflow.python.keras.callbacks.History at 0x7f4ca8774358>

層のカスタマイズ

tf.keras.layers.Layerを継承して層をカスタマイズするには、以下のメソッドを実装します:

  • build: 層の重みを定義します。add_weightメソッドで重みを追加します。
  • call: 順伝播を定義します。
  • compute_output_shape: 入力の形状をもとに出力の形状を算出する方法を指定します。
  • 必須ではありませんが、get_configメソッド と from_config クラスメソッドを実装することで層をシリアライズすることができます。

入力のカーネル行列を matmul (行列乗算)するカスタム層の実装例:

class MyLayer(layers.Layer):

  def __init__(self, output_dim, **kwargs):
    self.output_dim = output_dim
    super(MyLayer, self).__init__(**kwargs)

  def build(self, input_shape):
    shape = tf.TensorShape((input_shape[1], self.output_dim))
    # 学習可能な重みを指定します。
    self.kernel = self.add_weight(name='kernel',
                                  shape=shape,
                                  initializer='uniform',
                                  trainable=True)
    # 最後に`build` メソッドを呼ぶのをお忘れなく。
    super(MyLayer, self).build(input_shape)

  def call(self, inputs):
    return tf.matmul(inputs, self.kernel)

  def compute_output_shape(self, input_shape):
    shape = tf.TensorShape(input_shape).as_list()
    shape[-1] = self.output_dim
    return tf.TensorShape(shape)

  def get_config(self):
    base_config = super(MyLayer, self).get_config()
    base_config['output_dim'] = self.output_dim
    return base_config

  @classmethod
  def from_config(cls, config):
    return cls(**config)

カスタマイズした層を使ってモデルを構築します:

model = tf.keras.Sequential([
    MyLayer(10),
    layers.Activation('softmax')])

# コンパイル時に学習方法を指定します。
model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# 5エポック学習します。
model.fit(data, labels, batch_size=32, epochs=5)
W0802 20:24:46.207237 139968846919424 deprecation.py:506] From /tmpfs/src/tf_docs_env/lib/python3.5/site-packages/tensorflow/python/keras/initializers.py:119: calling RandomUniform.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor

Epoch 1/5
1000/1000 [==============================] - 0s 73us/sample - loss: 2.3096 - acc: 0.0940
Epoch 2/5
1000/1000 [==============================] - 0s 32us/sample - loss: 2.3082 - acc: 0.0970
Epoch 3/5
1000/1000 [==============================] - 0s 32us/sample - loss: 2.3050 - acc: 0.0970
Epoch 4/5
1000/1000 [==============================] - 0s 32us/sample - loss: 2.3020 - acc: 0.0960
Epoch 5/5
1000/1000 [==============================] - 0s 29us/sample - loss: 2.2994 - acc: 0.1030

<tensorflow.python.keras.callbacks.History at 0x7f4cb1b7e390>

コールバック

コールバックは、学習中のモデルの挙動をカスタマイズするためにモデルに渡されるオブジェクトです。 コールバック関数は自作する、もしくは以下に示すtf.keras.callbacksが提供する組み込み関数を利用できます:

tf.keras.callbacks.Callbackを使用するには、モデルの fit メソッドにコールバック関数を渡します:

callbacks = [
  # `val_loss` が2エポック経っても改善しなければ学習を中断させます。
  tf.keras.callbacks.EarlyStopping(patience=2, monitor='val_loss'),
  # TensorBoard用ログを`./logs` ディレクトリに書き込みます。
  tf.keras.callbacks.TensorBoard(log_dir='./logs')
]
model.fit(data, labels, batch_size=32, epochs=5, callbacks=callbacks,
          validation_data=(val_data, val_labels))
Train on 1000 samples, validate on 100 samples
Epoch 1/5
1000/1000 [==============================] - 0s 83us/sample - loss: 2.2971 - acc: 0.1090 - val_loss: 2.3014 - val_acc: 0.0700
Epoch 2/5
1000/1000 [==============================] - 0s 38us/sample - loss: 2.2958 - acc: 0.1200 - val_loss: 2.2999 - val_acc: 0.0600
Epoch 3/5
1000/1000 [==============================] - 0s 35us/sample - loss: 2.2937 - acc: 0.1050 - val_loss: 2.2984 - val_acc: 0.0900
Epoch 4/5
1000/1000 [==============================] - 0s 37us/sample - loss: 2.2917 - acc: 0.1230 - val_loss: 2.2992 - val_acc: 0.1000
Epoch 5/5
1000/1000 [==============================] - 0s 39us/sample - loss: 2.2896 - acc: 0.1240 - val_loss: 2.3021 - val_acc: 0.0800

<tensorflow.python.keras.callbacks.History at 0x7f4cb1306208>

保存と復元

重みのみ

tf.keras.Model.save_weightsを使ってモデルの重みの保存やロードを行います。

model = tf.keras.Sequential([
layers.Dense(64, activation='relu', input_shape=(32,)),
layers.Dense(10, activation='softmax')])

model.compile(optimizer=tf.train.AdamOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])
# TensorFlow チェックポイント ファイルに重みを保存します。
model.save_weights('./weights/my_model')

# モデルの状態を復元します。
# 復元対象のモデルと保存されていた重みのモデル構造が同一である必要があります。
model.load_weights('./weights/my_model')
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f4ca8194f98>

デフォルトでは、モデルの重みは TensorFlow チェックポイント 形式で保存されます。 重みはKerasのHDF5形式でも保存できます(マルチバックエンド実装のKerasではHDF5形式がデフォルト):

# 重みをHDF5形式で保存します。
model.save_weights('my_model.h5', save_format='h5')

# モデルの状態を復元します。
model.load_weights('my_model.h5')

構成のみ

モデルの構成も保存可能です。 モデル構造を重み抜きでシリアライズします。 元のモデルのコードがなくとも、保存された構成で再構築できます。 Kerasがサポートしているシリアライズ形式は、JSONとYAMLです。

# JSON形式にモデルをシリアライズします
json_string = model.to_json()
json_string
'{"config": {"layers": [{"config": {"kernel_initializer": {"config": {"seed": null, "dtype": "float32"}, "class_name": "GlorotUniform"}, "bias_regularizer": null, "units": 64, "name": "dense_17", "activation": "relu", "bias_initializer": {"config": {"dtype": "float32"}, "class_name": "Zeros"}, "bias_constraint": null, "kernel_regularizer": null, "trainable": true, "dtype": "float32", "kernel_constraint": null, "activity_regularizer": null, "use_bias": true, "batch_input_shape": [null, 32]}, "class_name": "Dense"}, {"config": {"kernel_initializer": {"config": {"seed": null, "dtype": "float32"}, "class_name": "GlorotUniform"}, "bias_regularizer": null, "units": 10, "name": "dense_18", "activation": "softmax", "bias_initializer": {"config": {"dtype": "float32"}, "class_name": "Zeros"}, "bias_constraint": null, "kernel_regularizer": null, "trainable": true, "dtype": "float32", "kernel_constraint": null, "activity_regularizer": null, "use_bias": true}, "class_name": "Dense"}], "name": "sequential_3"}, "keras_version": "2.2.4-tf", "backend": "tensorflow", "class_name": "Sequential"}'
import json
import pprint
pprint.pprint(json.loads(json_string))
{'backend': 'tensorflow',
 'class_name': 'Sequential',
 'config': {'layers': [{'class_name': 'Dense',
                        'config': {'activation': 'relu',
                                   'activity_regularizer': None,
                                   'batch_input_shape': [None, 32],
                                   'bias_constraint': None,
                                   'bias_initializer': {'class_name': 'Zeros',
                                                        'config': {'dtype': 'float32'}},
                                   'bias_regularizer': None,
                                   'dtype': 'float32',
                                   'kernel_constraint': None,
                                   'kernel_initializer': {'class_name': 'GlorotUniform',
                                                          'config': {'dtype': 'float32',
                                                                     'seed': None}},
                                   'kernel_regularizer': None,
                                   'name': 'dense_17',
                                   'trainable': True,
                                   'units': 64,
                                   'use_bias': True}},
                       {'class_name': 'Dense',
                        'config': {'activation': 'softmax',
                                   'activity_regularizer': None,
                                   'bias_constraint': None,
                                   'bias_initializer': {'class_name': 'Zeros',
                                                        'config': {'dtype': 'float32'}},
                                   'bias_regularizer': None,
                                   'dtype': 'float32',
                                   'kernel_constraint': None,
                                   'kernel_initializer': {'class_name': 'GlorotUniform',
                                                          'config': {'dtype': 'float32',
                                                                     'seed': None}},
                                   'kernel_regularizer': None,
                                   'name': 'dense_18',
                                   'trainable': True,
                                   'units': 10,
                                   'use_bias': True}}],
            'name': 'sequential_3'},
 'keras_version': '2.2.4-tf'}

JSONから(新たに初期化して)モデルを再構築します:

fresh_model = tf.keras.models.model_from_json(json_string)
W0802 20:24:47.549299 139968846919424 deprecation.py:506] From /tmpfs/src/tf_docs_env/lib/python3.5/site-packages/tensorflow/python/ops/init_ops.py:97: calling GlorotUniform.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
W0802 20:24:47.550951 139968846919424 deprecation.py:506] From /tmpfs/src/tf_docs_env/lib/python3.5/site-packages/tensorflow/python/ops/init_ops.py:97: calling Zeros.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor

YAML形式でモデルを保存するには、 TensorFlowをインポートする前に あらかじめpyyamlをインストールしておく必要があります:

yaml_string = model.to_yaml()
print(yaml_string)
backend: tensorflow
class_name: Sequential
config:
  layers:
  - class_name: Dense
    config:
      activation: relu
      activity_regularizer: null
      batch_input_shape: !!python/tuple [null, 32]
      bias_constraint: null
      bias_initializer:
        class_name: Zeros
        config: {dtype: float32}
      bias_regularizer: null
      dtype: float32
      kernel_constraint: null
      kernel_initializer:
        class_name: GlorotUniform
        config: {dtype: float32, seed: null}
      kernel_regularizer: null
      name: dense_17
      trainable: true
      units: 64
      use_bias: true
  - class_name: Dense
    config:
      activation: softmax
      activity_regularizer: null
      bias_constraint: null
      bias_initializer:
        class_name: Zeros
        config: {dtype: float32}
      bias_regularizer: null
      dtype: float32
      kernel_constraint: null
      kernel_initializer:
        class_name: GlorotUniform
        config: {dtype: float32, seed: null}
      kernel_regularizer: null
      name: dense_18
      trainable: true
      units: 10
      use_bias: true
  name: sequential_3
keras_version: 2.2.4-tf

YAMLからモデルを再構築します:

fresh_model = tf.keras.models.model_from_yaml(yaml_string)

注意:callメソッド内ににPythonコードでモデル構造を定義するため、派生モデルはシリアライズできません。

モデル全体

モデルの重み、構成からオプティマイザ設定までモデル全体をファイルに保存できます。 そうすることで、元のコードなしに、チェックポイントで保存したときと全く同じ状態から学習を再開できます。

# 層の浅いモデルを構築します。
model = tf.keras.Sequential([
  layers.Dense(64, activation='relu', input_shape=(32,)),
  layers.Dense(10, activation='softmax')
])
model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
model.fit(data, labels, batch_size=32, epochs=5)


# HDF5ファイルにモデル全体を保存します。
model.save('my_model.h5')

# 重みとオプティマイザを含む 全く同一のモデルを再構築します。
model = tf.keras.models.load_model('my_model.h5')
Epoch 1/5
1000/1000 [==============================] - 0s 108us/sample - loss: 2.3274 - acc: 0.0940
Epoch 2/5
1000/1000 [==============================] - 0s 47us/sample - loss: 2.3071 - acc: 0.1100
Epoch 3/5
1000/1000 [==============================] - 0s 47us/sample - loss: 2.2990 - acc: 0.1170
Epoch 4/5
1000/1000 [==============================] - 0s 44us/sample - loss: 2.2906 - acc: 0.1240
Epoch 5/5
1000/1000 [==============================] - 0s 42us/sample - loss: 2.2843 - acc: 0.1230

Eagerモード

Eagerモード は、オペレーションを即時に評価する命令型のプログラミング環境です。 Kerasでは必要ありませんが、tf.kerasでサポートされておりプログラムを検査しデバッグするのに便利です。

すべてのtf.kerasモデル構築用APIは、Eagerモード互換性があります。 Sequential や Functional APIも使用できますが、 Eagerモードは特に派生モデル の構築や 層のカスタマイズに有益です。 (既存の層の組み合わせでモデルを作成するAPIの代わりに) 順伝播をコードで実装する必要があります。

詳しくは Eagerモード ガイド (カスタマイズした学習ループとtf.GradientTapeを使ったKerasモデルの適用事例)をご参照ください。

分散

Estimators

Estimators は分散学習を行うためのAPIです。 実運用に耐えるモデルを巨大なデータセットを用いて分散学習するといった産業利用を目的にすえています。

tf.keras.Modeltf.estimator APIによる学習を行うには、 tf.keras.estimator.model_to_estimatorを使ってKerasモデルを tf.estimator.Estimatorオブジェクトに変換する必要があります。

KerasモデルからEstimatorsを作成するをご参照ください。

model = tf.keras.Sequential([layers.Dense(64, activation='relu', input_shape=(32,)),
                          layers.Dense(10,activation='softmax')])

model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

estimator = tf.keras.estimator.model_to_estimator(model)
W0802 20:24:49.304707 139968846919424 estimator.py:1811] Using temporary folder as model directory: /tmp/tmpywq6__g3

注意:Estimator input functionsをデバッグしてデータの検査を行うにはEagerモードで実行してください。

マルチGPU

tf.kerasモデルはtf.contrib.distribute.DistributionStrategyを使用することでマルチGPU上で実行できます。 このAPIを使えば、既存コードをほとんど改変することなく分散学習へ移行できます。

目下、分散方式としてtf.contrib.distribute.MirroredStrategyのみサポートしています。 MirroredStrategy は、シングルマシン上でAllReduce を使った同期学習によりin-grapnレプリケーションを行います。 KerasでDistributionStrategyを使用する場合は、tf.keras.estimator.model_to_estimatorを使って tf.keras.Modeltf.estimator.Estimatorに変換し、Estimatorインスタンスを使って分散学習を行います。

以下の例では、シングルマシンのマルチGPUにtf.keras.Modelを分散します。

まず、単純なモデルを定義します:

model = tf.keras.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10,)))
model.add(layers.Dense(1, activation='sigmoid'))

optimizer = tf.train.GradientDescentOptimizer(0.2)

model.compile(loss='binary_crossentropy', optimizer=optimizer)
model.summary()
Model: "sequential_6"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_23 (Dense)             (None, 16)                176       
_________________________________________________________________
dense_24 (Dense)             (None, 1)                 17        
=================================================================
Total params: 193
Trainable params: 193
Non-trainable params: 0
_________________________________________________________________

入力パイプラインを定義します。input_fn は、複数デバイスにデータを配置するのに使用する tf.data.Dataset を返します。 各デバイスは、入力バッチの一部(デバイス間で均等に分割)を処理します。

def input_fn():
  x = np.random.random((1024, 10))
  y = np.random.randint(2, size=(1024, 1))
  x = tf.cast(x, tf.float32)
  dataset = tf.data.Dataset.from_tensor_slices((x, y))
  dataset = dataset.repeat(10)
  dataset = dataset.batch(32)
  return dataset

次に、 tf.estimator.RunConfigを作成し、 train_distribute 引数にtf.contrib.distribute.MirroredStrategy インスタンスを設定します。MirroredStrategyを作成する際、デバイスの一覧を指定する、もしくは引数でnum_gpus(GPU数)を設定することができます。デフォルトでは、使用可能なすべてのGPUを使用する設定になっています:

strategy = tf.contrib.distribute.MirroredStrategy()
config = tf.estimator.RunConfig(train_distribute=strategy)
W0802 20:24:50.464648 139968846919424 lazy_loader.py:50] 
The TensorFlow contrib module will not be included in TensorFlow 2.0.
For more information, please see:
  * https://github.com/tensorflow/community/blob/master/rfcs/20180907-contrib-sunset.md
  * https://github.com/tensorflow/addons
  * https://github.com/tensorflow/io (for I/O related ops)
If you depend on functionality not listed there, please file an issue.

W0802 20:24:50.467222 139968846919424 cross_device_ops.py:1182] Not all devices in `tf.distribute.Strategy` are visible to TensorFlow.

Kerasモデルを tf.estimator.Estimator インスタンスへ変換します。

keras_estimator = tf.keras.estimator.model_to_estimator(
  keras_model=model,
  config=config,
  model_dir='/tmp/model_dir')

最後に、input_fnsteps引数を指定して Estimator インスタンスを学習します:

keras_estimator.train(input_fn=input_fn, steps=10)
<tensorflow_estimator.python.estimator.estimator.Estimator at 0x7f4bdf52a908>