全部文章

12.卷积神经网络CNN

全连接神经网络处理图像存在的问题

利用全连接神经网络对图像进行处理存在以下两个问题

  • 需要处理的数据量大,效率低假如我们处理一张 1000x1000 像素的图片,参数量如下:

1000x1000x3=3,000,000

这么大量的数据处理起来是非常消耗资源的

  • 图像在维度调整的过程中很难保留原有的特征,导致图像处理的准确率不高

假如有圆形是1,没有圆形是0,那么圆形的位置不同就会产生完全不同的数据表达。但是从图像的角度来看,图像的内容(本质)并没有发生变化,只是位置发生了变化。所以当我们移动图像中的物体,用全连接升降得到的结果会差异很大,这是不符合图像处理的要求的。

CNN网络的构成

CNN(Convolutional Neural Network)网络受人类视觉神经系统的启发,人类的视觉原理:从原始信号摄入开始(瞳孔摄入像素Pixels),接着做初步处理(大脑皮层某些细胞发现边缘和方向),然后抽象(大脑判定,眼前的物体的形状,是圆形的),然后进一步抽象(大脑进一步判定该物体是只人脸)。下面是人脑进行人脸识别的一个示例:

CNN网络主要有三部分构成:卷积层池化层全连接层构成:

  • 卷积层负责提取图像中的局部特征;
  • 池化层用来大幅降低参数量级(降维);
  • 全连接层类似人工神经网络的部分,用来输出想要的结果。

整个CNN网络结构如下图所示:

卷积层

卷积层是卷积神经网络中的核心模块,卷积层的目的是提取输入特征图的特征,如下图所示,卷积核可以提取图像中的边缘信息

卷积的计算方法

那卷积是怎么进行计算的呢?

(上面是使用的是3x3的卷积核(Fliter))

关于卷积核详解,参照文末:卷积核

卷积运算本质上就是在滤波器和输入数据的局部区域间做点积。

左上角的点计算方法:

同理可以计算其他各点,得到最终的卷积结果

最后一个点的计算过程为:

padding

在上述卷积过程中,特征图比原始图减小了很多,我们可以在原图像的周围进行padding,来保证在卷积过程中特征图大小不变(其实就是在周围添加一层或者多层“0”)

stride

按照步长为1来移动卷积核,计算特征图如下所示

如果我们把stride增大,比如设为2,也是可以提取特征图的,如下图所示:

步长增大也能起到降维的作用

多通道卷积

实际中的图像都是多个通道组成的,我们怎么计算卷积呢?

计算方法如下:当输入有多个通道(channel)时(例如图片可以有 RGB 三个通道),卷积核需要拥有相同的channel数,每个卷积核 channel 与输入层的对应 channel 进行卷积,将每个 channel的卷积结果按位相加得到最终的 Feature Map

多卷积核卷积

如果有多个卷积核时怎么计算呢?当有多个卷积核时,每个卷积核学习到不同的特征,对应产生包含多个 channel 的 Feature Map,例如下图有两个 filter,所以 output 有两个 channel。

特征图大小

输出特征图的大小与以下参数息息相关:

  • *size:卷积核/过滤器大小,一般会选择为奇数,比如有:1*1,3*3,5*5
  • *padding:零填充的方式
  • *stride:步长

计算方法如下所示:

  • 输入体积大小H1*W1*D1(H:高,W:宽,D:通道数)
  • 四个超参数:
    • Filter数量K(卷积核个数)
    • Filter大小F(卷积核大小)
    • 步长S
    • 零填充大小P
  • 输出体积大小H2*W2*D2
    • H2=(H1-F+2P)/S+1
    • W2=(W1-F+2P)/S+1
    • D2=K

输入特征图为5x5,卷积核为3x3,外加padding为1,则其输出尺寸为:

如下图所示:

在tf.keras中卷积核的实现使用:

tf.keras.layers.Conv2D(filters,kernel_size,strides=(1,1),padding='valid',activation=None)

主要参数说明:

参数 描述
filters 卷积过滤器的数量,对应输出特征图的通道数
kernel_size 过滤器 filter 的大小
strides 步长
padding

valid: 在输入周围不进行 padding;(padding=0)

same: padding 后使输出特征图和输入特征图形状相同

activation 激活函数

池化层(Pooling)

池化层用来降低后续网络层的输入维度,缩减模型大小,提高计算速度,并提高了Feature Map的鲁棒性,防止过拟合。

它主要对卷积层学习到的特征图进行下采样(subsampling)处理,主要有两种:最大池化,平均池化

最大池化(推荐)

  • Max Pooling,取窗口内的最大值作为输出,这种方式使用较广泛。

在tf.keras的实现使用:

