Kaggle Coursesの解説（Computer Vision - The Convolutional Classifier）

#はじめに
KaggleのCoursesを使って勉強している筆者が、Courseで提供されるコードを解説をしながら学んだことをメモしました。  
本記事では以下のコースを解説します。
[Kaggle Couses:  Computer Vision - The Convolutional Classifier](https://www.kaggle.com/learn/computer-vision)  



＊Kaggle Coursesは手軽に機械学習を勉強できます。計算環境、データすべて提供されており、非常に勉強しやすいです。


#コード解説(Introduction)
このコースのチュートリアルではVGG16という学習済みモデルを使用した結果、過学習になってしまうことがわかりました。そこで、今回はInceptionV1(GoogLeNet)という学習済みモデルを使って精度向上を図ります。
まずは以下の要領で環境とデータを用意します。

```python
# Setup feedback system
from learntools.core import binder
binder.bind(globals())
from learntools.computer_vision.ex1 import *

# Imports
import os, warnings
import matplotlib.pyplot as plt
from matplotlib import gridspec

import numpy as np
import tensorflow as tf
from tensorflow.keras.preprocessing import image_dataset_from_directory
```

```python:
# Reproducability
def set_seed(seed=31415):
    np.random.seed(seed)
    tf.random.set_seed(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)
    os.environ['TF_DETERMINISTIC_OPS'] = '1'
set_seed()
```

乱数を固定して再現性があるようにします。
numpyとtensorflowだけでなく、OSの環境変数も設定することで、やっと乱数が固定できるようです。

```python
# Set Matplotlib defaults
plt.rc('figure', autolayout=True)
plt.rc('axes', labelweight='bold', labelsize='large',
       titleweight='bold', titlesize=18, titlepad=10)
plt.rc('image', cmap='magma')
warnings.filterwarnings("ignore") # to clean up output cells

# Load training and validation sets
ds_train_ = image_dataset_from_directory(
    '../input/car-or-truck/train',
    labels='inferred',
    label_mode='binary',
    image_size=[128, 128],
    interpolation='nearest',
    batch_size=64,
    shuffle=True,
)
ds_valid_ = image_dataset_from_directory(
    '../input/car-or-truck/valid',
    labels='inferred',
    label_mode='binary',
    image_size=[128, 128],
    interpolation='nearest',
    batch_size=64,
    shuffle=False,
)
```
image_dataset_rfrom_directoryはディレクトリの中にある画像ファイルのリンクをラベル付きで取得します。
今回の場合は、./input/train/の下に、./Car, ./Truckがあり、それぞれ複数枚の画像が入っています。Carフォルダの画像には0, Truckフォルダの画像には1をラベリングしています。
[参考](https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/image_dataset_from_directory?hl=ja)

```python
# Data Pipeline
def convert_to_float(image, label):
    image = tf.image.convert_image_dtype(image, dtype=tf.float32)
    return image, label

AUTOTUNE = tf.data.experimental.AUTOTUNE
ds_train = (
    ds_train_
    .map(convert_to_float)
    .cache()
    .prefetch(buffer_size=AUTOTUNE)
)
ds_valid = (
    ds_valid_
    .map(convert_to_float)
    .cache()
    .prefetch(buffer_size=AUTOTUNE)
)
```

```python:
import tensorflow_hub as hub

pretrained_base = tf.keras.models.load_model(
    '../input/cv-course-models/cv-course-models/inceptionv1'
)
```
[TensorFlowHub](https://www.tensorflow.org/hub/)から学習済みモデルを読み込み。（今回はKaggleが用意してくれたローカルフォルダから読み込み
）

#コード解説（1. Define Pretrained Base）

```python
# YOUR_CODE_HERE
pretrained_base.trainable = False
```

ロードした学習済みモデルをそのまま使うために、学習不可に設定する。

#コード解説（2. Attach Head）


```python
from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    pretrained_base,
    layers.Flatten(),
    # YOUR CODE HERE. Attach a head of dense layers.
    layers.Dense(units=6,activation='relu'),
    layers.Dense(units=1,activation='sigmoid')
])
```

keras.Sequentialでモデルを構築する。今回は学習済みモデルに対して"Head"を追加する。"Head"とは計算された特徴量に対してラベルを当てはめるレイヤーのこと。
---流れ---
画像
↓
Base: 特徴量の計算（今回の場合は学習済みモデルであるInceptionV1）
↓
Head: ラベルを当てはめる(今回の場合は最後の付け足した2つのDenseレイヤー)  

#コード解説（3. Train）

```python
# YOUR CODE HERE: what loss function should you use for a binary
# classification problem? (Your answer for each should be a string.)
optimizer = tf.keras.optimizers.Adam(epsilon=0.01)
model.compile(
    optimizer=optimizer,
    loss = 'binary_crossentropy',
    metrics=['binary_accuracy'],
)
```
optimizer(最適化アルゴリズム) : Adam
loss(損失関数)：binary_crossentropy
metrics(評価関数)： binary_accuracy

Adamの引数epsilonの意味は”A small constant for numerical stability"と書いてあります。[参考](https://keras.io/api/optimizers/adam/)

アルゴリズムは以下が詳しい。
[【決定版】スーパーわかりやすい最適化アルゴリズム](https://qiita.com/omiita/items/1735c1d048fe5f611f80#%E6%B1%BA%E5%AE%9A%E7%89%88%E3%82%B9%E3%83%BC%E3%83%91%E3%83%BC%E3%82%8F%E3%81%8B%E3%82%8A%E3%82%84%E3%81%99%E3%81%84%E6%9C%80%E9%81%A9%E5%8C%96%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0)
ものすごくわかりやすい。勉強になります。


```python
history = model.fit(
    ds_train,
    validation_data=ds_valid,
    epochs=30,
)
```

学習

```python
import pandas as pd
f,axes = plt.subplots(1,2,figsize=(10,5))
history_frame = pd.DataFrame(history.history)
history_frame.loc[:, ['loss', 'val_loss']].plot(ax = axes[0])
history_frame.loc[:, ['binary_accuracy', 'val_binary_accuracy']].plot(ax = axes[1]);
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253582/d4f9dd7d-b121-e94a-d53c-eeb90b140e89.png)

結果の解釈
チュートリアルのVGG16と異なり、訓練データの損失関数減少に伴い評価データの損失関数も減少しているため、過学習には陥っていない。epoch数を増やすなり、モデルを複雑化することでもう少し精度を上げられるかも。