iT邦幫忙

2021 iThome 鐵人賽

DAY 8
0
AI & Data

30 天在 Colab 嘗試的 30 個影像分類訓練實驗系列 第 8

【8】資料集有沒有事先 shuffle 對訓練所產生的影響

Colab連結

昨天我們介紹了 Shuffle 這支 API 的使用方式,其中特別提到了如果今天資料集本身沒有先打散的話,你後面再做 shuffle 時,如果 batch size 不等於整個資料數量的話,就不是打的非常散,基於此問題,今天我們用 mnist 來實驗若資料沒有事前打亂,單純只靠 shuffle API 是否能有成效?

樣本一,我們使用 tfds 提供的 mnist,要初始化非常簡單。

ds_data, ds_info = tfds.load(
    'mnist',
    shuffle_files=False,
    as_supervised=True,
    with_info=True,
)

train_split, test_split = ds_data['train'], ds_data['test']

fig = tfds.show_examples(train_split, ds_info)
fig.show()

https://ithelp.ithome.com.tw/upload/images/20210922/20107299FsBL6rNOlz.png

由於 tfds 所提供的資料集都已將資料打散了,為了要重現整齊的 mnist,我選擇重新下載 mnist 來處理。

來源

!wget http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz .
!wget http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz .
!wget http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz .
!wget http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz .

我們用 numpy 的 argsort 來排序資料。

idx = np.argsort(train_labels)
train_labels_sorted = train_labels[idx]
train_images_sorted = train_images[idx]

idx = np.argsort(test_labels)
test_labels_sorted = test_labels[idx]
test_images_sorted = test_images[idx]

我們印出 label 前20個元素,可以看到都是0,而圖片也畫出0。

print(test_labels_sorted[:20])
image = np.asarray(test_images_sorted[0]).squeeze()
plt.imshow(image)
plt.show()

https://ithelp.ithome.com.tw/upload/images/20210922/20107299hEz7qPpNmS.png

接著就可以開始我們的實驗,實驗一,正常有打散的 mnist

model = tf.keras.Sequential()
model.add(tf.keras.layers.Conv2D(32, [3, 3], activation='relu', input_shape=(28,28,1)))
model.add(tf.keras.layers.Conv2D(64, [3, 3], activation='relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(tf.keras.layers.Dropout(0.25))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(128, activation='relu'))
model.add(tf.keras.layers.Dropout(0.5))
model.add(tf.keras.layers.Dense(10))

model.compile(
    optimizer=tf.keras.optimizers.SGD(LR),
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=[tf.keras.metrics.SparseCategoricalAccuracy()],
)

history = model.fit(
    ds_train_tf,  # 打散的ds
    epochs=EPOCHS,
    validation_data=ds_test_tf,  # 打散的ds
)

產出:

loss: 0.0473 - sparse_categorical_accuracy: 0.9850 - val_loss: 0.0314 - val_sparse_categorical_accuracy: 0.9901

https://ithelp.ithome.com.tw/upload/images/20210922/20107299cmQSCerWqB.png

看來我們建立的模型對於學習 mnist 錯錯有餘,驗證集的 loss 比訓練值還低,驗證集準確度也上升的比訓練集快,代表模型不用一個 epoch 的時間就能學得很好。

實驗二,label 照順序的 mnist。

model = tf.keras.Sequential()
model.add(tf.keras.layers.Conv2D(32, [3, 3], activation='relu', input_shape=(28,28,1)))
model.add(tf.keras.layers.Conv2D(64, [3, 3], activation='relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(tf.keras.layers.Dropout(0.25))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(128, activation='relu'))
model.add(tf.keras.layers.Dropout(0.5))
model.add(tf.keras.layers.Dense(10))

model.compile(
    optimizer=tf.keras.optimizers.SGD(LR),
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=[tf.keras.metrics.SparseCategoricalAccuracy()],
)

history = model.fit(
    ds_train_m,  # 照順序的ds
    epochs=EPOCHS,
    validation_data=ds_test_m,  # 照順序的s
)

產出:

loss: 0.0631 - sparse_categorical_accuracy: 0.9845 - val_loss: 5.9616 - val_sparse_categorical_accuracy: 0.2695

https://ithelp.ithome.com.tw/upload/images/20210922/20107299BC2qxdslve.png

非常詭異的圖,在第一個 epoch 前,訓練集 accuracy 接近100%,但是驗證集準確度卻非常低,為什麼會這樣子呢?我自己的想像是我訓練模型時,一個 epoch 假設有100個題目,但是前10題答案都是0,後面10題答案都是1,依序下去...

那模型會在前面就被訓練成只要回答0就會對的懶惰模型,中間雖然答案變成1有誘發模型去學習1的特徵,但是回打沒幾題後發現反正答案都是1,又變回懶惰模型,所以整體模型要學會數字1~9的效率會非常差,這也就導致了這次實驗模型學不太起來的窘境,而且即使套用了 shuffle 也沒起色!


上一篇
【7】Dataset 的三個API : Shuffle Batch Repeat 如果使用順序不同會產生的影響
下一篇
【9】各種優化器(Optimizer) 大車拼實驗
系列文
30 天在 Colab 嘗試的 30 個影像分類訓練實驗31

尚未有邦友留言

立即登入留言