CNN卷积神经网络

卷积神经网络CNN

卷积神经网络(Convolutional Neural Networks, CNN)的复杂性和灵活性使其成为深度学习领域的核心研究主题之一。

背景

卷积神经网络的灵感源自人类视觉系统,特别是视觉皮层中的神经元结构。自Hubel和Wiesel在1962年的开创性工作以来,这一理念已经引发了一系列研究和发展。

早期发展: 由Yann LeCun等人在上世纪80年代末到90年代初开发的LeNet-5被视为第一个成功的卷积神经网络。LeNet-5在手写数字识别方面取得了令人印象深刻的结果。

现代崛起: 随着硬件的快速进展和大数据的涌现,CNN在21世纪初开始重新崛起,并在各个领域实现了突破性进展。

CNN的重要性不仅体现在其精度和效率上,而且还体现在其理论洞见上。例如,卷积层通过共享权重减少了参数数量,这有助于更有效地训练模型,还增强了模型对平移不变性的理解。

结构大观

  1. 卷积层

    通过卷积操作检测图像的局部特征。

  2. 激活函数

    引入非线性函数,增加模型的表达能力。

  3. 池化层

    减少特征维度,增加模型的鲁棒性。

  4. 全连接层

    在处理空间特征后,全连接层用于进行分类或回归。

卷积神经网络的这些组件协同工作,使得CNN能够从原始像素中自动学习有意义的特征层次结构。随着深度增加,这些特征从基本形状和纹理逐渐抽象为复杂的对象和场景表现。img

卷积神经网络层

卷积神经网络由多个层组成,每个层具有特定的目的和功能。这一部分将探讨卷积操作、激活函数、池化层、归一化层基本概念。

什么是卷积

img

卷积操作可以理解为一个线性压缩的过程,通过卷积运算(对应元素相乘后求和)使得一个高维举矩阵降维。 \[ (I∗K)(i,j)=∑_m∑_nI(i−m,j−n)×K(m,n)\\ I是输入图像\\ K是卷积核\\ (i,j)是输出特征图的位置\\ (m,n)是卷积核中元素的位置\\ ∗ 表示卷积操作。 \]

卷积操作的附加与变体

  1. 标准卷积:最基本的卷积操作,涉及将卷积核覆盖在输入图像的局部区域上,对应元素相乘后求和。
  2. 步长(Stride):步长定义了卷积核在输入图像上滑动的间隔。步长为1意味着卷积核每次移动一个像素;步长更大则可以减少输出特征图的空间尺寸。
  3. 填充(Padding):在输入图像的边缘添加额外的零(零填充)或通过其他方式扩展输入图像,以控制输出特征图的大小。这有助于保留输入图像的边缘信息。
  4. 扩张卷积(Dilated Convolution):在扩张卷积中,卷积核的元素之间插入了间隙,这使得卷积核可以覆盖更大的输入区域,同时仍然保持较小的参数数量。
  5. 分组卷积(Grouped Convolution):在深度可分离卷积(Depthwise Separable Convolution)中,输入通道被分成多个组,每组使用独立的卷积核。这种方法可以减少参数数量和计算量。
  6. 转置卷积(Transposed Convolution):也称为分数步长卷积(Fractionally-strided Convolution),用于上采样,即增加特征图的空间尺寸。它通过对卷积核应用反向步幅来实现。
  7. 多尺度卷积(Multi-scale Convolution):在某些网络结构中,输入图像的不同尺度版本被同时应用于卷积核,以捕获不同尺度的特征。
  8. 空洞卷积(Atrous Convolution):在空洞卷积中,卷积核的元素之间可以有更大的间隙,这允许网络以更低的计算成本捕获更广泛的上下文信息。
  9. 卷积变体:除了标准卷积,还有许多变体,如1x1卷积,用于在深度方向上进行线性变换,以及分离卷积等。
  10. 激活函数:在卷积操作之后,通常会应用一个非线性激活函数,如ReLU,以增加模型的非线性能力。

什么是卷积核,特征映射

卷积核是一个小型的矩阵,通过在输入上滑动来生成特征映射。每个卷积核都能捕获不同的特征,例如边缘、角点等。

img

输出特征图m与输入图片n维度关系是 \[ m = n - k + 1\ (k为卷积核维度) \] 这是一个十分简化的公式,它假定输入图片与卷积核均为方阵。但对于非方阵来说,实际上相当于将n,m以对应行列数代换即可。此处仅适用于步长为1,步长不为1的情况需要考虑是否有填充零。

感受野

感受野(Receptive Field)是神经网络中一个重要的概念,特别是在卷积神经网络(CNN)中。它指的是网络中一个神经元能够“看到”或影响的输入数据的空间范围。换句话说,它是输入图像中一个给定的像素点到网络中某个特定神经元的映射区域,这个区域包含了该神经元进行特征检测所需的所有像素。

