# Chapter 2: TensorFlow 1.x and 2.x¶

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

## 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
• Functional API
• Model Subclassing

### Functional API (p.64)¶

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

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

• __init__ ... constructor
• build ... layerのweightを作成する。add_weight()
• call ... forward pass
• get_config (optional) ... serialize
• from_config (optional) ... deserialize

## Callbacks¶

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

• tf.keras.callbacks.ModelCheckpoint ... チェックポイントに状態を保存する
• tf.keras.callbacks.LearningRateScheduler ... learning rate を動的に変更する
• tf.keras.callbacks.EarlyStopping ... 検証結果の改善が止まったら、trainingを止める
• tf.keras.callbacks.TensorBoard ... モデルの振る舞いをモニターする。
    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


## 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?¶


# 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):
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

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


## 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 を使うと容易にできる。