【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 也没起色!


<<:  Day 7 Functions

>>:  Python 语言

jQuery 日历 datepicker

Step 1.add textbox 2.import js 3.bind textbox &...

从零开始的ASP.Net Core 学习

万事起头难 平常的学习方式都是遇到问题才去学、上哪门课学什麽、对哪个主题有兴趣才去学,现在想要有组织...

[DAY 09] ParagraphTextItem

上一篇所说到的textItem 仅能回答一行 若想要出问答题、申论题等 就要使用能回答多行的Para...

[C 语言笔记--Day02] locality

上一篇:[C 语言笔记--Day01] Hello World 大纲 什麽是 memory hier...

Day 28 如何撰写表徵测试

该文章同步发布於:我的部落格 什麽是表徵测试以及解决的问题是什麽? 假如我遇到一段想重构的代码,但...