CV&NLP基础9之卷积神经网络CNN入门

专业英语

英文中文
CNN(Convolutional Neural Network)卷积神经网络
RNN(Recurrent Neural Network)循环神经网络
DNN(Deep Neural Network)深度神经网络
ANN(Artificial Neural Network)人工神经网络
GNN(Graph Neural Network)图神经网络
BRNN(Bi-directional Recurrent Neural Network)双向循环神经网络
GAN(Generative Adversarial Network)生成式对抗网络
MTL(Multi-Task-Learning)多任务学习
LSTM(Long Short-Term Memory)长短期记忆网络
SVM(Support Vector Machine)支持向量机
KNN(K-NearestNeighbor)K最近邻分类算法
NBM(Naive Bayesian Model)朴素贝叶斯模型

四维张量

四维张量在卷积神经网络中应用非常广泛,它用于保存特征图(Feature maps)数据,格式一般定义为: [b, h, w, c]。
其中b表示输入样本的数量,h/w分别表示特征图的高/宽,c表示特征图的通道数。

图片数据是特征图的一种,对于含有 RGB 3 个通道的彩色图片,每张图片包含了h行w列像素点,每个点需要 3 个数值表示 RGB 通道的颜色强度,因此一张图片可以表示为[h, w, 3]。如下图所示,最上层的图片表示原图,它包含了下面 3 个通道的强度信息。

在这里插入图片描述

神经网络中一般并行计算多个输入以提高计算效率,故b张图片的张量可表示为[b, h, w, 3],例如:

In [48]:
# 创建32x32的“彩色”图片输入,个数为4
x = tf.random.normal([4,32,32,3]) #输入矩阵: batch=4,32*32,3通道
# 创建卷积神经网络
layer = layers.Conv2D(16,kernel_size=3) #16个卷积核,3*3
out = layer(x) # 前向计算
out.shape # 输出大小
Out[48]: TensorShape([4, 30, 30, 16]) #输出矩阵: batch=4,30*30,16个输出矩阵

其中卷积核张量也是 4 维张量,可以通过 kernel 成员变量访问:

In [49]:layer.kernel.shape # 访问卷积核张量 
Out[49]: TensorShape([3, 3, 3, 16]) #3*3,3通道,16个卷积核

卷积神经网络(CNN)初步

  1. 共享权值的“局部连接层”网络,就是卷积神经网络。

  2. 卷积神经网络通过充分利用局部相关性权值共享的思想,大大地减少了网络的参数量,从而提高训练效率,更容易实现超大规模的深层网络。

  3. 输入通道的通道数量决定了卷积核的通道数。一个卷积核只能得到一个输出矩阵,无论输入𝑿的通道数量。

  4. 卷积运算的“最终输出矩阵大小”由卷积核的大小k,输入𝑿的高宽h/w,移动步长s,是否填充等因素共同决定

  5. feature map = 卷积后的特征数量 = 卷积层的输出维度 = 用了几个卷积核(就有几个输出矩阵) = 提取出图片的特征数量

  6. 解释“最终输出”: 使用卷积核处理图片后, 所总结出的图片“特征”。用更多的卷积核来处理图片,就会得到更多的图片特征

注: 一个卷积核可以有多个通道

感受野

如下图所示,以实心网格所在的像素为参考点,它周边欧式距离小于或等于 𝑘/√2 的像素点以矩形网格表示,网格内的像素点重要性较高,网格外的像素点较低。这个高宽为𝑘的窗口称为感受野(Receptive Field)它表征了每个像素对于中心像素的重要性分布情况,网格内的像素才会被考虑,网格外的像素对于中心像素会被简单地忽略

在这里插入图片描述

这种基于距离的重要性分布假设特性称为局部相关性,它只关注和自己距离较近的部分节点,而忽略距离较远的节点。在这种重要性分布假设下,全连接层的连接模式变成了如下图所示,输出节点𝑗只与以𝑗为中心的局部区域(感受野)相连接,与其它像素无连接

在这里插入图片描述

权值共享

能否再将参数量进一步减少,比如只需要𝑘 * 𝑘个参数即可完成当前层的计算? 答案是肯定的,通过权值共享的思想,对于每个输出节点,均使用相同的权值矩阵𝑾,那么无论输出节点的数量是多少,网络层的参数量总是𝑘 * 𝑘。如下面图片所示,在计算左上角位置的输出像素时,使用权值矩阵:
在这里插入图片描述
与对应感受野内部的像素相乘累加,作为左上角像素的输出值; 在计算右下方感受野区域时,共享权值参数𝑾,即使用相同的权值参数𝑾相乘累加,得到右下角像素的输出值,此时网络层的参数量只有3 * 3 = 9个,且与输入、输出节点数无关。
在这里插入图片描述
总结句: 共享权值矩阵的“局部连接层”网络就是卷积神经网络。

