Chapter 2: TensorFlow 1.x and 2.x

[自分へのメモ] TensorFlow 1.x の部分はいまさら学ぶ意味が無いので省略。

Understanding TensorFlow 2.x (p.60)

Eager execution

TensorFlow 1.x は静的計算グラフを定義する。この種の宣言的プログラミングは多くの人々にとって混乱を招くものである。 PyTorch ではもっと命令的(imperative)かつ動的(dynamic)なやり方で定義をする。

「モデルの定義を動的に行い、即座に実行する」やり方を eager execution と呼ぶ。

PyTorch も TensorFlow 2 も Chainer から Powerful, Flexible, and Intuitive Framework for Neural Networks のスタイルを継承している。

AutoGraph (p.61)

TensorFlow 2 では python の命令コード(if - while, print() など)をサポートしている。

AutoGraph は eager-style pythonコードを受け取り、効率的にグラフ計算を行う。 AutoGraph を利用するのは簡単で、pythonコードをtf.function で修飾すればよい。

import tensorflow as tf def linear_layer(x): return 3 * x + 2 @tf.function def simple_nn(x): return tf.nn.relu(linear_layer(x)) def simple_function(x): return 3 * x

simple_nnはTensorFlowの内部で特別な処理が必要であるが、 simple_function は普通のpythonの処理でよい。

Keras APIs - three programming models (p.63)

Sequential API (p.63)

直観的で簡潔に記述でき、90%のケースに当てはまる。 前の章でMNISTのコードをSequential APIで記述した。

Functional API (p.64)

複雑な(=線形でない)モデルを記述するのに適している。 各layerはcallableで、出力としてtensorを返す。

2つの入力を持ち、中間layerは共有して、2つの分離したロジスティック回帰を出力する例を考える。

Model subclassing (p.66)

高いフレキシビリティを提供していて、自分自身の新しいlayerを定義するときに使う。 複雑なので、本当に必要な時にだけ使うようにすべき。

tf.keras.layers.Layer のサブクラスとして定義して、以下のメソッドを実装する。

入力に、kernel と呼ばれる行列を乗算するカスタムlayerの例(省略版) p.67 は省略する

Callbacks

