Skip to content

卷积神经网络

在理解了机器学习概念之后,我们现在可以将重点转移到深度学习。深度学习作为机器学习的一个子领域,代表了 AI 的重大进步,为图像和语音识别等应用提供了支持。

两种重要的深度神经网络类型是:

  • 卷积神经网络 (Convolutional Neural Networks, CNNs)
  • 循环神经网络 (Recurrent Neural Networks, RNNs)

本章重点介绍 CNNs,它们特别擅长处理网格状数据,例如图像。

卷积神经网络 (Convolutional Neural Networks)

Section titled “卷积神经网络 (Convolutional Neural Networks)”

卷积神经网络 (CNNs) 是用于处理具有网格状拓扑的数据(例如图像(二维像素网格))的专门神经网络。它们是许多计算机视觉应用(如图像分类、对象检测和人脸识别)的核心。与可能需要手动从图像中提取特征的传统神经网络不同,CNNs 直接从输入数据(通常是二维或三维 tensor)中自动学习分层特征。

领先的科技公司广泛使用 CNNs 执行各种识别任务,利用它们学习特征空间层次结构的能力。

CNN 通常包含三个核心概念或层类型:

  • 卷积层 (Convolutional layers) (利用局部感受野 local receptive fields)
  • 池化层 (Pooling layers)
  • 全连接层 (Fully Connected layers)

让我们理解这些概念:

CNNs 利用输入数据中的空间相关性。早期层中的神经元仅连接到输入层的一小部分区域,称为局部感受野 (local receptive field)。这使得网络能够首先学习基本特征(如边缘或角)。随着数据通过更深的层,这些局部特征被组合起来形成更复杂的模式。

CNNs 中的一个关键操作是卷积 (convolution)。想象一个小的滤波器 (filter)(或称为核 kernel)在输入图像上滑动。在每个位置,滤波器与其覆盖的图像部分执行逐元素乘法,并将结果相加产生输出特征图 (feature map) 中的一个值。使用多个滤波器重复此过程以学习不同的特征。这些滤波器的权重 (weights) 在训练期间学习。

定义滤波器的权重集在输入的所有位置共享,这显著减少了参数数量,并使网络能够检测特征,而不管其在图像中的位置如何。每个滤波器通常还有一个相关的偏置项 (bias term),该偏置项也是共享的。

池化层 (Pooling layers) 通常插入在卷积层之后。它们的目的是减小特征图的空间维度(宽度和高度),从而降低计算复杂度并控制过拟合 (overfitting)。常见的池化操作包括最大池化 (Max Pooling)(取局部区域的最大值)和平均池化 (Average Pooling)。这也有助于使学习到的特征对输入的微小平移 (translations) 更具鲁棒性。

我们现在将使用 TensorFlow 的 Keras API 实现一个用于图像分类的 CNN,Keras 提供了一种用户友好的方式来构建神经网络。我们将使用手写数字的 MNIST 数据集。

步骤 1:导入必要的模块并加载数据。我们将使用 tf.keras.datasets.mnist 加载数据,并使用 tf.keras 构建模型。

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import numpy as np
# Load the MNIST dataset
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
# Preprocess the data
# Normalize pixel values to be between 0 and 1
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
# Reshape images to (28, 28, 1) for CNN input (add channel dimension)
x_train = np.expand_dims(x_train, -1)
x_test = np.expand_dims(x_test, -1)
# Convert labels to one-hot encoded vectors
num_classes = 10
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

此步骤导入 TensorFlow 和 Keras 中必要的库和模块,加载 MNIST 数据集,并通过重塑 (reshaping)、归一化 (normalizing) 和 one-hot 编码标签 (labels) 来准备数据进行训练。

步骤 2:使用 Keras Sequential API 定义 CNN 模型架构。

input_shape = (28, 28, 1) # Height, Width, Channels
model = keras.Sequential(
[
keras.Input(shape=input_shape),
layers.Conv2D(32, kernel_size=(3, 3), activation="relu"), # 32 filters, 3x3 kernel
layers.MaxPooling2D(pool_size=(2, 2)), # 2x2 max pooling
layers.Conv2D(64, kernel_size=(3, 3), activation="relu"), # 64 filters, 3x3 kernel
layers.MaxPooling2D(pool_size=(2, 2)),
layers.Flatten(), # Flatten the 2D feature maps to a 1D vector
layers.Dropout(0.5), # Dropout for regularization
layers.Dense(num_classes, activation="softmax") # Output layer with softmax
]
)
model.summary() # Print model architecture

