「ゼロから作るDeep Learning」自習メモ（その１５） TensorFlowの初心者向けチュートリアル

「ゼロから作るDeep Learning」(斎藤 康毅　著　オライリー・ジャパン刊)を読んでいる時に、参照したサイト等をメモしていきます。　[その１４](https://qiita.com/slow_learner/items/c422bd3d06c86bf0beec)← →[その１６](https://qiita.com/slow_learner/items/28a8025c9b881491e3be)

Google Colab がふつうに使えるので、この本の内容を TensorFlow でやってみることにします。

##TensorFlow の初心者向けチュートリアル
TensorFlow のサイト　https://www.tensorflow.org/?hl=ja の初心者向けチュートリアル「[はじめてのニューラルネットワーク](https://www.tensorflow.org/tutorials/keras/classification?hl=ja)」をそのまま動かして見ました。

ほんとに、そのまんま Colab にコピペすれば動くので、特にメモすることもありません。
しかし、動くことを確認させるためのものなので、内容についての説明はまったくありません。必要な説明はサイト内のあちこちにあるようですが、初心者はチュートリアルをやったあと、自分が今何をしたのか、次に何をすればよいかがわからず、迷子になってしまいそうです。

と言うか、

おそらくこのサイトはまったくの初心者向けではなく、pythonやニューラルネットについてある程度知っている人が、Google Colab でTensorFlow を使えるようにするためのサイトなんだろうと思います。実際問題、ニューラルネットワークそのものについての解説が見当たらないし。

そういう点では、「ゼロから作るDeep Learning」のように、順番に説明を積み上げていく書籍は必要なんだと思いました。

で

このチュートリアルで実行したスクリプトを、「ゼロから作るDeep Learning」の内容と照らし合わせて、keras および TensorFlow が何をしているかを調べていこうと思います。
##モデルの構築
```python
model = keras.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(128, activation='relu'),
    keras.layers.Dense(10, activation='softmax')
])
```
ここでは、[keras のシーケンシャルモデル](https://www.tensorflow.org/guide/keras/sequential_model?hl=ja)を構築しています。

```python
type(model)
```
>tensorflow.python.keras.engine.sequential.Sequential

```python
model.summary()
```
>Model: "sequential"
Layer (type)      　　　　　 Output Shape 　　　　　   Param #   
_________________________________________________________________
flatten (Flatten)　　　　　  (None, 784)  　　　　　   0         
dense (Dense)     　　　　　 (None, 128)     　　　　　100480    
dense_1 (Dense)    　　　　　(None, 10)      　　　　　1290      
_________________________________________________________________
Total params: 101,770
Trainable params: 101,770
Non-trainable params: 0

入力層からのoutput( , 784)は
次のdense層で (784, 128)　の重みとドット積され、( , 128)をoutputする
それを次のdense-1層で(128, 10)の重みとドット積し、( , 10)をoutputしている。

```
model.layers
```
>[tensorflow.python.keras.layers.core.Flatten at 0x7faf1e9efac8,
 tensorflow.python.keras.layers.core.Dense at 0x7faeea73b438,
 tensorflow.python.keras.layers.core.Dense at 0x7faeea73b710]

モジュール tensorflow.python.keras.engine.sequential.py で定義してあるSequentialクラスでモデルを構築。
最初の層は入力層で、「(28×28ピクセルの）2次元配列から、28×28＝784ピクセルの、1次元配列に変換」しているだけのようです。

>ピクセルが１次元化されたあと、ネットワークは2つの tf.keras.layers.Dense 層となります。これらの層は、密結合あるいは全結合されたニューロンの層となります。最初の Dense 層には、128個のノード（あるはニューロン）があります。最後の層でもある2番めの層は、10ノードのsoftmax層です。この層は、合計が1になる10個の確率の配列を返します。それぞれのノードは、今見ている画像が10個のクラスのひとつひとつに属する確率を出力します。

と言う事なので、書籍「ゼロから作るDeep Learning」のP113 から説明されている 2 層ニューラルネットワーククラス TwoLayerNet に相当するようです。
ただ、TwoLayerNet クラスの活性化関数はsigmoid関数でしたが、このkeras のシーケンシャルモデルではRelu関数を指定しています。

Dense 「密集した、(…で)密集して、密度が高い」という意味から、全結合層のことのようです。

>「ゼロから作るDeep Learning」P205
隣接する層のすべてのニューロン間で結合がありました。これを全結合（fully-connected）と呼び、私たちは全結合層をAffine レイヤという名前で実装しました。

に相当するようです。

###denseのパラメータ
units,                    出力の次元数
activation=None,          使用する活性化関数（未指定なら活性化関数は使用しない）
use_bias=True,            バイアスを使用するかどうか
kernel_initializer='glorot_uniform',  重みの初期値
bias_initializer='zeros',  バイアスの初期値
kernel_regularizer=None,   重み行列に適用される正則化関数
bias_regularizer=None,     バイアスに適用される正則化関数
activity_regularizer=None, レイヤーの出力（アクティベーション）に適用される正則化関数
kernel_constraint=None,    制約関数
bias_constraint=None,      制約関数
**kwargs

####活性化関数
softmax
elu
selu
softplus
softsign
relu
tanh
sigmoid
hard_sigmoid
linear

半分くらいは「ゼロから作るDeep Learning」に説明があったものです。linear はP66の恒等関数のこと。

####重みの初期値
glorot_uniform デフォルト値
    Glorot の一様分布（Xavier の一様分布）による初期化を返します．

>Keras Documentationより
これは limit を sqrt(6 / (fan_in + fan_out)) としたとき [limit, -limit] を範囲とする一様分布と同じです． ここで fan_in は入力ユニット数，fant_out は出力ユニット数です．

glorot_normal
    Glorot の正規分布（Xavier の正規分布と）による初期化を返します
    「ゼロから作るDeep Learning」p182の「Xavier の初期値」
    前層のノードの数がn 個の場合、$\frac{1}{\sqrt n}$ を標準偏差とするガウス分布

he_normal
    He の正規分布による初期化を返します
    「ゼロから作るDeep Learning」p184の「He の初期値」
    前層のノードの数がn 個の場合、$\sqrt\frac{2}{n}$ を標準偏差とするガウス分布

random_normal
    正規分布に従って重みを初期化。
    文字列で指定すると mean=0.0, stddev=0.05, seed=None の設定(標準偏差が0.05のガウス分布)で初期化する。
    パラメータを設定したい場合は以下のように、関数で指定する。
      keras.initializers.RandomNormal(mean=0.0, stddev=0.05, seed=None)

>「ゼロから作るDeep Learning」P184
sigmoid 関数やtanh 関数は左右対称で中央付近が線形関数として見なせるので、
「Xavier の初期値」が適しています。一方、ReLU を用いる場合は、ReLU に特化し
た初期値を用いることが推奨されています。それは、Kaiming He らが推奨する初期
値――その名も「He の初期値」です。


##model.compileメソッドで指定できるパラメータ
```python
model.compile(optimizer='adam', 
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
```
モデルのコンパイルでは、オプティマイザにadam、損失関数に sparse_categorical_crossentropy を指定しています。

optimizer='rmsprop',　最適化　デフォルトは rmsprop
loss=None,　　損失関数　
metrics=None,　評価関数
loss_weights=None,
weighted_metrics=None,
run_eagerly=None,
**kwargs



###最適化　optimizer
SGD
RMSprop
Adagrad
Adadelta
Adam
Adamax
Nadam
TFOptimizer


###損失関数　loss
mean_squared_error
mean_absolute_error
mean_absolute_percentage_error
mean_squared_logarithmic_error
squared_hinge
hinge
categorical_hinge
logcosh
categorical_crossentropy
sparse_categorical_crossentropy
binary_crossentropy
kullback_leibler_divergence
poisson
cosine_proximity

mean～は回帰問題で使う損失関数
～crossentropyは分類問題で使う損失関数で、「ゼロから作るDeep Learning」P89で説明しています。
正解ラベルがone-hot 表現のときはcategorical_crossentropyを使い、
整数の目的値のときはsparse_categorical_crossentropyを使うようです。
binary_crossentropy 二値交差エントロピー 1出力とし，その出力 y∈[0,1]の値が1/2 より大きいか否かでクラス判定をする。



###評価関数 metrics

compileメソッドに書いてあるコメントによると、
>通常、 `metrics = ['accuracy']`を使用します。

ということです。また、

>文字列「accuracy」または「acc」を渡すと、
 使用した損失関数とモデルの出力形状に基づいて、これを `tf.keras.metrics.BinaryAccuracy`、
`tf.keras.metrics.CategoricalAccuracy`、 `tf.keras.metrics.SparseCategoricalAccuracy`
のいずれかに変換します。

ということです。

他に、`metrics = ['mae']` という指定もできるようですが、これは回帰問題用で平均絶対誤差(Mean Absolute Error)を求めるもののようです。
また、ここに損失関数の名前を指定しても、それに合わせて適切な評価関数に変換してくれるようです。

で

>文字列「accuracy」～を ～`tf.keras.metrics.SparseCategoricalAccuracy`のいずれかに変換します。

とあるように、本当は関数そのものを指定するところに、文字列識別子で指定すれば変換してくれる、ということになっているようです。これは最適化や損失関数でも同じです。文字列で指定すれば分かりやすいし、間違うことも少なくなると思いますが、パラメータがデフォルト値になってしまいます。

たとえば、optimizer で 'adam' を指定した場合モジュール tensorflow.python.keras.optimizer_v2.adam.py のクラス Adam を呼び出してますが、以下のパラメータがデフォルトで設定されています。
learning_rate=0.001,
beta_1=0.9,
beta_2=0.999,

>「ゼロから作るDeep Learning」P175
Adam は3 つのハイパーパラメータを設定します。ひとつは、これまでの学習係数（論文ではαとして登場）。後の2 つは、一次モーメント用の係数β1 と二次モーメント用の係数β2 です。論文によると、標準の設定値は、β1 は0.9、β2 は0.999 であり、その設定値であれば、多くの場合うまくいくようです。

ということなので、デフォ値で問題ないようですが、これを変更したい場合は関数を直接指定しないといけなくなります。

```python
model.compile(optimizer=keras.optimizers.Adam(0.001, 0.9, 0.999), 
              loss=keras.losses.SparseCategoricalCrossentropy(),
              metrics=[keras.metrics.SparseCategoricalAccuracy()])
```


##モデルの訓練
```
model.fit(train_images, train_labels, epochs=5)
```

model.fit メソッドで訓練（学習）をします。訓練データの画像とラベルを指定してます。
epochs エポック数を５と指定しています。５回学習を繰り返す、ということで、実際に実行すると、以下のように５行の実行結果が表示されます。

>Epoch 1/5
1875/1875 [==============================] - 2s 1ms/step - loss: 1.5450 - accuracy: 0.6806
Epoch 2/5
1875/1875 [==============================] - 2s 1ms/step - loss: 0.7987 - accuracy: 0.8338
Epoch 3/5
1875/1875 [==============================] - 2s 1ms/step - loss: 0.5804 - accuracy: 0.8666
Epoch 4/5
1875/1875 [==============================] - 2s 1ms/step - loss: 0.4854 - accuracy: 0.8804
Epoch 5/5
1875/1875 [==============================] - 2s 1ms/step - loss: 0.4319 - accuracy: 0.8893
tensorflow.python.keras.callbacks.History at 0x7fd89467f550

fitメソッドのパラメータには、以下のものがあります
x=None,　訓練データ（画像）
y=None,　訓練データ（ラベル）
batch_size=None,　バッチサイズ　１度のバッチで処理するデータ数　デフォルトは32
epochs=1,　学習の回数
verbose=1,　ログ出力の指定 0:出力しない 1、2:出力する
callbacks=None,
validation_split=0.,
validation_data=None,
shuffle=True,
class_weight=None,
sample_weight=None,
initial_epoch=0,
steps_per_epoch=None,
validation_steps=None,
validation_batch_size=None,
validation_freq=1,
max_queue_size=10,
workers=1,
use_multiprocessing=False

訓練データが60000件、バッチサイズのデフォルトが32件なので、
iter_per_epoch イテレーション数 は 60000 ÷ 32 = 1875
1回のエポックで 1875個のバッチ処理（学習）をするとすべての訓練データを見たということになります。
これを５回繰り返しています。

###正解率の評価
```
test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)

print('\nTest accuracy:', test_acc)
```
>313/313 - 0s - loss: 0.3390 - accuracy: 0.8781
Test accuracy: 0.8780999779701233

model.evaluateメソッドのパラメータ

x=None,　テストデータ（画像）
y=None,　テストデータ（ラベル）
batch_size=None,　バッチサイズ　デフォルトは32
verbose=1,　ログ出力の指定 0:出力しない 1、2:出力する
sample_weight=None,
steps=None,
callbacks=None,
max_queue_size=10,
workers=1,
use_multiprocessing=False,
return_dict=False

学習したモデルで、テストデータの損失値と正解率を返す


TensorFlowのサイトでは、パラメータにどういうものがあるか、よくわからないので、こちらのサイトを参考にしました。説明はいまひとつ足りませんが、何を指定できるかがわかります。
→[Keras Documentation](https://keras.io/ja/) 、[Keras API ref](https://keras.io/api/)

　[その１４](https://qiita.com/slow_learner/items/c422bd3d06c86bf0beec)← →[その１６](https://qiita.com/slow_learner/items/28a8025c9b881491e3be)
メモの目次等はこちらから　[読めない用語集](https://qiita.com/slow_learner/items/03eb3367119e98b5a22c)