初心者でもJKでも大丈夫！TensorFlow公式チュートリアルを解説

# 動機/対象
現在美女たちを機械学習させてみようと思い奮闘中なのですが、scikit-learnのニューラルネットワークライブラリではいまいち満足する結果が得られなかったので、TensorFlowに乗り換えちゃえyo!って感じです。[美女を見分けられい機械はだだの機械だ：OpenCV, Python3による画像からの顔抽出](https://qiita.com/Tatsuro64/items/95b0ce48b6bb155bfe29)
そこでTensorFlowの勉強としてまず、公式チュートリアルをやってみよう！と思いましたが、英語、、、メンドくさい。。。
-> Qiitaに載っているチュートリアルの翻訳を見ながらやればいいんだ！
-> （おそらく）前のバージョンのチュートリアルの解説しか出て来ぬ。。。
-> 仕方ないから英語読むか。

よって対象は私と同じTensorFlowって美味しいの？系初心者です。解説も完全な翻訳ではなく、端折ったり、付け加えている部分があります。

なおTensorFlowのチュートリアルにはいくつか種類があって、BasicClassificationは一番基本のチュートリアルです。本家はこちら。[Train your first neural network: basic classification](https://www.tensorflow.org/tutorials/keras/basic_classification)

# 環境
私はAnaconda + Jupyter Notebookを用いた。JupyterNotebookはインタプリタ形式でトライアンドエラーで進んで行くのにとても捗るので、オススメです。
AnacondaやJupyter Notebookのインストール・使い方についてはググってください。

# 解説
## 0. 必要なモジュールのインポート
このチュートリアルはKerasを用います。KerasはTensorFlowを使い易くするふりかけみたいなものです。

```python
# TensorFlow and tf.keras
import tensorflow as tf
from tensorflow import keras

# Helper libraries
import numpy as np
import matplotlib.pyplot as plt

print(tf.__version__)
````

インポートに失敗した場合はその環境にパッケージがインストールされていないので、pipなどでインストールしてください。

## 1. Fashion MNIST datasetの読み込み
Fashon MNISTという10クラスの服(Tシャツ、コート、スニーカーなど)の画像を70,000点持つデータセットを用います。

![Fashaon-MNIST samples](https://tensorflow.org/images/fashion-mnist-sprite.png "[Train your first neural network: basic classification](https://www.tensorflow.org/tutorials/keras/basic_classification)より拝借
")

```python
fashion_mnist = keras.datasets.fashion_mnist

#train_*は訓練用、test_*はテスト用
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
```

これでデータセットをfashon_mnistに読み込み、さらに60,000点を訓練セットに、10,000点をテストセットに分割します。

ここで、imageデータは28x28のNumpy行列であり、その各値は0~255の整数値に収まっています。labelデータは0~9の整数値に収まっており、それぞれの値が各imageデータがどの服クラスに属するかを表しています。以下のコートで実際にデータの形状、ラベルの値を見てみてください。

```python
print(train_images.shape) #データの形状を出力
print(train_labels.shape)
print(test_images.shape)
print(test_labels.shape)
print(train_labels[0:10]) #最初の10個のラベルをみる
```

服のラベルは以下のように振られています。

|label|class|
|----|----|
|0|T-shirt/top|
|1|Trouser|
|2|Pullover|
|3|Dress|
|4|Coat|
|5|Sandal|
|6|Shirt|
|7|Sneaker|
|8|Bag|
|9|Ankle boot|

このクラス分けを後で使うので、class_namesとして格納します。

```python
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
```

## 2. データの前処理
まずデータを可視化して、その値が0~255に収まっていることを確認しておきましょう。

```python
plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
```
![fig2-1](https://www.tensorflow.org/tutorials/keras/basic_classification_files/output_20_0.png)

モデル構築の前に、(正確な理由はわからないが)imagesデータを整数値から0~1の実数値にスケール変換する必要があります。

```python
train_images = train_images / 255.0
test_images = test_images / 255.0
```

これでOK。

また、以下のコードで最初の25点のデータを可視化して見ることができます。

```python
plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(train_images[i], cmap=plt.cm.binary)
    plt.xlabel(class_names[train_labels[i]])
```
![fig2-1](https://www.tensorflow.org/tutorials/keras/basic_classification_files/output_25_0.png)

## 3. モデル構築
### 3.1 レイヤーをセットアップ
Sequentialモデルはneural networkの層を単純に積み重ねたものです。softmax関数は簡単に言うと、実数値を確率に変換してくれる活性化関数です。

```python
modell = keras.Sequential([
    #入力を2次元から1次元に落としてやる。
    keras.layers.Flatten(input_shape=(28, 28)),
    #ノード数128の隠れ層を作成。活性化関数としてReLuを用いる
    keras.layers.Dense(128, activation=tf.nn.relu),
    #最後の出力は10段階で、それぞれの確率がでるようにする。
    keras.layers.Dense(10, activation=tf.nn.softmax)
])
```

### 3.2 モデルをコンパイル
モデルをコンパイルする際には以下の3つのパラメータを定める必要があります。

・Loss function=損失関数:モデルが最小化しようとする目的関数。既存の定義されている損失関数の識別子を与えるか、関数を自分で定義して与える。

・Optimaizer=最適化アルゴリズム:データや損失関数に基づいて、どのようにモデルが更新されて行くかを決める。

・Metrics=評価関数のリスト：評価関数はモデルの性能を測るために用いる。この評価結果が訓練にフィードバックされることはない。（損失関数との違い）

```python
model.compile(optimizer=tf.train.AdamOptimizer(),
             loss='sparse_categorical_crossentropy',
             metrics=['accuracy'])
```

それぞれのパラメータについての詳細はググって見てください。

### 3.3 モデルを訓練する

```python
model.fit(train_images, train_labels, epochs=5)
```
*epocks: 訓練を何回繰り返すか

## 4. モデルの性能評価
```python
test_loss, test_acc = model.evaluate(test_images, test_labels)
print('Test accuracy:', test_acc)
```

私の場合、
Test accuracy: 0.8721
となった。まぁまぁ良い性能。

## 5. 訓練したモデルで予測
このモデルで同様な画像に対してクラス分類の予測をすることができます。

```python
#testデータのすべての予測をpredictionsに格納
predictions = model.predict(test_images)
#test_images[0]の予測値を表示
print(predictions[0])
```
10列、実数0~1の配列が表示されます。それらはデータがそれぞれのクラスである確率です。その内最大値をとるものが予測クラスとして採用されます。これが本当のtest_labelsと一致していたら正解、一致しなかったらハズレ。

```python
#予測クラス
print(np.argmax(predictions[0]))
#本当のクラス
print(test_labels[0])
```

確率をグラフで可視化することもできます。

```python
# 画像とクラス予測確率を可視化する関数
def plot_image(i, predictions_array, true_label, img):
    predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]
    plt.xticks([])
    plt.yticks([])
    
    plt.imshow(img, cmap=plt.cm.binary)
    
    predicted_label = np.argmax(predictions_array)
    if predicted_label == true_label:
        color = 'blue'
    else:
        color = 'red'
    
    plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
                                         100 * np.max(predictions_array),
                                         class_names[true_label]),
              color=color)

