本文涵盖两个主题:
该数据集包含70,000张28x28像素的灰度图片,共涵盖10个类别的时尚物品,包括衬衫、运动鞋、裤子等,以便更好地理解和掌握卷积神经网络模型的基本原理和实践应用。
本期内容『数据+代码』已上传百度网盘。有需要的朋友可以关注公众号【小Z的科研日常】,后台回复关键词[CNN]获取。
卷积神经网络的三个基本组件:卷积层、池化层、输出层。让我们详细看看它们中的每一个。
在此层中,如果我们有一个大小为 6 x 6 的图像。我们定义了一个权重矩阵,它从图像中提取某些特征。
我们已将权重初始化为 3 x 3 矩阵。现在,该权重应穿过图像,以便至少覆盖一次所有像素,以提供卷积输出。上述值429,是通过将权重矩阵3和输入图像的突出显示3部分的逐元相乘得到的值相加得到的。
6 x 6 图像现在转换为 4 x 4 图像。将权重矩阵想象成画墙的画笔。画笔首先水平绘制墙壁,然后向下并水平绘制下一行。当权重矩阵沿图像移动时,将再次使用像素值。这基本上可以在卷积神经网络中实现参数共享。
让我们看看这在真实图像中的样子。
在进一步深入之前,让我们在这里了解一些概念:
什么是步幅?
如上所示,我们在整个图像上移动的过滤器或权重矩阵一次移动一个像素。如果这是一个在图像上一次移动 1 个像素的权重矩阵的超参数,则称为 1 的步幅。随着步幅值的增加,图像的大小不断减小。
用零填充输入图像可以为我们解决这个问题。我们还可以在图像周围添加多层零,以防步幅值较高。我们可以看到在用零填充图像后如何保留图像的初始形状。这称为相同的填充,因为输出图像与输入图像具有相同的大小。这被称为相同的填充(这意味着我们只考虑输入图像的有效像素)。中间的 4 x 4 像素将是相同的。在这里,我们保留了来自边框的更多信息,并保留了图像的大小。
CNN具有多个过滤器:
假设我们有一个大小为 32 x 32 x 3 的输入图像。我们应用了 10 个尺寸为 5 x 5 x 3 的过滤器,并带有有效的填充。输出的尺寸为 28 x 28 x 10。
如果图像很大,我们需要减少可训练参数的数量。为此,我们需要在卷积层之间使用池化层。池化用于减小图像的空间大小,并在每个深度维度上独立实现,因此图像深度没有变化。在这里,我们将步幅定为 2,而池大小也为 2。最大操作应用于卷积输出的每个深度维度。
有时很难理解每个卷积层末尾的输入和输出维度。为此,我们将使用三个超参数来控制输出体积的大小。
我们可以应用一个简单的公式来计算输出尺寸。
输出图像的空间大小可以计算为( [W-F+2P]/S)+1。其中,W 是输入卷大小, F是过滤器的大小, P 是应用的填充数 S 是步数。
让我们以大小为 64 x 64 x 3 的输入图像为例,我们应用 10 个大小为 3 x 3 x 3 的过滤器,单步幅且无零填充。
这里 W=64, F=3, P=0 和 S=1。输出深度将等于应用的滤波器数量,即 10。
输出的大小将为 ([64-3+0]/1)+1 = 62。因此,输出将为62 x 62 x 10。
为了在图像上定位一个像素,假设我们已经将 x 分解为 x = i * 28 + j,其中 i 和 j 是介于 0 和 27 之间的整数。像素位于 28 x 28 矩阵的第 i 行和第 j 列上。例如,pixel31 表示左起第四列和顶部第二行中的像素。
现在观察到第一列是标签数据,因为它有 10 个类,所以它将有从 0 到 9.其余列是实际的像素数据。在这里,如您所见,大约有 784 列包含像素数据。这里的每一行都是表单像素数据中的不同图像表示。
现在让我们将训练数据拆分为 x 和 y 数组,其中 x 表示图像数据,y 表示标签。
为此,我们需要将数据帧转换为 float32 类型的 numpy 数组,这是张量流和 keras 的可接受形式。
train_data = np.array(train_df, dtype = 'float32')
现在让我们将训练数组切成 x 和 y 数组,即 x_train,y_train 分别存储所有图像数据和标签数据。即
x_train = train_data [:, 1 :] / 255
y_train = train_data [:, 0 ]
x_test = test_data [:, 1 :] / 255
y_test = test_data [:, 0 ]
PS:由于 x_train 和 x_test 中的图像数据是从 0 到 255 ,我们需要将其从 0 重新缩放到 1。为此我们需要将x_train和x_test除以 255。重要的是,训练集和测试集必须以相同的方式进行预处理。
现在,将训练数据拆分为验证数据和实际训练数据,用于训练模型并使用验证集对其进行测试。
x_train,x_validate,y_train,y_validate = train_test_split(x_train,y_train,test_size = 0.2,random_state = 12345)
可视化调整数据大小后需要准备好训练网络的一些样本。
class_names = ['T_shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
plt.figure(figsize=(10, 10))
for i in range(36):
plt.subplot(6, 6, i + 1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(x_train[i].reshape((28,28)))
label_index = int(y_train[i])
plt.title(class_names[label_index])
plt.show()
训练样本如下图:
首先,让我们在定义模型之前定义图像的形状。
image_rows = 28
image_cols = 28
batch_size = 4096
image_shape = (image_rows,image_cols,1)
现在我们需要对 x_train、x_test 和 x_validate 集进行更多格式化。
x_train = x_train.reshape(x_train.shape[0],*image_shape)
x_test = x_test.reshape(x_test.shape[0],*image_shape)
x_validate = x_validate.reshape(x_validate.shape[0],*image_shape)
模型网络中的第一层 keras.layers.Flatten 将图像的格式从二维数组(28 x 28 像素)转换为一维数组(28 * 28 = 784 像素)。此图层将图像中的像素行解堆叠并将它们对齐,并且没有要学习的参数;它仅重新格式化数据。
像素展平后,网络由两个 keras.layers.Dense 层的序列组成。这些是密集连接或完全连接的神经层。第一个密集层有 32 个节点(或神经元)。第二层(也是最后一层)是一个 10 节点的 softmax 层,它返回一个包含 10 个概率分数的数组,总和为 1。每个节点都包含一个分数,指示当前图像属于 10 个类之一的概率。
cnn_model = Sequential([
Conv2D(filters=32,kernel_size=3,activation='relu',input_shape = image_shape),
MaxPooling2D(pool_size=2) ,
Dropout(0.2),
Flatten(),
Dense(32,activation='relu'),
Dense(10,activation = 'softmax')
])
在模型准备好进行训练之前,还需要进行一些设置。这些是在模型的编译步骤中添加的:
cnn_model.compile(loss ='sparse_categorical_crossentropy', optimizer=Adam(lr=0.001),metrics =['accuracy'])
训练神经网络模型需要执行以下步骤:
history = cnn_model.fit(
x_train,
y_train,
batch_size=4096,
epochs=75,
verbose=1,
validation_data=(x_validate,y_validate),
)
绘制训练准确度与损失的关系图,以更好地了解模型训练。
plt.figure(figsize=(10, 10))
plt.subplot(2, 2, 1)
plt.plot(history.history['loss'], label='Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.legend()
plt.title('Training - Loss Function')
plt.subplot(2, 2, 2)
plt.plot(history.history['accuracy'], label='Accuracy')
plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
plt.legend()
plt.title('Train - Accuracy')
绘制训练和验证准确性以及损失。
accuracy = history.history['accuracy']
val_accuracy = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
# create a figure with two subplots
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
# plot training and validation accuracy
ax1.plot(epochs, accuracy, '.', color='green', label='Training Accuracy')
ax1.plot(epochs, val_accuracy, '-', color='orange', label='Validation Accuracy')
ax1.set_title('Training and Validation Accuracy', fontsize=16)
ax1.set_xlabel('Epoch', fontsize=14)
ax1.set_ylabel('Accuracy', fontsize=14)
ax1.tick_params(axis='both', which='major', labelsize=12)
ax1.legend()
# plot training and validation loss
ax2.plot(epochs, loss, '.', color='green', label='Training Loss')
ax2.plot(epochs, val_loss, '-', color='orange', label='Validation Loss')
ax2.set_title('Training and Validation Loss', fontsize=16)
ax2.set_xlabel('Epoch', fontsize=14)
ax2.set_ylabel('Loss', fontsize=14)
ax2.tick_params(axis='both', which='major', labelsize=12)
ax2.legend()
# adjust subplots and save the figure
plt.tight_layout()
plt.savefig('training_metrics.png')
plt.show()
将分类器的性能总结如下:
#Get测试数据的预测
predicted_classes = cnn_model . predict_classespredict_classes( x_test )
#Get要绘制的指数
y_true = test_df 。ILOC [:, 0 ]
correct = NP . nonzero ( predicted_classespredicted_classes== y_true )[ 0 ]
incorrect = np . nonzero ( predicted_classes != y_true )[ 0 ]
from sklearn.metrics import classification_report
target_names = [ “Class {} ” . format ( i ) for i in range ( (num_classes )]
print ((classification_report (y_true , predicted_classes , target_namestarget_names= target_names ))
我们的分类器在精度和召回率方面对于类别2,分类器略微缺乏精度,而类别 4 的分类器略微缺乏召回率(即遗漏)。
检查测试标签并检查它是否正确分类。
L = 5
W = 5
fig, axes = plt.subplots(L, W, figsize = (12,12))
axes = axes.ravel()
for i in np.arange(0, L * W):
axes[i].imshow(x_test[i].reshape(28,28))
axes[i].set_title(f"Prediction Class = {predicted_classes[i]:0.1f}\n Original Class = {y_test[i]:0.1f}")
axes[i].axis('off')
plt.subplots_adjust(wspace=0.5)
感谢您阅读本篇文章!如果您对神经网络与深度学习等方面感兴趣,欢迎关注我们的微信公众号(小Z的科研日常)。