单通道输入和单卷积核

首先讨论单通道输入c=1,如灰度图片只有灰度值一个通道,单个卷积核c=1的情况。以输入𝑿为 5 * 5 的矩阵,卷积核为3 * 3的矩阵为例,如下图所示。与卷积核同大小的感受野(输入𝑿上方的绿色方框)首先移动至输入𝑿最左上方,选中输入𝑿上3 * 3 的感受野元素,与卷积核(图片中间3 * 3方框)对应元素相乘:
在这里插入图片描述
⨀符号表示哈达马积(Hadamard Product),即矩阵的对应元素相乘。运算后得到3*3的矩阵,这9个数值全部-1-1+0-1+2+6+0-2+4=标量7,写入输出矩阵第一行、第一列的位置,如下图:
在这里插入图片描述
完成第一个感受野区域的特征提取后,感受野窗口向右移动一个步长单位(Strides,记为𝑠,默认为 1),选中下图中绿色方框中的 9 个感受野元素,按照同样的计算方法, 与卷积核对应元素相乘累加,得到输出 10,写入第一行、第二列位置:
在这里插入图片描述

感受野窗口再次向右移动一个步长单位,选中下图中绿色方框中的元素,并与卷积核相乘累加,得到输出 3,并写入输出的第一行、第三列位置,如下图所示:
在这里插入图片描述

此时感受野已经移动至输入𝑿的有效像素的最右边,无法向右边继续移动(在不填充无效元素的情况下),因此感受野窗口向下移动一个步长单位(𝑠 = 1),并回到当前行的行首位置,继续选中新的感受野元素区域,如下图所示,与卷积核运算得到输出-1。此时的感受野由于经过向下移动一个步长单位,因此输出值-1 写入第二行、第一列位置:
在这里插入图片描述
按照上述方法,每次感受野向右移动𝑠 = 1个步长单位,若超出输入边界,则向下移动 𝑠 = 1个步长单位,并回到行首,直到感受野移动至最右边、最下方位置,如下图所示。每次选中的感受野区域元素,和卷积核对应元素相乘累加,并写入输出的对应位置。 最终输出我们得到一个3×3的矩阵,比输入5 × 5略小,这是因为感受野不能超出元素边界的缘故。可以观察到,卷积运算的输出矩阵大小由卷积核的大小𝑘,输入𝑿的高宽h/w,移动步长s,是否填充等因素共同决定。这里为了演示计算过程,预绘制了一个与输入等大小的网格,并不表示输出高宽为 5×5 ,这里的实际输出高宽只有3×3:
在这里插入图片描述

多通道输入和单卷积核

多通道输入的卷积层更为常见,比如彩色的图片包含了 R/G/B 三个通道,每个通道上面的像素值表示 R/G/B 色彩的强度。下面我们以 3 通道输入、单个卷积核为例,将单通道输入的卷积运算方法推广到多通道的情况。

如下图所示,每行的最左边5 * 5的矩阵表示输入𝑿的 1 ~ 3 通道,第 2 列的3 * 3矩阵分别表示卷积核的 1 ~ 3 通道,第 3 列的矩阵表示当前通道上运算结果的中间矩阵,最右边一个矩阵表示卷积层运算的最终输出:
在这里插入图片描述
随后,感受野窗口同步在𝑿的每个通道上向右移动 s = 1 个步长单位,此时感受野区域元素如下图 10.18 所示,每个通道上面的感受野与卷积核对应通道上面的矩阵相乘累加, 得到中间变量 10、20、20,全部相加得到输出 50,写入第一行、第二列元素位置:
在这里插入图片描述
以此方式同步移动感受野窗口,直至最右边、最下方位置,此时全部完成输入和卷积核的卷积运算,得到3 * 3的输出矩阵,如图 10.19 所示:
在这里插入图片描述

多通道输入、多卷积核

概念

多通道输入、多卷积核是卷积神经网络中最为常见的形式,前面我们已经介绍了单卷积核的运算过程,每个卷积核和输入𝑿做卷积运算,得到一个输出矩阵。当出现多卷积时,第𝑖 (𝑖 ∈ 𝑛 ,𝑛为卷积核个数)个卷积核与输入𝑿运算得到第𝑖个输出矩阵(也称为输出张量𝑶的通道𝑖),最后全部的输出矩阵在通道维度上进行拼接(Stack 操作,创建输出通道数的新维度),产生输出张量𝑶,𝑶包含了𝑛个通道数

