关于使用Tensorflow 2进行Fashion Mnist数据集识别提出的八个问题
本篇文章是参考了Andrew Ng与Laurence Moroney的Tensorflow 2.0课程而作的,其中加入了本人一些浅显的理解,拾人牙慧,实属惭愧。
我们考虑使用神经网络解决一些计算机视觉方面的问题,下面通过一个例子----不同服饰种类的识别来进行关于神经网络一些问题的探究。
一、全连接层神经网络(DNN)的建立
导入第三方库,并查看Tensorflow版本,确保使用2.0以上版本,如果版本过低,建议先进行新版本的安装再进行下面的学习。
import tensorflow as tf
print(tf.__version__)
Fahion Mnist 数据集已经封装在tf.keras.datasets 当中,在使用时,我们只需要载入即可。
mnist = tf.keras.datasets.fashion_mnist
load_data 命令将整个数据集分成两部分,一部分作为训练数据,另一部分作为测试数据。
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
数据集当中的数据具体是什么呢,我们接下来通过输出结果观察一下。
import matplotlib.pyplot as plt
plt.imshow(training_images[0])
print(training_labels[0])
print(training_images[0])
展示出训练集第一张图片的图片数据信息,标签以及在画布上的该图片。
9
[[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 13 73 0
0 1 4 0 0 0 0 1 1 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 3 0 36 136 127 62
54 0 0 0 1 3 4 0 0 3]
[ 0 0 0 0 0 0 0 0 0 0 0 0 6 0 102 204 176 134
144 123 23 0 0 0 0 12 10 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 155 236 207 178
107 156 161 109 64 23 77 130 72 15]
[ 0 0 0 0 0 0 0 0 0 0 0 1 0 69 207 223 218 216
216 163 127 121 122 146 141 88 172 66]
[ 0 0 0 0 0 0 0 0 0 1 1 1 0 200 232 232 233 229
223 223 215 213 164 127 123 196 229 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 183 225 216 223 228
235 227 224 222 224 221 223 245 173 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 193 228 218 213 198
180 212 210 211 213 223 220 243 202 0]
[ 0 0 0 0 0 0 0 0 0 1 3 0 12 219 220 212 218 192
169 227 208 218 224 212 226 197 209 52]
[ 0 0 0 0 0 0 0 0 0 0 6 0 99 244 222 220 218 203
198 221 215 213 222 220 245 119 167 56]
[ 0 0 0 0 0 0 0 0 0 4 0 0 55 236 228 230 228 240
232 213 218 223 234 217 217 209 92 0]
[ 0 0 1 4 6 7 2 0 0 0 0 0 237 226 217 223 222 219
222 221 216 223 229 215 218 255 77 0]
[ 0 3 0 0 0 0 0 0 0 62 145 204 228 207 213 221 218 208
211 218 224 223 219 215 224 244 159 0]
[ 0 0 0 0 18 44 82 107 189 228 220 222 217 226 200 205 211 230
224 234 176 188 250 248 233 238 215 0]
[ 0 57 187 208 224 221 224 208 204 214 208 209 200 159 245 193 206 223
255 255 221 234 221 211 220 232 246 0]
[ 3 202 228 224 221 211 211 214 205 205 205 220 240 80 150 255 229 221
188 154 191 210 204 209 222 228 225 0]
[ 98 233 198 210 222 229 229 234 249 220 194 215 217 241 65 73 106 117
168 219 221 215 217 223 223 224 229 29]
[ 75 204 212 204 193 205 211 225 216 185 197 206 198 213 240 195 227 245
239 223 218 212 209 222 220 221 230 67]
[ 48 203 183 194 213 197 185 190 194 192 202 214 219 221 220 236 225 216
199 206 186 181 177 172 181 205 206 115]
[ 0 122 219 193 179 171 183 196 204 210 213 207 211 210 200 196 194 191
195 191 198 192 176 156 167 177 210 92]
[ 0 0 74 189 212 191 175 172 175 181 185 188 189 188 193 198 204 209
210 210 211 188 188 194 192 216 170 0]
[ 2 0 0 0 66 200 222 237 239 242 246 243 244 221 220 193 191 179
182 182 181 176 166 168 99 58 0 0]
[ 0 0 0 0 0 0 0 40 61 44 72 41 35 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0]]
标签为9,从画布上展示的图片大概可以看出训练集第一个图片为踝靴,我们也知道标签9代表的就是踝靴。
然后我们展示不同种类的服饰,发现这些服饰各异,有上衣下装,也包含着鞋靴等。
plt.figure(figsize=(10,10))
for i in range(1,17):
plt.subplot(4,4,i)
plt.imshow(training_images[i])
从上面输出的图片数据可知,每个图片数据矩阵当中的数值均处于0到255之间,我们想到如果所有数据均在0到1之间,那么我们的神经网络训练将会非常好,但是这也并不困难,我们只需对其进行标准化,所有数据均除以255即可。
training_images = training_images / 255.0
test_images = test_images / 255.0
这里需要注意的是不仅训练集要进行标准化,对测试集也同样需要进行标准化。
接下来进行模型的建立
model = tf.keras.models.Sequential([tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation=tf.nn.relu),
tf.keras.layers.Dense(10,activation=tf.nn.softmax)
])
- Sequential:定义了神经网络当中层的一种顺序结构。
- Flatten: 从开始对训练数据集中图片的输出可知,图片数据均是二维的,Flatten的作用即是将数据转变为一维数据
- Dense: 添加一层全连接层的神经网络。
每一层网络均需要一个激活函数(均是非线性的函数),有许多可供选择,这里暂时不做讨论。 - Relu :意味着当
x
>
0
x>0
x>0时,返回
x
x
x,当
x
<
0
x<0
x<0时,返回
0
0
0。这意味着这有0和大于0的数会进入到下一层神经网络当中。
- Softmax :在一系列数据当中选择最大的。例如,我们的输出层得到[0.1, 0.1, 0.05, 0.1, 9.5, 0.1, 0.05, 0.05, 0.05],它将选取数据当中最大值,而不需人为地再去观察,将该列表数据即转换为 [0,0,0,0,1,0,0,0,0] ,
softmax 适用于多分类问题。
下面进行模型的编译(compile)与训练(fit),优化方法采用adam ,损失函数选用交叉熵,评判指标选用accuracy .
使用训练集中的数据对模型训练五次。
model.compile(optimizer = 'adam',
loss = 'sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(training_images, training_labels, epochs=5)
结果如下,发现在训练到第五次的时候精度已经到达了0.8266,这说明该神经网络模型在匹配其图片与其对应标签中,有82.66%的概率匹配正确。
Epoch 1/5
1875/1875 [==============================] - 1s 770us/step - loss: 2.9202 - accuracy: 0.7058
Epoch 2/5
1875/1875 [==============================] - 2s 860us/step - loss: 0.6286 - accuracy: 0.7741
Epoch 3/5
1875/1875 [==============================] - 1s 785us/step - loss: 0.5599 - accuracy: 0.8029
Epoch 4/5
1875/1875 [==============================] - 1s 762us/step - loss: 0.5229 - accuracy: 0.8216
Epoch 5/5
1875/1875 [==============================] - 1s 750us/step - loss: 0.5170 - accuracy: 0.8266
接下来来看一下模型对陌生数据预测结果如何,使用测试集对模型进行评估,输入两个数据集,包括测试图片集与测试图片集的标签,得到损失值与精度。
model.evaluate(test_images, test_labels)
结果如下所示,精度达到了0.8260,说明在一定程度上模型具有一定的识别能力。
313/313 [==============================] - 0s 618us/step - loss: 0.5208 - accuracy: 0.8260
[0.5207503437995911, 0.8259999752044678]
二、八个问题
1.模型预测结果的探究
使用model.predict() 得到模型对测试图片的预测结果。
classifications = model.predict(test_images)
print(classifications[0])
[7.9142317e-18 9.2104990e-15 3.4202259e-35 1.5384416e-16 1.3053542e-24 2.7295727e-02 8.0706191e-29 3.7396610e-02 1.4129637e-11 9.3530768e-01]
我们得到了一组这样的数据,但我们思考,得到结果的一系列数字究竟有何含义? 我们尝试运行下列代码,发现
print(test_labels[0])
print(np.argmax(classifications[0]))
发现输出结果均为7,model.predict() 得到的预测结果意味着什么,我们有以下猜测:
- 输出结果是10个没有任何意义的值。
- 输出结果是10个计算机制作的10个不同种类。
- 输出结果为10个不同服饰种类的可能性。
显然答案便是第3个,输出的结果恰为10个不同服饰种类的概率。
怎样通过输出列表当中的值知道预测结果?我们有以下的猜测:
- 没有足够的信息回答这一个问题
- 哪一个元素最大,则预测结果为该元素位置
- 有几个元素则预测结果为多少
正确答案显然为2,在每个位置上的数据代表着是否为该结果概率,数值越大的也就意味着是该结果的可能性越大。
2.神经元的数量的影响
下面来观察一下将神经网络当中第一层神经元数量改为1024个,输出的损失值大小以及耗费的时间。
import tensorflow as tf
print(tf.__version__)
mnist = tf.keras.datasets.mnist
(training_images, training_labels) , (test_images, test_labels) = mnist.load_data()
training_images = training_images/255.0
test_images = test_images/255.0
model = tf.keras.models.Sequential([tf.keras.layers.Flatten(),
tf.keras.layers.Dense(1024, activation=tf.nn.relu),
tf.keras.layers.Dense(10, activation=tf.nn.softmax)])
model.compile(optimizer = 'adam',
loss = 'sparse_categorical_crossentropy')
model.fit(training_images, training_labels, epochs=5)
model.evaluate(test_images, test_labels)
classifications = model.predict(test_images)
print(classifications[0])
print(test_labels[0])
输出结果如下:
2.3.0
Epoch 1/5
1875/1875 [==============================] - 10s 5ms/step - loss: 0.1832
Epoch 2/5
1875/1875 [==============================] - 10s 5ms/step - loss: 0.0755
Epoch 3/5
1875/1875 [==============================] - 9s 5ms/step - loss: 0.0477
Epoch 4/5
1875/1875 [==============================] - 9s 5ms/step - loss: 0.0353
Epoch 5/5
1875/1875 [==============================] - 9s 5ms/step - loss: 0.0255
313/313 [==============================] - 0s 1ms/step - loss: 0.0711
[2.17035829e-08 6.24947845e-08 1.41845042e-08 1.13515984e-04
1.89369367e-10 5.86703264e-09 5.19989087e-11 9.99870062e-01
8.58290718e-07 1.54760037e-05]
7
问题1:将神经元个数增加到1024个产生的影响?我们作出了如下的猜想。
- 时间变长,精度变高
- 时间变长,精度相同
- 时间不变,精度变高
正确答案为1,通过增加神经元个数我们做了更多的运算,减缓了训练过程,但我们也获得了更好的影响,得到了更高的精确度,但这并不意味着训练次数越多越好,这也需要在一定程度上合理选择。
3.删除展平层(Flatten)
import tensorflow as tf
print(tf.__version__)
mnist = tf.keras.datasets.mnist
(training_images, training_labels),(test_images, test_labels) = mnist.load_data()
training_images = training_images/255.0
test_images = test_images/255.0
model = tf.keras.models.Sequential([
tf.keras.layers.Dense(64, activation=tf.nn.relu),
tf.keras.layers.Dense(10, activation=tf.nn.softmax)])
model.compile(optimizer = 'adam',
loss = 'sparse_categorical_crossentropy')
model.fit(training_images, training_labels, epochs=5)
model.evaluate(test_images, test_labels)
classifications = model.predict(test_images)
print(classifications[0])
print(test_labels[0])
我们发现将会报错,说明展平层的存在是必要的,但是原因我们却是不明确的。现在我们数据集每一张图片都是2828形状的,所以要想进行神经网络的建立需要28层28个神经元的神经网络,所以我们将其展平为7841形状的数据更有意义。
4.输出层神经元的个数
考虑输出层神经元的个数,为什么一定要是10个,如果我们将其改为5个会发生什么呢?
import tensorflow as tf
print(tf.__version__)
mnist = tf.keras.datasets.mnist
(training_images, training_labels) , (test_images, test_labels) = mnist.load_data()
training_images = training_images/255.0
test_images = test_images/255.0
model = tf.keras.models.Sequential([tf.keras.layers.Flatten(),
tf.keras.layers.Dense(64, activation=tf.nn.relu),
tf.keras.layers.Dense(5, activation=tf.nn.softmax)])
model.compile(optimizer = 'adam',
loss = 'sparse_categorical_crossentropy')
model.fit(training_images, training_labels, epochs=5)
model.evaluate(test_images, test_labels)
classifications = model.predict(test_images)
print(classifications[0])
print(test_labels[0])
同样的,程序将会报错,所以这引出第二个原则----最后一层神经元个数一定要等于分类的种类数量。
5.增加隐藏层
考虑增加一层神经网络层对结果影响,在512个神经元的层与10个神经元的输出层当中插入一层包括256个神经元的层。
import tensorflow as tf
print(tf.__version__)
mnist = tf.keras.datasets.mnist
(training_images, training_labels) , (test_images, test_labels) = mnist.load_data()
training_images = training_images/255.0
test_images = test_images/255.0
model = tf.keras.models.Sequential([tf.keras.layers.Flatten(),
tf.keras.layers.Dense(512, activation=tf.nn.relu),
tf.keras.layers.Dense(256, activation=tf.nn.relu),
tf.keras.layers.Dense(10, activation=tf.nn.softmax)])
model.compile(optimizer = 'adam',
loss = 'sparse_categorical_crossentropy')
model.fit(training_images, training_labels, epochs=5)
model.evaluate(test_images, test_labels)
classifications = model.predict(test_images)
print(classifications[0])
print(test_labels[0])
输出结果如下:
2.3.0
Epoch 1/5
1875/1875 [==============================] - 5s 3ms/step - loss: 0.1825
Epoch 2/5
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0773
Epoch 3/5
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0553
Epoch 4/5
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0410
Epoch 5/5
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0306
313/313 [==============================] - 0s 955us/step - loss: 0.0757
[1.1087765e-11 1.7926065e-07 5.5143340e-07 3.6257799e-08 8.3221478e-11
1.4963332e-08 6.8053222e-14 9.9999893e-01 3.5755072e-09 2.3824717e-07]
7
我们看不出增添一层神经网络隐藏层对我们结果产生了什么影响,这是因为我们使用的就是普通的数据,例如带有多种颜色的图片,增添神经网络层往往是很有必要的。
6.改变模型训练次数
考虑如果我们使用更多或者更少的训练次数,我们将得到什么结果呢?
import tensorflow as tf
print(tf.__version__)
mnist = tf.keras.datasets.mnist
(training_images, training_labels) , (test_images, test_labels) = mnist.load_data()
training_images = training_images/255.0
test_images = test_images/255.0
model = tf.keras.models.Sequential([tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation=tf.nn.relu),
tf.keras.layers.Dense(10, activation=tf.nn.softmax)])
model.compile(optimizer = 'adam',
loss = 'sparse_categorical_crossentropy')
model.fit(training_images, training_labels, epochs=30)
model.evaluate(test_images, test_labels)
classifications = model.predict(test_images)
print(classifications[34])
print(test_labels[34])
训练次数改为15次,我们发现训练结果更加精确,损失值变得更小。 训练次数改为30次时,我们发现训练后期损失值变得忽大忽小,这就是因为数据产生了过拟合的结果,在以后的神经网络训练当中,我们需要极力避免这种现象的发生。
7.标准化(Normalization)
在训练一开始,我们对数据进行了标准化,将大小在0到255之间的数据都转化成了0到1之间的数据。所以我们考虑取消这一操作对结果有何影响。
import tensorflow as tf
print(tf.__version__)
mnist = tf.keras.datasets.mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images
test_images=test_images
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(512, activation=tf.nn.relu),
tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')
model.fit(training_images, training_labels, epochs=5)
model.evaluate(test_images, test_labels)
classifications = model.predict(test_images)
print(classifications[0])
print(test_labels[0])
输出结果如下:
2.3.0
Epoch 1/5
1875/1875 [==============================] - 5s 3ms/step - loss: 2.7173
Epoch 2/5
1875/1875 [==============================] - 5s 3ms/step - loss: 0.3359
Epoch 3/5
1875/1875 [==============================] - 5s 2ms/step - loss: 0.3222
Epoch 4/5
1875/1875 [==============================] - 4s 2ms/step - loss: 0.2772
Epoch 5/5
1875/1875 [==============================] - 4s 2ms/step - loss: 0.2551
313/313 [==============================] - 0s 765us/step - loss: 0.2600
[0.0000000e+00 3.7754320e-21 3.5940075e-12 4.2507407e-24 6.5570809e-32
1.1645400e-27 0.0000000e+00 1.0000000e+00 9.0640749e-23 4.9115202e-22]
7
8.回调函数(Callbacks)
在实际操作当中,我们发现随着训练次数的增加,损失值,精确度都会随之改变,在一些情况下,这并不会得到更好的效果,一般而言,95%的精确度就是一个比较不错的标准,如果我们在训练三次就得到该精度,后面的训练便不太有意义,我们可以采用什么办法让训练停下来呢?我们接下来考虑使用callbacks
示例: 下面代码实现了在损失值小于0.4时终止模型的功能。
import tensorflow as tf
print(tf.__version__)
class myCallback(tf.keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs={}):
if(logs.get('loss')<0.4):
print("\nReached 60% accuracy so cancelling training!")
self.model.stop_training = True
callbacks = myCallback()
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images/255.0
test_images=test_images/255.0
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(512, activation=tf.nn.relu),
tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')
model.fit(training_images, training_labels, epochs=5, callbacks=[callbacks])
输出结果如下:
2.3.0
Epoch 1/5
1875/1875 [==============================] - 4s 2ms/step - loss: 0.4719
Epoch 2/5
1866/1875 [============================>.] - ETA: 0s - loss: 0.3576
Reached 60% accuracy so cancelling training!
1875/1875 [==============================] - 4s 2ms/step - loss: 0.3577
|