Chap.III 深度学习与模型优化
Part 4: 卷积神经网路 (CNN)
Day18提到了数字与文字辨识的机器学习。
然而实际上,我们应该进一步考虑图片的每个像素权重与各个像素间彼此的关联性。
举例来说,一张带有数字的图片,在中心区块的权重(红圈处)理当明显比角落的权重要高。
为此,科学家提出了新方法:Convolutional Neural Network
也就是常看到的 CNN 卷积神经网路
卷积神经网路 (CNN) 是一种前馈神经网路 (Feedforward Neural Network)。
藉影像处理,从图片中萃取特徵,使特徵抽象化 (Abstraction),从而更準确辨识影像。
常由多个卷积层与池化层 Convolution & Pooling;和全连接层 Fully Connected 组成。
此结构使 CNN 与其他深度学习相比,在图像和语音辨识表现得更好。
原图网址
4-1. Assumption 假设
CNN 有两大假设
Local Connectivity 局部连接
即是每个神经元仅接收上一层部分神经元的传导,又称 Receptive Field 感知域。
Share Weight 共享权重
每个感知域对下一隐藏层均使用相同的权重,即 Feature Detector 也称 Filter。
4-2. Function of Layers 各层功能
A. Convolution Layer 卷积层
甚么是卷积运算?
即是将 "Input" 与 "Filter" 以 numpy nd array 的方式相乘后加总
假设今天我们有一个 7*7 的 input image
我们使用一个 3*3 的 Feature Detector(又称 Filter)stride=1, 1 来转换:
这样一来我们就把原图的 7*7 个特徵,萃取成 5*5 个特徵了!
实例上,我们常用卷积运算萃取物体边界
甚至搭配 Relu 函数,进一步淬炼物体形状(因负值都变成 0,轮廓更显着)
不同的 Filter
除上述自订的 Filter,也很常使用以下几种滤波器:
Denosing 去噪:滤波器内讯号平均,使噪讯被模糊化。



重要参数
tf.keras.layers.Conv2D(filters=32, kernel_size=(3, 3), strides=(2, 2), padding='same', activation='relu')
filters:就是你该卷积层想要使用多少个 filters。常设 4 的倍数。kernel_size:你使用的 filter 的 shape。常设奇数边长的正方形(3*3, 5*5 等)。strides:滑动步长,计算滑动视窗时移动的格数。默认 (1, 1)。padding:补 0 策略,卷积层取 kernel_size 滑动视窗时,若超越边界,是选择放弃这个 output 点(valid)、一律补零(same)、或是不计算超越边界的 Input 值(causal)。
因为卷积后图形会变小,为了不让图片与原本大小有差异,会在周围补上 0 维持原本图片大小

B. Pooling Layer 池化层
若说卷积层是用来萃取「精华」,那么池化层就是用来「压缩并保留」重要资讯的方法。
以上例延伸,使用较常见的 Max Pooling(另一种为 Avg),对 2*2 的範围 stride=2, 2 取最大值:
重要参数
tf.keras.layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2), padding='same')
pool_size:池化视窗的大小。常设 2*2。strides:滑动步长,计算滑动视窗时移动的格数。默认 (1, 1)。padding:补 0 策略,卷积层取 kernel_size 滑动视窗时,若超越边界,是选择放弃这个 output 点(valid)、一律补零(same)。
C. Fully Connected Layer 全连接层
即是将结果平坦化后连接,概念就像是把 2D 的图片拍扁变成 1D 的数列。
4-3. 实作
讲完了概念,接着我们用 Tensorflow 官网的範例来演练一下。
官网的程式码如下:
import tensorflow as tfmnist = tf.keras.datasets.mnist(x_train, y_train),(x_test, y_test) = mnist.load_data()x_train, x_test = x_train / 255.0, x_test / 255.0model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(input_shape=(28, 28)), tf.keras.layers.Dense(128, activation='relu'), tf.keras.layers.Dropout(0.2), tf.keras.layers.Dense(10, activation='softmax')])model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])model.fit(x_train, y_train, epochs=5)model.evaluate(x_test, y_test)
原本的 mnist 的资料已经很乾净,因此实作的準确度本身就已相当高。
接着我们试着用 CNN 的方式来撰写:
import tensorflow as tfmnist = tf.keras.datasets.mnist(x_train, y_train),(x_test, y_test) = mnist.load_data()x_train_norm, x_test_norm = x_train / 255.0, x_test / 255.0
不同的是,这次我们在建模的时候加入 CNN:
首先,要把 x 增加一维在最后面,因为 CNN 要多一个表示颜色的维度
x_train = x_train.reshape(*x_train.shape, 1)x_test = x_test.reshape(*x_test.shape, 1)x_train.shape, x_test.shape>> ((60000, 28, 28, 1), (10000, 28, 28, 1))
建模
model_cnn = tf.keras.Sequential([ tf.keras.Input(shape=(28, 28, 1)), tf.keras.layers.Conv2D(32, kernel_size=(3, 3), activation="relu"), tf.keras.layers.MaxPooling2D(pool_size=(2, 2)), tf.keras.layers.Conv2D(64, kernel_size=(3, 3), activation="relu"), tf.keras.layers.MaxPooling2D(pool_size=(2, 2)), tf.keras.layers.Flatten(), tf.keras.layers.Dropout(0.2), tf.keras.layers.Dense(10, activation="softmax"),])
优化器设定:与前面同样使用 Adam、交叉熵做损失函数,关键指标则看準确率。
model_cnn.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])history = model_cnn.fit(x_train, y_train, epochs=5, validation_split=0.2)