层解释:

  • keras.Input: 定义预期的输入形状 (input shape)。
  • layers.Conv2D: 二维卷积层。第一个参数是滤波器 (filters) 的数量,kernel_size 指定卷积窗口的维度,activation 是激活函数 (ReLU 是常见的)。
  • layers.MaxPooling2D: 通过在 pool_size 定义的窗口上取最大值来降低维度。
  • layers.Flatten: 将二维多通道特征图 (feature maps) 展平为一维向量,以便输入到全连接层 (dense layers)。
  • layers.Dropout: 一种正则化 (regularization) 技术,在训练期间随机忽略选定的神经元以防止过拟合 (overfitting)。
  • layers.Dense: 一个标准的 full connected 神经网络层。最后一层使用 softmax 激活函数进行多类分类 (multi-class classification)。

步骤 3:编译 (Compile) 模型。这配置了学习过程。

model.compile(optimizer="adam",
loss="categorical_crossentropy",
metrics=["accuracy"])

在这里,我们使用:

  • optimizer="adam": Adam 是一种高效且常用的优化算法。
  • loss="categorical_crossentropy": 适用于带有 one-hot 编码标签的多类分类。
  • metrics=["accuracy"]: 我们希望在训练期间监控分类准确率 (accuracy)。

步骤 4:使用 fit 方法训练模型。

batch_size = 128
epochs = 15
print("\nTraining the model...")
history = model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
validation_split=0.1) # Use 10% of training data for validation

batch_size 决定了在更新模型内部参数之前处理的样本数量。epochs 是整个训练数据集通过模型的次数。validation_split 保留一部分训练数据用于训练期间的验证 (validation)。

步骤 5:在测试集上评估 (Evaluate) 训练好的模型。

print("\nEvaluating the model on test data...")
score = model.evaluate(x_test, y_test, verbose=0)
print("Test loss:", score[0])
print("Test accuracy:", score[1])
# Example: Make a prediction on a single test image
print("\nMaking a prediction on the first test image...")
prediction = model.predict(np.expand_dims(x_test[0], axis=0))
predicted_class = np.argmax(prediction[0])
actual_class = np.argmax(y_test[0])
print(f"Predicted class: {predicted_class}, Actual class: {actual_class}")

此示例演示了使用 TensorFlow 2.x 及其 Keras API 构建、训练和评估 CNN 的现代方法。与需要手动会话管理、占位符 (placeholders) 和显式变量初始化 (variable initialization) 的旧版 TensorFlow 相比,代码更简洁,并与当前的最佳实践保持一致。

预期输出(由于随机初始化和训练动态,会有轻微变化):

Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 26, 26, 32) 320
max_pooling2d (MaxPooling2D (None, 13, 13, 32) 0
)
conv2d_1 (Conv2D) (None, 11, 11, 64) 18496
max_pooling2d_1 (MaxPoolin (None, 5, 5, 64) 0
g2D)
flatten (Flatten) (None, 1600) 0
dropout (Dropout) (None, 1600) 0
dense (Dense) (None, 10) 16010
=================================================================
Total params: 34,826
Trainable params: 34,826
Non-trainable params: 0
_________________________________________________________________
Training the model...
Epoch 1/15
422/422 [==============================] - 5s 5ms/step - loss: 0.3651 - accuracy: 0.8900 - val_loss: 0.0836 - val_accuracy: 0.9773
Epoch 2/15
422/422 [==============================] - 2s 4ms/step - loss: 0.1109 - accuracy: 0.9663 - val_loss: 0.0578 - val_accuracy: 0.9840
...
Epoch 15/15
422/422 [==============================] - 2s 4ms/step - loss: 0.0265 - accuracy: 0.9913 - val_loss: 0.0337 - val_accuracy: 0.9903
Evaluating the model on test data...
Test loss: 0.0279...
Test accuracy: 0.9901...
Making a prediction on the first test image...
1/1 [==============================] - 0s 18ms/step
Predicted class: 7, Actual class: 7