有几个卷积核,就有几个输出矩阵O;一个卷积核只能得到一个输出矩阵。每个卷积核可以有多个通道,卷积核的通道数等于输入矩阵X的通道数。

以 3 通道输入、2 个卷积核的卷积层为例。第一个卷积核与输入𝑿运算得到输出𝑶的第一个通道,第二个卷积核与输入𝑿运算得到输出𝑶的第二个通道,如下图 10.21 所示,输出的两个通道拼接在一起形成了最终输出𝑶。每个卷积核的大小𝑘、步长𝑠、填充设定等都是统一设置,这样才能保证输出的每个通道大小一致,从而满足拼接的条件。
在这里插入图片描述

注1: feature map = 卷积后的特征数量 = 卷积层的输出维度 = 用了几个卷积核(就有几个输出矩阵,这些输出矩阵会拼接在一起)

注2: 解释“最终输出”: 使用卷积核处理图片后, 所总结出的图片“特征”。用更多的卷积核来处理图片,就会得到更多的图片特征。每个输出矩阵就是一个特征。

注3: 一个卷积核可以有多个通道,但是每个卷积核只能产出一个输出矩阵

实例(视频)

在这里插入图片描述

下面视频清晰版: 链接: https://pan.baidu.com/s/1T7Q1SRG4mMhXmjHOKrh6sA?pwd=gf79 提取码: gf79

CVNLP基础文章9多维输入多维卷积核


下面视频清晰版: 链接: https://pan.baidu.com/s/1MI1CR4PElWhtOji1w4B2gw?pwd=g8a6 提取码: g8a6

CVNLP基础文章9多维输入多维卷积核重要解读

步长(Strides)

在卷积运算中,如何控制感受野布置的密度呢? 对于信息密度较大的输入,如物体数量很多的图片,为了尽可能的少漏掉有用信息,在网络设计的时候希望能够较密集地布置感受野窗口; 对于信息密度较小的输入,比如全是海洋的图片,可以适量的减少感受野窗口的数量。 感受野密度的控制手段一般是通过移动步长(Strides)实现的。步长是指感受野窗口每次移动的长度单位,对于 2D 输入来说,分为沿𝑥(向右)方向和 𝑦(向下)方向的移动长度。 为了简化讨论,这里只考虑𝑥/𝑦方向移动步长相同的情况,这也是神经网络中最常见的设定。如下图 10.22 所示,绿色实线代表的感受野窗口的位置是当前位置,绿色虚线代表是上一次感受野所在位置,从上一次位置移动到当前位置的移动长度即是步长的定义。图 10.22 中感受野沿𝑥方向的步长为 2,表达为步长𝑠 = 2。
在这里插入图片描述

在这里插入图片描述
循环往复移动,直至达到最下方、最右边边缘位置,如图 10.24 所示,最终卷积层输出的高宽只有2 * 2。对比前面 s = 1 的情形,输出高宽由3 * 3降低为2 * 2,感受野的数量 减少为仅 4 个。
在这里插入图片描述
可以看到,通过设定步长s,可以有效地控制信息密度的提取。当步长设计的较小时, 感受野以较小幅度移动窗口,有利于提取到更多的特征信息,输出张量的尺寸也更大; 当步长设计的较大时,感受野以较大幅度移动窗口,有利于减少计算代价,过滤冗余信息,输出张量的尺寸也更小。

填充(Padding)

经过卷积运算后的输出𝑶的高宽一般会小于输入𝑿的高宽,即使是步长s = 1时,输出𝑶 的高宽也会略小于输入𝑿高宽。在网络模型设计时,有时希望输出𝑶的高宽能够与输入𝑿的高宽相同,从而方便网络参数的设计、残差连接等。为了让输出𝑶的高宽能够与输入𝑿的相等,一般通过在原输入𝑿的高和宽维度上面进行填充(Padding)若干无效元素操作,得到增大的输入𝑿′。 通过精心设计填充单元的数量,在𝑿′上面进行卷积运算得到输出𝑶的高宽可以和原输入𝑿相等,甚至更大。