tf.keras.layers.MaxPool2D(pool_size=(2,2),strides=None,padding='valid')

参数:

  • pool_size:池化窗口的大小
  • strides:窗口移动的步长,默认为1
  • padding:是否进行填充,默认是不进行填充的

平均池化

Avg Pooling,取窗口内的所有值的均值作为输出

在tf.keras的实现使用:

tf.keras.layers.AveragePooling2D(pool_size=(2,2),strides=None,padding='valid')

全连接层

全连接层位于CNN网络的末端,经过卷积层的特征提取与池化层的降维后,将特征图转换成一维向量送入到全连接层中进行分类或回归的操作。

在tf.keras中全连接层使用tf.keras.dense实现。

LeNet-5卷积神经网络的构建

我们构建卷积神经网络在mnist数据集上进行处理,如下图所示:LeNet-5是一个较简单的卷积神经网络,输入的二维图像,先经过两次卷积层,池化层,再经过全连接层,最后使用softmax分类作为输出层。

导入工具包:

import tensorflow as tf 
from tensorflow.keras.datasets import mnist

数据集加载

(x_train,y_train),(x_test,y_test)=mnist.load_data()
x_train.shape,y_train.shape,x_test.shape,y_test.shape#((60000, 28, 28), (60000,), (10000, 28, 28), (10000,))

数据处理

卷积神经网络的输入要求是:NHWC,分别是图片数量,图片高度,图片宽度和图片的通道,因为是灰度图,通道为1.

# 数据处理num,H,W,C
# 训练集
train_imags=tf.reshape(x_train,(x_train.shape[0],x_train.shape[1],x_train.shape[2],1))
# 测试集
test_imags=tf.reshape(x_test,(x_test.shape[0],x_test.shape[1],x_test.shape[2],1))
train_imags.shape,test_imags.shape#(TensorShape([60000, 28, 28, 1]), TensorShape([10000, 28, 28, 1]))

模型搭建

Lenet-5模型输入的二维图像,先经过两次卷积层,池化层,再经过全连接层,最后使用softmax分类作为输出层,模型构建如下:

net=tf.keras.models.Sequential([

    tf.keras.layers.Input(shape=(28,28,1)),
    #卷积层:6个5*5的卷积核,激活函数是sigmoid
    tf.keras.layers.Conv2D(filters=6,kernel_size=5,activation='sigmoid'),
    # 最大池化    
    tf.keras.layers.MaxPool2D(pool_size=2,strides=2),
    #卷积层:16个5*5的卷积核,激活函数是sigmoid   
    tf.keras.layers.Conv2D(filters=16,kernel_size=5,activation='sigmoid'),
    # 最大池化    
    tf.keras.layers.MaxPool2D(pool_size=2,strides=2),
    # 维度调整为1维数据
    tf.keras.layers.Flatten(),
    # 全连接层,激活‘sigmoid’
    tf.keras.layers.Dense(120,activation='sigmoid'),
    # 全连接层,激活‘sigmoid’
    tf.keras.layers.Dense(80,activation='sigmoid'),
    # 全连接层,激活‘sigmoid’
    tf.keras.layers.Dense(10,activation='softmax')
])

net.summary()
Model: "sequential"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓
┃ Layer (type)                         ┃ Output Shape                ┃         Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩
│ conv2d (Conv2D)                      │ (None, 24, 24, 6)           │             156 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ max_pooling2d (MaxPooling2D)         │ (None, 12, 12, 6)           │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ conv2d_1 (Conv2D)                    │ (None, 8, 8, 16)            │           2,416 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ max_pooling2d_1 (MaxPooling2D)       │ (None, 4, 4, 16)            │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ flatten (Flatten)                    │ (None, 256)                 │               0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ dense (Dense)                        │ (None, 120)                 │          30,840 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ dense_1 (Dense)                      │ (None, 80)                  │           9,680 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ dense_2 (Dense)                      │ (None, 10)                  │             810 │
└──────────────────────────────────────┴─────────────────────────────┴─────────────────┘
 Total params: 43,902 (171.49 KB)
 Trainable params: 43,902 (171.49 KB)
 Non-trainable params: 0 (0.00 B)

模型编译

设置优化器和损失函数:

# 优化器
optimizer=tf.keras.optimizers.SGD(learning_rate=0.9)
# 模型编译:指定损失函数、优化器和评价指标
net.compile(optimizer=optimizer,loss='sparse_categorical_crossentropy',metrics=['accuracy'])#由于目标数据未进行热编码,所以选用sparse_categorical_crossentropy

模型训练