卷积核的大小如何设置,有何关系

卷积核的大小影响了它能捕获的特征的尺度。较小的卷积核可以捕获更细致的特征,而较大的卷积核可以捕获更广泛的特征。

1
2
3
4
# 使用3x3的卷积核
conv_layer_small = nn.Conv2d(3, 64, 3)
# 使用5x5的卷积核
conv_layer_large = nn.Conv2d(3, 64, 5)

多通道卷积

在多通道输入下进行卷积,每个输入通道与一个卷积核进行卷积,然后所有的结果相加。这允许模型从不同的通道捕获不同的特征。

步长与填充

设定不同的步长

1
2
# 使用步长为2
cov_layer_stride2=nn.Conv2d(3,64,3,stride=2)

填充通过在输入边缘添加零来控制输出的尺寸。这有助于控制信息在卷积操作中的丢失。

1
2
# 使用填充1,使得输出尺寸与输入尺寸相同(假设步长为1
conv_layer_padding1 = nn.Conv2d(3, 64, 3, padding=1)

空洞卷积

空洞卷积也称扩展卷积或带空间及,它通过在卷积核的元素之间插入空间采样点(通常是0)来扩大卷积核的感受野。

这种方法允许网络在保持相同参数量和计算量的情况下捕获更广泛的上下文信息,特别适用于需要大感受野的场景,如语义分割、目标检测等任务。

分组卷积

分组卷积通过将输入通道分组并对每组使用不同的卷积核来扩展卷积操作。这增加了模型的容量,并使其能够学习更复杂的表示。

在分组卷积中,输入特征图(Feature Maps)和卷积核被分成多个组(groups),每组独立进行卷积运算。具体来说,如果输入特征图的尺寸是 \(W×H×C_1\),并且我们设定要将其分为 \(g\) 个组,那么每组的输入特征通道数为 \(\frac{C_1}{g}\)。相应地,每个卷积核也被分为 \(g\)组,每组卷积核的尺寸变为\(k\times k \times \frac{C_1}{g}\)\(C_2\)表示输出通道的通道数,并且每组有 \(\frac{C_2}{g}\)个卷积核,最终每组生成 \(\frac{C_2}{g}\)个输出特征图 。

  1. 在进行分组卷积后输出的特征图的通道数并没有改变
  2. 在进行分组卷积后,在同等的卷积核数量下,参数减少到了原来的\(\frac{1}{g}\)

激活函数

img

池化层

池化层(Pooling Layer)在卷积神经网络中扮演了重要角色,通常用于降低特征映射的维度,从而减少计算需求,并增加特征检测器的感受野。

最大池化

img最大池化是最常用的池化技术之一。它通过选择窗口中的最大值来降低特征映射的尺寸。

1
2
# 使用PyTorch定义2x2的最大池化层
max_pooling = nn.MaxPool2d(2)

最大池化的主要优点是它能保留窗口中的最显著特征。然而,它会丢失一些细节信息。

平均池化

与最大池化不同,平均池化使用窗口中所有值的平均值。

1
2
# 使用PyTorch定义2x2的平均池化层
average_pooling = nn.AvgPool2d(2)

平均池化可以减轻最大池化可能导致的过于突出某些特征的问题,但可能会淡化一些重要特征。

全局平均池化

全局平均池化是一种更复杂的池化策略,它计算整个特征映射的平均值。这常用于网络的最后一层,直接用于分类。

1
2
# 使用PyTorch定义全局平均池化层
global_average_pooling = nn.AdaptiveAvgPool2d(1)

池化窗口大小和步长

池化窗口的大小和步长会直接影响输出的尺寸。较大的窗口和步长会更显著地降低尺寸。

池化的替代方案

池化层已经有了一些现代替代方案,例如使用卷积层的步长大于1,或使用空洞卷积。这些方法可能提供更好的特征保存。

池化层的选择

选择特定类型的池化层取决于任务需求和特定数据特性。深入理解各种池化技术如何工作,可以帮助深入理解它们是如何影响模型性能的。

归一化层

img

归一化层在训练深度神经网络时扮演了关键角色,主要用于改善训练的稳定性和速度。通过将输入数据缩放到合适的范围,归一化层有助于缓解训练过程中的梯度消失梯度爆炸问题。

批量归一化

通过对每个特征通道的输入进行归一化,将输入所梵高零均值和单位方差。

1
2
# 使用PyTorch定义批量归一化层
batch_norm = nn.BatchNorm2d(num_features=64)

优势与劣势

  • 优势:它允许更高的学习率,提供了一些正则化效果,通常导致更快的训练。
  • 劣势:在小批量上的统计估计可能会导致训练和推理间的不一致。

层归一化(LN)

