import tensorflow as tf
print(tf.__version__)
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images.reshape(60000, 28, 28, 1)
training_images=training_images / 255.0
test_images = test_images.reshape(10000, 28, 28, 1)
test_images=test_images/255.0
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(64, (3,3), activation='relu', input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
后面三行跟之前的设置方法一样。
tf.keras.layers.Conv2D(64, (3,3), activation=‘relu’, input_shape=(28, 28, 1))中:
Conv2D()指定第一个卷积,要求keras为我们生成64个过滤器,这些过滤器是3×3的;激活函数是relu,意味着负值会被丢弃;输入形状是28×28,后面额外的1表示用1个字节来计算颜色深度,因为图像是灰度,所以只使用一个字节。这64个过滤器的类定义有点超出了scope的范围,但它们是随机的,它们从一组已知良好的过滤器开始,不断拟合,并且从该组中工作的过滤器会随着时间推移而学习。
tf.keras.layers.MaxPooling2D(2, 2)中:
这一行代码会创建一个池化层,这是极大池化层因为我们要取它的最大值。
接着继续添加一个卷积层和一个极大池化层,使神经网络可以学习到另一组信息。之后再进行池化,减小其大小。当信息扁平化,进入全连接层后,它的信息就已经被压缩得较为精简。
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.summary()
model.fit(training_images, training_labels, epochs=5)
test_loss = model.evaluate(test_images, test_labels)
model.summary()是一个很重要的方法,它能检查模型当中的网络层,查看图片在卷积层被卷积的过程。
注意到output shape(输出大小)这一栏,比如(None, 26, 26, 64),这不是28×28大小的数据,反而输出是26×26,这是因为过滤器是3×3的,当从图片左上角开始卷积,将左上角区域的像素点放大,但最左上角的数据没有相邻的数据,所以不能计算它左边的数据;同样,右边的像素点的上方也没有任何的像素点,所以第一个能做卷积的是不在边缘的像素点,如下图,因为它有着全部八个相邻的像素点。因此输出的把实际的x和y都少了两个像素点。在上下左右四个边界分别移除了一个像素,所以造成了输出大小的改变。
如果过滤器是5×5,那么x、y的输出会更小,都会少4个像素点。
第一个极大池化层的输出形状是(None, 13, 13, 64),池化的方法可以将2×2的像素点变成一个像素点,所以现在我们的输出从26×26减小成了13×13。
接着又是卷积,变成11×11;另一个2×2的极大池化层,使其又变成5×5。
现在,全连接层和之前一样,只不过被5×5的像素点表示了,而不是28×28了。
我们指定的每个图像有很多卷积层,在这里都是64。因此,64个卷积被5×5的像素表示了。
扁平层中(None, 1600),这个1600是因为25个像素乘以64就是1600。所以新的扁平层有1600个元素,扁平层就是将方形矩阵展平变成列向量。这个值和所设置的卷积层参数有关。
总结一下,卷积和池化的方法:我们设置了两个卷积层,每个都有64个卷积,每个层后面都有一个最大池化层。对于每张图片,都尝试了64次卷积,然后将图像压缩,然后又有64个卷积,然后再次压缩,然后通过DNN就可完成任务。不仅速度提高,还可以得到更准确的测试数据和训练数据。
接下来展示卷积过程中图像的变化:
print(test_labels[:100])
首先先打印出前100个测试标签。keras的API给了我们每个卷积、每个池化以及每个密集等作为一层。因此,使用图像api可以看每一层的输出,所以可以创建每个图层输出的列表,然后可以将图层中的每个项目都视为个体激活模型。
import matplotlib.pyplot as plt
f, axarr = plt.subplots(3,4)
FIRST_IMAGE=0
SECOND_IMAGE=7
THIRD_IMAGE=26
CONVOLUTION_NUMBER = 1
from tensorflow.keras import models
layer_outputs = [layer.output for layer in model.layers]
activation_model = tf.keras.models.Model(inputs = model.input, outputs = layer_outputs)
for x in range(0,4):
f1 = activation_model.predict(test_images[FIRST_IMAGE].reshape(1, 28, 28, 1))[x]
axarr[0,x].imshow(f1[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
axarr[0,x].grid(False)
f2 = activation_model.predict(test_images[SECOND_IMAGE].reshape(1, 28, 28, 1))[x]
axarr[1,x].imshow(f2[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
axarr[1,x].grid(False)
f3 = activation_model.predict(test_images[THIRD_IMAGE].reshape(1, 28, 28, 1))[x]
axarr[2,x].imshow(f3[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
axarr[2,x].grid(False)
现在,通过遍历各层可以显示图像的变化:
通过第一次卷积合并,然后池化;然后第二次卷积,第二次池化。图像的大小的改变可以通过轴来查看。
CONVOLUTION_NUMBER = 1:将卷积数设为1,可以看到它几乎立即检测到鞋带区域是鞋子之间的共同特征。通过改变FIRST_IMAGE=0
SECOND_IMAGE=7
THIRD_IMAGE=26
CONVOLUTION_NUMBER = 1可以检测不同的fashion对象。