net.fit(x_train,y_train,epochs=5,validation_split=0.1)
Epoch 1/5
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 4s 2ms/step - accuracy: 0.2273 - loss: 2.0352 - val_accuracy: 0.9270 - val_loss: 0.2190
Epoch 2/5
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 4s 2ms/step - accuracy: 0.9463 - loss: 0.1711 - val_accuracy: 0.9742 - val_loss: 0.0889
Epoch 3/5
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 4s 2ms/step - accuracy: 0.9680 - loss: 0.1026 - val_accuracy: 0.9813 - val_loss: 0.0642
Epoch 4/5
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 4s 3ms/step - accuracy: 0.9735 - loss: 0.0831 - val_accuracy: 0.9738 - val_loss: 0.0806
Epoch 5/5
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9775 - loss: 0.0728 - val_accuracy: 0.9722 - val_loss: 0.0930
<keras.src.callbacks.history.History at 0x1c006626450>

 模型评估

score=net.evaluate(x_test,y_test,verbose=1)
score
313/313 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9652 - loss: 0.1076
[0.09157712757587433, 0.9710999727249146]

 与全连接相比,准确率提高了不少?

 

 

补充

卷积核

卷积核(也叫卷积滤波器、卷积矩阵 )是一个方阵,但对角线上不一定都是 1 ,它的数值完全由任务需求设计目标决定,不同场景下卷积核的数值千差万别

一、基础卷积核:数值由功能决定

卷积核本质是 “权重矩阵”,用于提取图像局部特征(如边缘、纹理、色彩 )。

1. 边缘检测核(以 Sobel 算子为例)

Sobel 核用于检测图像水平 / 垂直边缘,以 3×3 水平边缘检测核为例:
 
原理:通过上下行像素差计算梯度,差值大的位置判定为边缘。

2. 均值模糊核

用于图像平滑(模糊),3×3 均值核:
这是 “均值模糊” 的特殊设计(所有像素等权平均 )。

3. 锐化核

用于增强图像边缘(让画面更清晰 ),3×3 锐化核:
核心是中心像素加权增强。

二、深度学习中的卷积核:自动学习权重

在 CNN(卷积神经网络 )中,卷积核的数值不是人工设计,而是通过训练数据自动学习得到的。

1. 训练前:随机初始化

训练开始前,卷积核数值是随机生成的(如正态分布、均匀分布 ),对角线可能是任意值(比如 0.1, -0.3, 0.2 等 )。

2. 训练后:适配任务

训练完成后,卷积核数值会适配任务需求(如分类、检测 )。例如:
  • 提取 “圆形物体” 特征的核,对角线数值可能和其他位置差异极大;
  • 提取 “纹理重复模式” 的核,数值分布可能呈现周期性。

三、特殊场景:单位矩阵相关的核

** Identity 核 **(恒等变换核 ):
作用是 “保留中心像素,忽略周围”,常用于残差连接(如 ResNet )中传递原始信息。
常见误解 事实澄清
卷积核都是方阵 实际工程中非方核占比>30%
卷积核是矩阵 卷积核是4维张量,不是矩阵
残差连接中的"恒等映射"说法 实际实现多用1×1卷积替代

卷积核作为矩阵

在基础的图像处理,如传统的数字图像处理领域,当进行简单的滤波操作(如边缘检测、图像平滑)时 ,卷积核一般是二维矩阵。比如常见的用于边缘检测的 Sobel 算子,是一个 3×3 的二维矩阵;用于图像平滑的均值滤波器,也是二维矩阵形式,像 3×3 的均值矩阵:

这种情况下,卷积操作就是将二维的卷积核矩阵与二维的图像矩阵进行对应位置的相乘再累加运算。

卷积核作为四维张量

在深度学习的 CNN 中,卷积核通常是四维张量,这是因为要考虑多个维度的信息,其四个维度分别代表:
  1. 卷积核的数量:在一个卷积层中,通常会使用多个卷积核去提取不同的特征。比如一个卷积层中有 32 个卷积核,就意味着会提取 32 种不同的特征。
  2. 输入通道数:对于彩色图像,它有 RGB 三个通道,那么输入通道数就是 3 ;如果是灰度图像,输入通道数就是 1。卷积核的输入通道数需要和输入图像的通道数保持一致,这样才能正确进行卷积运算。
  3. 卷积核的高度:也就是卷积核在图像垂直方向上的尺寸,常见的有 3、5 等。
  4. 卷积核的宽度:即卷积核在图像水平方向上的尺寸,常见的取值也有 3、5 等。
例如,假设一个卷积层中有 64 个卷积核,输入图像是 RGB 彩色图像(输入通道数为 3),卷积核的大小是 3×3, 那么这个卷积核的形状就是 (64, 3, 3, 3),这是一个四维张量。