层归一化是在单个样本上对所有特征进行归一化的变体。它在句子处理和循环神经网络中特别流行。

1
2
# 使用PyTorch定义层归一化
layer_norm = nn.LayerNorm(normalized_shape=64)

LN的计算方法是对一个样本内所有神经元的输出进行归一化处理,使得这一层的输出具有稳定的均值和方差。具体来说,对于一个隐藏层中的所有激活值\(a_i^l\),LN首先计算这些激活值的均值 μ和标准差 σ,然后利用以下公式进行归一化: \[ \mu = \frac{1}{H} \sum_{i=1}^{H} a_i \]

\[ \sigma^2 = \frac{1}{H} \sum_{i=1}^{H} (a_i - \mu)^2 \]

H表示该层的隐藏单元数。诡异话后通过可学习参数\(\gamma\ \beta\)进行缩放和平移,以适应数据分布 \[ \text{output}_i = \gamma \hat{a}_i + \beta \]

实例归一化

实例归一化主要用于样式转换任务,归一化是在每个样本的每个通道上独立进行的。

1
2
# 使用PyTorch定义实例归一化
instance_norm = nn.InstanceNorm2d(num_features=64)

组归一化

组归一化是批量归一化和层归一化之间的一种折衷方案,将通道分为不同的组,并在每个组内进行归一化。

1
2
# 使用PyTorch定义组归一化
group_norm = nn.GroupNorm(num_groups=32, num_channels=64)

归一化层的选择

归一化层的选择应基于特定的任务和模型架构。例如,在视觉任务中,批量归一化可能是首选,而在NLP任务中,层归一化可能更有用。

训练与优化

训练集的准备与增强

有效的训练数据是深度学习成功的基础。为了使卷积神经网络有效学习,训练集的选择和增强至关重要。

数据预处理

预处理是训练集准备的关键步骤,包括:

  • 标准化:将输入缩放到0-1范围。
  • 中心化:减去均值,使数据以0为中心。
  • 数据清洗:消除不一致和错误的数据。

数据增强

数据增强是一种通过应用随机变换增加数据量的技术,从而增加模型的泛化能力。

常见增强技巧

  • 图像旋转、缩放和剪裁
  • 颜色抖动
  • 随机噪声添加
1
2
3
4
5
6
7
# 使用PyTorch进行多种图像增强
from torchvision import transforms
transform = transforms.Compose([
transforms.RandomRotation(10),
transforms.RandomResizedCrop(224),
transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1)
])

训练集分割

通常将数据分为训练集、验证集和测试集,以确保模型不会过拟合。

损失函数

损失函数衡量模型预测与真实目标之间的差距。选择适当的损失函数是优化模型性能的关键步骤。

均方误差(MSE)

衡量预测值与真实值之间的平方差

常用于连续值预测

1
2
# 使用PyTorch定义MSE损失
mse_loss = nn.MSELoss()

平滑L1损失

  • 平滑L1损失:减少异常值的影响。

交叉熵损失

  • 交叉熵损失:衡量预测概率分布与真实分布之间的差异。
1
2
# 使用PyTorch定义交叉熵损失
cross_entropy_loss = nn.CrossEntropyLoss()
  • 二分交叉熵损失:特别用于二分类任务
  • 多标签损失:用于多标签分类问题

优化损失函数

选择适当的损失函数不仅取决于任务类型,还与模型架构、数据分布和特定的业务指标有关。有时,自定义损失函数可能是必要的,以便捕捉特定问题的核心挑战。

优化器

优化器用于更新神经网络的权重,以便最小化损失函数。每种优化器都有其特定的数学原理和应用场景。

随机梯度下降(SGD)

SGD是最基本的优化算法。

  • 基本SGD: 按照负梯度方向更新权重。
  • 带动量的SGD: 引入动量项,积累之前的梯度,以便更平稳地收敛。
1
2
# 使用PyTorch定义带动量的SGD优化器
optimizer_sgd_momentum = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

自适应优化器

自适应优化器能自动调整学习率。

  • Adam: 结合了Momentum和RMSProp的优点。
1
2
# 使用PyTorch定义Adam优化器
optimizer_adam = torch.optim.Adam(model.parameters(), lr=0.001)
  • Adagrad、RMSprop等: 针对不同参数有不同的学习率。

优化器选择注意事项

  • 任务相关性: 不同优化器在不同任务和数据上可能有不同的效果。
  • 超参数调优: 如学习率、动量等可能需要调整。

学习率调整

学习率是优化器中的关键超参数,其调整对模型训练有深远影响。

固定学习率

最简单的方法是使用固定学习率。但可能不够灵活。

学习率调度

更复杂的方法是在训练过程中动态调整学习率。

预定调整
  • 步骤下降: 在固定步骤处降低学习率。
  • 余弦退火: 周期性调整学习率。