# 0~9の各クラスそれぞれの予測確率を可視化する関数
def plot_value_array(i, predictions_array, true_label):
    predictions_array, true_label = predictions_array[i], true_label[i]
    plt.xticks([])
    plt.yticks([])
    thisplot = plt.bar(range(10), predictions_array, color="#777777")
    plt.ylim([0, 1])
    predicted_label = np.argmax(predictions_array)
    
    thisplot[predicted_label].set_color('red')
    thisplot[true_label].set_color('blue')
```

この2つの関数を用いていくつかのテストデータの予測確率を可視化してみます。正解の場合は青、ハズレの場合は赤で表示されます。

```python
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
  plt.subplot(num_rows, 2*num_cols, 2*i+1)
  plot_image(i, predictions, test_labels, test_images)
  plt.subplot(num_rows, 2*num_cols, 2*i+2)
  plot_value_array(i, predictions, test_labels)
```
![fig4-1](https://www.tensorflow.org/tutorials/keras/basic_classification_files/output_51_0.png)

最後に、一枚の画像を入力として予測します。ここで、tf.kerasは集合（リストなど)に対して予測するように最適化されているので、一枚の画像でもリストに変換する必要があります。

```python
img = test_images[0]
print(img.shape)

#リストに次元を拡張
img = (np.expand_dims(img, 0))
print(img.shape)

# 予測
predictions_single = model.predict(img)
print(predictions_single)

# プロットして可視化
plot_value_array(0, predictions_single, test_labels)
_ = plt.xticks(range(10), class_names, rotation=45)
```