选题:彩色图片分类
难度:新手入门
语言:Python3、TensorFlow2
要求:
学习如何编写一个完整的深度学习程序
了解分类彩色图片会灰度图片有什么区别
测试集accuracy到达72%
import tensorflow as tf
from tensorflow.keras import datasets,layers,models #keras:指神经网络框架
import matplotlib.pyplot as plt
(train_images,train_labels),(test_images,test_labels) = datasets.cifar10.load_data()
train_images,test_images = train_images/255.0,test_images/255.0
train_images.shape,test_images.shape,train_labels.shape
((50000, 32, 32, 3), (10000, 32, 32, 3), (50000, 1))
plt.figure(figsize=(20,10))
#根据结果,对图片编号对应分类进行标注
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer','dog', 'frog', 'horse', 'ship', 'truck']
for i in range(20):
plt.subplot(5,10,i+1)
plt.imshow(train_images[i])
plt.yticks([])
plt.xticks([])
plt.xlabel(class_names[train_labels[i][0]])
plt.show()
根据相关理论,特征提取的误差主要来自两个方面:
(1)邻域大小受限造成的估计值方差增大;
(2)卷积层参数误差造成估计均值的偏移。
一般来说
mean-pooling能减小第一种误差(邻域大小受限造成的估计值方差增大),更多的保留图像的背景信息,
max-pooling能减小第二种误差(卷积层参数误差造成估计均值的偏移),更多的保留纹理信息。
Conv2D(): 卷积层,动态提取图片局部特征,tf.keras.layers.Conv2D(
即,误差反向传播,建立在梯度下降基础上。
正向传播,输入信息经隐含层,逐步处理并传播至输出层,得到预测值,若与真实值不同,则计算损失函数
将该损失函数传入反向传播过程,逐层求出loss对各神经元权重的偏导,作为目标函数对权重梯度,并修改,直到误差达到期望
计算某一个系数对总误差的影响采用链式法则,主要该误差要将不同路径结果求和
系数更新公式为
与灰度图象不同,彩色图像通常有三个通道,即图像深度视为3,因此卷积核深度为3而灰度图为1,最终输出结果是将同一个卷积核对三个通道矩阵分别卷积后求和的结果
model = models.Sequential([ #Sequential:顺序,制造一个容器
layers.Conv2D(32,(3,3),activation = 'relu',input_shape=(32,32,3)), #卷积层1,3*3
layers.MaxPool2D((2,2)), #池化层
layers.Conv2D(64,(3,3),activation='relu'),
layers.MaxPool2D((2,2)),
layers.Flatten(),
layers.Dense(64,activation='relu'), #全连接层提取特征
layers.Dense(10,activation='softmax')
])
model.summary()
Model: “sequential”
conv2d (Conv2D) (None, 30, 30, 32) 896
max_pooling2d (MaxPooling2D (None, 15, 15, 32) 0
)
conv2d_1 (Conv2D) (None, 13, 13, 64) 18496
max_pooling2d_1 (MaxPooling (None, 6, 6, 64) 0
2D)
flatten (Flatten) (None, 2304) 0
dense (Dense) (None, 64) 147520
dense_1 (Dense) (None, 10) 650
=================================================================
Total params: 167,562
Trainable params: 167,562
Non-trainable params: 0
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
history = model.fit(train_images,train_labels,epochs=10,validation_data=(test_images,test_labels))
Epoch 1/10
1563/1563 - 37s 22ms/step - loss: 1.4751 - accuracy: 0.4729 - val_loss: 1.2133 - val_accuracy: 0.5764
Epoch 2/10
1563/1563- 29s 19ms/step - loss: 1.1154 - accuracy: 0.6101 - val_loss: 1.0410 - val_accuracy: 0.6333
Epoch 3/10
1563/1563- 32s 20ms/step - loss: 0.9889 - accuracy: 0.6554 - val_loss: 0.9828 - val_accuracy: 0.6562
Epoch 4/10
1563/1563 - 31s 20ms/step - loss: 0.9118 - accuracy: 0.6839 - val_loss: 0.9593 - val_accuracy: 0.6695
Epoch 5/10
1563/1563 - 29s 19ms/step - loss: 0.8490 - accuracy: 0.7051 - val_loss: 0.9274 - val_accuracy: 0.6776
Epoch 6/10
1563/1563- 30s 19ms/step - loss: 0.7962 - accuracy: 0.7212 - val_loss: 1.0031 - val_accuracy: 0.6605
Epoch 7/10
1563/1563 - 31s 20ms/step - loss: 0.7539 - accuracy: 0.7363 - val_loss: 0.9010 - val_accuracy: 0.6927
Epoch 8/10
1563/1563 - 33s 21ms/step - loss: 0.7157 - accuracy: 0.7486 - val_loss: 0.9414 - val_accuracy: 0.6831
Epoch 9/10
1563/1563- 32s 20ms/step - loss: 0.6773 - accuracy: 0.7624 - val_loss: 0.9776 - val_accuracy: 0.6772
Epoch 10/10
1563/1563 - 32s 20ms/step - loss: 0.6494 - accuracy: 0.7714 - val_loss: 0.9521 - val_accuracy: 0.6868
import matplotlib.pyplot as plt
plt.plot(history.history['accuracy'],label='accuracy')
plt.plot(history.history['val_accuracy'],label='val_accuracy')
plt.xlabel('Epoch')
plt.ylabel('accuracy')
plt.legend(loc='lower right')
test_loss,test_acc = model.evaluate(test_images,test_labels,verbose=2)
print(test_acc)
0.6868000030517578
显然模型预测准确率过低,需要对模型进行优化
model2 = models.Sequential([
layers.Conv2D(32,(3,3),padding='same',activation = 'relu',input_shape=(32,32,3)), #为了防止卷积过多使得图像边缘消失,padding=‘same'
layers.MaxPool2D((2,2)),
layers.Conv2D(64,(3,3),padding='same',activation='relu'),
layers.MaxPool2D((2,2)),
layers.Conv2D(128,(3,3),activation='relu',padding='valid'),
layers.Flatten(),
layers.Dense(128,activation='relu'),
layers.Dense(10,activation='softmax')])
model2.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
history = model2.fit(train_images,train_labels,epochs=10,validation_data=(test_images,test_labels))
plt.plot(history.history['accuracy'],label='accuracy')
plt.plot(history.history['val_accuracy'],label='val_accuracy')
plt.xlabel('Epoch')
plt.ylabel('accuracy')
plt.legend(loc='lower right')
test_loss,test_acc = model2.evaluate(test_images,test_labels,verbose=2)
可见测试集准确率已经达到72%,但训练集超过90%考虑是否存在过拟合
我们一般在网络的最开始和结束的时候使用全连接层,而hidden layers则是网络中的卷积层。所以一般情况,在全连接层部分,采用较大概率的dropout而在卷积层采用低概率或者不采用dropout。
model3 = models.Sequential([
layers.Conv2D(32,(3,3),padding='same',activation = 'relu',input_shape=(32,32,3)), #为了防止卷积过多使得图像边缘消失,padding=‘same'
layers.MaxPool2D((2,2)),
layers.Conv2D(64,(3,3),padding='same',activation='relu'),
layers.MaxPool2D((2,2)),
layers.Conv2D(128,(3,3),activation='relu',padding='valid'),
layers.Flatten(),
layers.Dense(128,activation='relu'),
layers.Dropout(0.2),#该方法常用于全连接层部分
layers.Dense(10,activation='softmax')])
model3.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
history = model3.fit(train_images,train_labels,epochs=10,validation_data=(test_images,test_labels))
Epoch 10/10
1563/1563 52s 33ms/step - loss: 0.4802 - accuracy: 0.8274 - val_loss: 0.8817 - val_accuracy: 0.7297
plt.plot(history.history['accuracy'],label='accuracy')
plt.plot(history.history['val_accuracy'],label='val_accuracy')
plt.xlabel('Epoch')
plt.ylabel('accuracy')
plt.legend(loc='lower right')
test_loss,test_acc = model3.evaluate(test_images,test_labels,verbose=2)
第三次实验结果,测试集准确率接近73%,训练集为82.7%,相对来说过拟合的情况明显减弱
plt.imshow(test_images[5])
import numpy as np
pre = model3.predict(test_images)
print(class_names[np.argmax(pre[5])])
313/313 [==============================] - 3s 9ms/step
frog
针对模型准确率不足的情况可以通过适当添加卷积层得到比较好的解决,但有可能导致模型过拟合,此时通过在模型开头或是结尾添加dropout层的方法得到一定的改善