1
2
# 使用PyTorch定义余弦退火调度器
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer_adam, T_max=50)

正则化技巧

正则化是防止过拟合和提高模型泛化能力的关键技术。

L1和L2正则化

  • L1正则化:倾向于产生稀疏权重,有助于特征选择。
  • L2正则化:减小权重,使模型更平滑。
1
2
3
4
# 使用PyTorch添加L1L2正则化
l1_lambda = 0.0005
l2_lambda = 0.0001
loss = loss + l1_lambda * torch.norm(weights, 1) + l2_lambda * torch.norm(weights, 2)

Dropout

随机关闭一部分神经元,使模型更鲁棒。

  • 普通Dropout:随机丢弃神经元。
  • Spatial Dropout:在卷积层中随机丢弃整个特征图。

Batch Normalization

通过标准化层输入,加速训练并减轻初始化的敏感性。

数据增强

如前所述,数据增强是一种重要的正则化手段。

模型评估和调优

模型评估是衡量模型性能的过程,调优则是改进性能。

交叉验证

使用交叉验证来估计模型的泛化能力。

  • k-折交叉验证:将数据分为k个部分,轮流使用其中一个作为验证集。

调参技巧

  • 网格搜索:尝试不同超参数组合。
  • 随机搜索:随机选择超参数,更高效。

早停技巧

如果验证损失不再下降,则停止训练,以防止过拟合。

模型集成

通过结合多个模型来提高性能。

  • Bagging:训练多个模型并平均预测。
  • Boosting:在先前模型的错误上训练新模型。
  • Stacking:使用新模型组合其他模型的预测。

实践与CNN模型编写

下面使用CNN编写一个简单的句子分类器

字词为何要数据化,怎样数据化的?

字词需要数据化,因为计算机和机器学习模型只能处理数值型数据。数据化(也称为特征提取或向量化)是将原始文本转换为模型可以理解和处理的数值形式的过程。以下是将字词数据化的常见步骤:

  1. 分词(Tokenization)

    将句子分解成单独的单词或标记(tokens),这些单词或标记是数据化的基本单位。

  2. 构建词汇表(Vocabulary)

    从训练数据中提取所有唯一的单词,并为每个单词分配一个唯一的索引或ID。

  3. 词嵌入(Word Embedding)

    使用预训练的词向量模型(如word2vec、GloVe或BERT)将每个单词转换为固定大小的向量。这些向量捕捉了单词的语义和语法特征。

  4. 索引化(Indexing)

    由于句子长度可能不同,通常需要将句子填充到相同的长度,以便能够批量处理。这通常涉及到在句子末尾添加特殊的“填充”标记。

  5. 序列化(Sequencing)

    将填充后的句子转换为数值序列,每个位置对应一个单词的数值索引或词嵌入向量。

  6. 特殊标记(Special Tokens)

    在某些模型中,可能会使用特殊的开始(如<BOS>)和结束(如<EOS>)标记来标记句子的开始和结束。

  7. 转换为张量(Tensorization)

    将数值序列转换为可以被深度学习框架处理的张量(多维数组)

  8. 上下文化(Contextualization)

    在某些模型中,如Transformer或BERT,单词的表示不是静态的,而是根据它们在句子中的上下文动态生成的。

  9. 归一化(Normalization)

    有时,为了提高模型性能,会将词嵌入向量进行归一化处理,使它们具有单位长度。

需要准备的第三方包

安装依赖

旧版依赖安装已废弃,请阅读CNN补充-pyTorch中有关异常处理的安装问题中的版本控制处理。

  1. Numpy:适用于多维数组方面的数学运算
  2. pyTorch:深度学习框架库,提供了构建和训练神经网络所需的工具与函数

使用pip安装

1
2
pip install numpy # 安装numpy
pip install torch # 安装pyTorch

验证是否安装成功

1
2
3
4
import torch
import numpy
print(numpy.__version__)
print(torch.__version__)
1
2
3
4
5
6
>>> import torch
>>> import numpy
>>> print(numpy.__version__)
>>> 1.26.4
>>> print(torch.__version__)
>>> 2.4.0+cpu

下载所需数据集

分别是情感分析数据集(MR, SST-1, SST-2)或问题分类数据集(TREC)。

以下内容与GithubCNN-NLP学习系列内容重复,等待整理或异步GithubCNN-NLP学习

模型构建

卷积层
神经网络层

……

训练与预测函数

训练函数
验证函数
番外
  1. 一般在同文件中写入所有模型所需函数,例如预测函数(单测试数据输出)、参数保存函数

……

日志记录与参数保存

…….

参考文献

  1. 头疼!卷积神经网络是什么?CNN结构、训练与优化一文全解-腾讯云开发者社区-腾讯云 (tencent.com)
  2. Convolutional Neural Networks for Sentence Classification.pdf