总结

  • 在传统图像处理简单场景下,卷积核可以看作二维矩阵;而在深度学习 CNN 处理多通道、多特征提取的复杂场景中,卷积核是四维张量。不过,当我们在讨论单个卷积核在某一通道上的操作时,也可以把四维张量中的一部分视为二维矩阵进行理解 。

 

其他疑问:

我们在使用卷积层的时候:

 #卷积层:16个5*5的卷积核,激活函数是sigmoid 
tf.keras.layers.Conv2D(filters=16,kernel_size=5,activation='sigmoid'), 

核的个数和卷积核大小都是设置好的,为什么说他们的形状是随机生成的?这不矛盾吗?

另外,参数设置只有一个kernel_size来指定核的形状,那岂不是只能是方阵?

1. 人为设置的是卷积层的 “架构参数”

当你写 Conv2D(filters=16, kernel_size=5) 时,你定义的是卷积层的静态结构
  • filters=16:指定该层有 16 个卷积核(即 16 个不同的特征检测器);
  • kernel_size=5:每个卷积核的 空间尺寸 是 5×5(高 × 宽)。
这些参数在模型构建时就固定了,决定了卷积层的计算规模(如参数量、计算量)。

2. 卷积核的 “具体数值” 是随机初始化的

虽然你定义了 16 个 5×5 的卷积核,但每个核内部的具体数值(权重)在训练前是随机生成的。例如:
  • 第一个卷积核可能初始化为:
  • 第二个卷积核又是另一组随机值。
为什么随机?
因为深度学习的核心是通过数据训练调整这些权重,让卷积核学会 “检测特定特征”(如边缘、纹理)。如果初始值都相同,所有卷积核会学到完全一样的特征,模型就失去了多样性。

3. 训练过程:从随机到 “有意义”

训练时,模型通过反向传播算法不断调整这些随机权重,直到它们能提取出对任务(如图像分类)有帮助的特征。例如:
  • 某个卷积核可能最终学会检测 “水平边缘”;
  • 另一个可能学会检测 “圆形图案”。

二、kernel_size 只能指定方阵吗?

不是kernel_size 支持非方阵,但有两种写法:

1. 方阵写法(最常见)

当你写 kernel_size=5 时,Keras 会自动解析为 (5, 5)(即高和宽都是 5)。

2. 非方阵写法

你可以用元组指定不同的高和宽,例如:
# 使用 3×5 的矩形卷积核(高=3,宽=5)
tf.keras.layers.Conv2D(filters=16, kernel_size=(3, 5), activation='sigmoid')

3. 为什么常见方阵?

  • 计算效率:方阵在硬件(如 GPU)上的优化更成熟;
  • 对称性:对图像的水平和垂直方向同等处理,符合大多数视觉任务需求;
  • 经验验证:在 ImageNet 等大规模任务中,3×35×5 方阵表现优异,成为主流选择。

三、总结:卷积层参数的双重性

层面 固定参数(人为设置) 随机参数(训练学习)
结构 卷积核个数、空间尺寸(高 × 宽)
权重 每个卷积核内部的具体数值
理解这一点后,你可以更灵活地设计卷积层:
  • 用 kernel_size=(h, w) 定义矩形核;
  • 通过调整 filters 控制特征提取的丰富度;
  • 让模型通过训练自动学习卷积核的 “最佳形状”(权重分布)。
这种 “人为设计架构 + 数据驱动学习” 的组合,正是深度学习强大表达能力的来源~

问:也就是说,卷积核的形状我们初始化之后就不在变了,变的是里面的数值对吗?

在卷积神经网络(CNN)中,一旦定义好了卷积层,卷积核的形状就固定下来,在训练过程中保持不变,而变化的是卷积核里面的数值(权重参数) 。

卷积核数值的变化

虽然卷积核的形状固定不变,但卷积核中的数值(权重参数)是可学习的参数。在训练开始前,这些权重参数通常会按照一定的方式进行随机初始化,比如使用正态分布、均匀分布等。
在训练过程中,模型会根据输入数据和标签,通过反向传播算法计算损失函数对这些权重参数的梯度,然后使用优化器(如随机梯度下降、Adam 等)来更新权重参数。随着训练的进行,卷积核中的权重数值会不断调整,使得卷积核能够提取出对当前任务(如图像分类、目标检测等)有意义的特征。
例如,对于图像分类任务,经过多次迭代训练后,有的卷积核可能学会了检测图像中的边缘特征,有的可能学会了检测特定的纹理特征等。

总结

卷积核形状是模型架构层面的设定,在模型构建阶段确定后就保持稳定;而卷积核内部的数值作为可学习参数,在训练过程中不断更新优化,以适应训练数据,提升模型的性能和表现 。

 

posted @ 2025-06-29 18:10  指尖下的世界  阅读(52)  评论(0)    收藏  举报