如下图 10.25 所示,在高/行方向的上(Top)、下(Bottom)方向,宽/列方向的左(Left)、 右(Right)均可以进行不定数量的填充操作,填充的数值一般默认为 0,也可以填充自定义的数据。图 10.25 中上、下方向各填充 1 行,左、右方向各填充 2 列,得到新的输入𝑿′。
在这里插入图片描述
那么添加填充后的卷积层怎么运算呢? 同样的方法,仅仅是把参与运算的输入从𝑿换成了填充后得到的新张量𝑿′。如下图 10.26 所示,感受野的初始位置在填充后的𝑿′的左上方,完成相乘累加运算,得到输出 1,写入输出张量的对应位置。
在这里插入图片描述
移动步长 s = 1 个单位,重复运算逻辑,得到输出0,如图10.27所示。
在这里插入图片描述
通过精心设计的Padding方案,即上下左右各填充一个单位,记为 p = 1,我们可以得到输出𝑶和输入𝑿的高、宽相等的结果。

CNN引入(视频)

下面视频清晰版: 链接: https://pan.baidu.com/s/1VWFE4–dksPsjgK_bnHAFg?pwd=vx9j 提取码: vx9j

CVNLP基础文章9引入CNN视频

卷积层的实现

自定义权值(tf.nn.conv2d)

在这里插入图片描述
在这里插入图片描述

重要补充

当步长s>1时,设置padding=‘same’,将使得输出高、宽成1/s倍减少。高宽先padding成可以整除s的最小整数,再除以步长:
例1:
在这里插入图片描述
例2:
在这里插入图片描述
例3:
在这里插入图片描述
例4:
在这里插入图片描述
例5:
在这里插入图片描述

卷积层类(layers.Conv2D)

在这里插入图片描述
在这里插入图片描述
注1: padding若等于“valid”,就是不padding
注2: 上面的例子,使用layer.kernel可以看“权重”参数;使用layer.bias可以看“偏置”参数

LeNet-5

概念

下图是 LeNet-5 的网络结构图,它接受32 × 32大小的数字、字符图片,经过第一个卷积层(6个卷积核,5 * 5)得到 [b, 28, 28, 6] 形状的张量,经过一个向下采样层,张量尺寸缩小到[b, 14, 14, 6] ,经过第二个卷积层(16个卷积核,5 * 5),得到[b, 10, 10, 16]形状的张量,同样经过下采样层,张量尺寸缩小到[b, 5, 5, 16],在进入全连接层之前,先将张量打平成[b, 400] 的张量,送入输出节点数分别为 120、84 的 2 个全连接层,得到 [b, 84] 的张量,最后通过 Gaussian connections 层。
在这里插入图片描述

现在看来,LeNet-5 网络层数较少(2 个卷积层和 2 个全连接层),参数量较少,计算代价较低,尤其在现代 GPU 的加持下,数分钟即可训练好 LeNet-5 网络。
在 LeNet-5 的基础上进行了少许调整,使得它更容易在现代深度学习框架上实现。首先我们将输入𝑿形状由32 × 32调整为28 × 28,然后将 2 个下采样层实现为最大池化层(降低特征图的高、宽),最后利用全连接层替换掉 Gaussian connections 层。下文统一称修改的网络也为 LeNet-5 网络。网络结构图如下图所示:
在这里插入图片描述
模型测试代码,运行截图:
在这里插入图片描述
可以看到,卷积层的参数量非常少,主要的参数量集中在全连接层。由于卷积层将输入特征维度降低很多,从而使得全连接层的参数量不至于过大,整个模型的参数量约 6万,因此通过卷积神经网络可以显著降低网络参数量,同时增加网络深度。

代码实践

我们基于 MNIST 手写数字图片数据集训练 修改过的LeNet-5 网络,并测试其最终准确度。这里是修改过的LeNet -5网络,输入X的形状为: [4, 28, 28, 1]。卷积核的size为3 * 3

导入各种包、获取mnist数据

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, optimizers, datasets, Sequential
from __future__ import division
(x, y), (x_val, y_val) = datasets.mnist.load_data()
x.shape, y.shape

运行截图:在这里插入图片描述

处理数据

def preprocessing(xdata, ydata):
    xdata = tf.cast(xdata, dtype=tf.float32)/255
    ydata = tf.cast(ydata, dtype=tf.int32)
    return xdata, ydata
db_train = tf.data.Dataset.from_tensor_slices((x, y))
db_test = tf.data.Dataset.from_tensor_slices((x_val, y_val))
db_train = db_train.map(preprocessing).batch(100) #每组100张图片,共600组
db_test = db_test.map(preprocessing).batch(100) #每组100张图片,共100组

运行截图:
在这里插入图片描述

搭建模型