Callback は、trainingの最中にモデルに渡されて拡張したり振る舞いを変更したりするためのオブジェクトである。 tf.keras で使われる有用な callback がいくつか存在する。

    callbacks = [ tf.keras.callbacks.TensorBoard(log_dir='./logs')]
    model.fit(data, labels, batch_size=256, epochs=100, callbacks=callbacks, validation_data=(val_data,val_labels)

Saving a model and weights

modelをtrainingした後で、重みを保存するには次のようにすればよい。

# save weights to a tensorflow checkpoint
model.save_weights('./weights/my_model')

# save weights to HDF5
mode.save_weights('my_model.h5', save_format='h5')

重みを読み込む。

model.load_weights(file_path)

modelをserializedできる

[JSON形式で]
  json_string = model.to_json()  # save
  model = tf.keras.models.model_from_json(json_string) # restore
[YAML形式で]
  yaml_string = model.to_yaml() # save
  model = tf.keras.models.model_from_yaml(yaml_string) # restore

model を weights や最適化されたパラメータとともに保存する。

model.save('my_model.h5') # save
model = tf.keras.models.load_model('my_model.h5') # restore

Training from tf.data.datasets

TensorFlow 2.x では いろいろな分野の dataset が使えることが利点である。

pip install tensorflow-datasets

dataset は入力をある方法に基づいて扱うライブラリである。次の命令を含んでいる。

  1. Creation
    1. from_tensor_slices() ... 一つまたは複数のNumPyのtensorを受け付ける。batchをサポートしている。
    2. from_tensors() ... 上と似ているが batchをサポートしていない。
    3. from_generator() ... generator関数からの入力を受け付ける。
  2. Transformation
    1. batch() ... datasetを指定されたサイズで分割する。
    2. repeat() ... データを複製する
    3. shuffle() ... 順番をランダムに並べ替える
    4. map() ... データに関数を適用する。
    5. filter() ... データをフィルタに通すために、関数を適用する。
  3. Iteration
    1. next_batch = iterator.get_next()

tf.keras or Estimators?

直接のグラフ計算や、tf.keras の高レベル API に加えて、Estimators と呼ばれる高レベルの API が TensorFlow 1.x にも 2.x にもある。 Emulatorsとは大規模な production-ready 環境のための非常に効率的なモデルである。

    
# 10 unit の完全結合隠れlayerが2層、出力層が3クラスのclassifier
classifier = tf.estimator.DNNClassifier(
    feature_columns = my_feature_columns,
    hidden_units=[10,10],
    n_classes = 3
)
my_feature_columns = []
for key in train_x.keys():
    my_feature_columns.append(tf.feature_column.numeric_column(key=key))

tf.feature_column.numeric_column() は数値化された features である。 効率的な Estimators は tf.Datasets を入力として訓練すべきだ。 下は MNIST の例である。

Estimator は tf.estimator.train_and_evaluate() でtrain and evaluatedされる。

tf.estimator.train_and_evaluate(
    classifier, 
    train_spec=tf.estimator.TrainSpec(input_fn=input_fn),
    eval_spec=tf.estimateor.EvalSpec(input_fn=input_fn)
    )

TensorFlow 2.x では、すでに導入しているのならばEstimator を使いつづけてもよいが、その他の場合はtf.keras を使ったほうがよい。

Ragged tensors (p.74) ぼろぼろのテンソル

TensorFlow 2.x では "ragged" tensors のサポートが追加された。 ragged tensor とは、サイズが統一されていないdense tensorのことである。

ragged = tf.ragged.constant([[1,2,3],[3,4],[5,6,7,8]]

Custom training (p.74)

TensorFlow は自動微分により勾配を計算してくれるので、modelを開発するのがとても簡単である。 tf.keras.fit()を使うと詳細を気にすることなく training できる。

しかし、最適化を制御しよとするときには自分だけのカスタムな training が必要になることもある。 勾配を計算する方法はいろいろある。

  1. tf.GradientTape()
  2. tf.gradient_function()
  3. tf.value_and_gradients_function()
  4. tf.implicit_gradients()
@tf.function
def train_step(inputs, labels):
    with tf.GradientTape() as tape:
        predictions = model(inputs, training=True)
        regularization_loss = // TBD according to the problem
        pred_loss = // TBD according to the problem
        total_loss = pred_loss + regularization_loss
    gradients = tape.gradient(total_loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

for epoch in range(NUM_EPOCHS):
    for inputs, labels in train_data:
        train_step(inputs, labels)
    print("Finished epoch", epoch)

Distributed training in TensorFlow 2.x (p.76)

Multiple GPUs (p.76)

MultiWorkerMirroredStrategy (p.78)

TPUStrategy (p.78)

ParameterServerStragegy (p.78)

Changes in namespaces (p.79)

Converting from 1.x to 2.x (p.80)

Using TensorFlow 2.x effectively (p.80)

  1. tf.kerasのような高レベルAPIをデフォルトとし、特別な操作が必要でないならばdirect computational graph 低レベルなAPIは使わないこと。すなわち、tf.Session, tf.Session.run は使わない。/li>
  2. AutoGraph によって効率的に動作するように @tf.function decorator を付加すること。
  3. 変数や損失を追跡するのに Python オブジェクトを使うこと。tf.get_variable の代わりに tf.Variable を使うこと。こうすると普通のPythonのスコープで変数が扱われる。
  4. データの入力にはtf.data dataset を用いて、それらのオブジェクトを直接tf.keras.Model.fitに渡すこと。データを効率良く扱うことができるので。
  5. Sequential, Functional, SubclassingのどのAPIを使うにせよ、できるだけtf.layersモジュールを使うこと。既存のモデルを使う場合は、GPUによる高速化が可能なのでEstimatorsを使くこと。
  6. GPUやCPU, 複数のサーバを使って分散処理を試みよ。tf.keras を使うと容易にできる。

The TensorFlow 2.x ecosystem (p.81)

Language bindings (p.82)

Keras or tf.keras? (p.83)

Summary (p.84)