model = keras.Sequential([ #网络容器
    layers.Conv2D(6, kernel_size=3, strides=1), # 第一个卷积层,6个5*5卷积核
    layers.MaxPool2D(pool_size=2, strides=2), # 高宽各减半的池化层
    layers.ReLU(), # 激活函数
    layers.Conv2D(16, kernel_size=3, strides=1), # 第二个卷积层,16个5*5卷积核
    layers.MaxPool2D(pool_size=2, strides=2), # 高宽各减半的池化层
    layers.ReLU(), # 激活函数
    layers.Flatten(), # 打平层,方便全连接层处理
    
    layers.Dense(120, activation='relu'), # 全连接层,120个节点
    layers.Dense(84, activation='relu'), # 全连接层,84个节点
    layers.Dense(10, activation='relu') # 全连接层,10个节点
])
optimizer = optimizers.Adam(learning_rate=0.0001)
model.build(input_shape=(4,28,28,1))
model.summary()

运行截图:
在这里插入图片描述

使用“训练数据集”训练模型过程及每轮计算准确率

注意1,处理输入数据时为: x = tf.expand_dims(x, axis=3);
注意2,计算准确率,使用argmax和cast时,指定axis=-1;

for epoch in range(30):
    print(f"当前是 第 {epoch} 次 大循环")
    
    for step, (x, y) in enumerate(db_train):
        with tf.GradientTape() as tape:
            #x = tf.reshape(x, (-1, 784))
            x = tf.expand_dims(x, axis=3)
            y = tf.one_hot(y, depth=10)
            out = model(x)
            loss_ce = tf.losses.categorical_crossentropy(y, out, from_logits=True)
            loss_ce = tf.reduce_mean(loss_ce)
        grads = tape.gradient(loss_ce, model.trainable_variables)
        optimizer.apply_gradients(zip(grads, model.trainable_variables))
        
        if step%100==0:
            print(f"epoch: {epoch}; step: {step}; loss: {loss_ce.numpy()}")
    
    total_correct = 0
    total_number = 0
    for (xval, yval) in db_test:
        #xval = tf.reshape(xval, (-1, 784))
        xval = tf.expand_dims(xval, axis=3)
        logits_test = model(xval)
        probability = tf.nn.softmax(logits_test, axis=-1)
        predict = tf.argmax(probability, axis=-1)
        predict = tf.cast(predict, dtype=tf.int32)
        
        bool_correct = tf.equal(predict, yval)
        correct_number = tf.cast(bool_correct, dtype=tf.int32)
        correct_number = tf.reduce_sum(correct_number)
        total_correct += correct_number
        total_number += yval.shape[0]
    print(f"正确个数为: {total_correct}; 当前总图片数为: {total_number}")
    print(f"本轮准确率为: {total_correct / total_number}")
    print('-----------------------')

部分运行截图:
在这里插入图片描述

表示学习

复杂的卷积神经网络模型也是基于卷积层的堆叠构成的。网络层数越深,模型的表达能力越强

2014 年,Matthew D. Zeiler 等人尝试利用可视化的方法去理解卷积神经网络到底学到了什么。通过将每层的特征图利用“反卷积”网络(Deconvolutional Network)映射回输入图片,即可查看学到的特征分布,如下图所示。可以观察到,第二层的特征对应到边、角、色彩等底层图像提取;第三层开始捕获到纹理这些中层特征;第四、五层呈现了 物体的部分特征,如小狗的脸部、鸟类的脚部等高层特征。通过这些可视化的手段,我们可以一定程度上感受卷积神经网络的特征学习过程。
在这里插入图片描述
图片数据的识别过程一般认为也是表示学习(Representation Learning)的过程,从接受到的原始像素特征开始,逐渐提取边缘、角点等底层特征,再到纹理等中层特征,再到头部、物体部件等高层特征,最后的网络层基于这些学习到的抽象特征表示(Representation)做分类逻辑的学习学习到的特征越高层、越准确,就越有利于分类器的分类,从而获得较好的性能。从表示学习的角度来理解,卷积神经网络通过层层堆叠来逐层提取特征,网络训练的过程可以看成特征的学习过程,基于学习到的高层抽象特征可以方便地进行分类任务。
应用表示学习的思想,训练好的卷积神经网络往往能够学习到较好的特征,这种特征的提取方法一般是通用的。比如在猫、狗任务上学习到头、脚、身躯等特征的表示,在其它动物上也能够一定程度上使用。基于这种思想,可以将在任务 A 上训练好的深层神经网络的前面数个特征提取层迁移到任务 B 上,只需要训练任务 B 的分类逻辑(表现为网络的最末数层),即可取得非常好的效果,这种方式是迁移学习的一种,从神经网络角度也称为网络微调(Fine-tuning)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值