CNN的基本概念、常用的计算公式和pytorch代码

本文围绕CNN展开,介绍了其基本概念,如卷积、池化和激活函数的作用;阐述常见卷积类型及输入输出尺寸计算公式;讲解常用激活函数、标准化和归一化方法;还涉及模型保存加载、model.eval()和with torch.no_grad()区别、微调方式以及评价指标等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


一、CNN的基本概念

卷积填充池化参考此处
激活函数参考此处
简言之:
卷积有助于我们找到特定的局部图像特征。
池化是用于特征融合和降维,还可以防止过拟合。
激活函数是增加非线性,主要是为了解决梯度消失和梯度爆炸问题

二、常见的卷积

参考此处

1.一般卷积

这个就是最常见的卷积了,看动图比较容易理解。
在这里插入图片描述

2.扩张卷积(空洞卷积)

这个主要用来扩大感受野,改变扩张率可获得多尺度信息。

3.转置卷积(反卷积)

就是卷积的逆过程做还原(恢复尺寸不恢复值),比如要可视化、分割还原、gan生成等。

4.可分离卷积

可分离卷积主要可分为空间可分离卷积和深度可分离卷积。

4.1.空间可分离卷积

用2个1D卷积核代替1个2D卷积核得到同样的结果,这样减少了计算量。

4.2.深度可分离卷积

对N通道分别进行卷积后,再对这个输出做一个pointwise核(11N)卷积,这样也减少了计算量。

11的卷积核可以降维、增加模型深度以及增加非线性。
N
N的卷积核可以

三、CNN的输入输出尺寸计算公式

3.1.卷积层

N=(W-F+2P)/S + 1
其中
N:输出大小
W:输入大小
F:卷积核大小
P:填充值的大小
S:步长大小

如当W=256,F=3,P=1,S=2时,N=(256-3+2*1)/2+1=128

3.2.池化层

N=(W+2P-D(F-1)-1)/S + 1
其中
N:输出大小
W:输入大小
D:空洞
F:池化核大小
P:填充值的大小
S:步长大小
*
如当W=128,D=0, F=2,P=0,S=2时,N=(128+0-0-1)/2+1=64
当分子为奇数时,无论分母是1还是2,分子在最后算的时候都会取为偶数

四、CNN常用的激活函数

4.1.Sigmoid

计算公式:
在这里插入图片描述
函数图像:
在这里插入图片描述
导数图像:
在这里插入图片描述

4.2.tanh

计算公式:在这里插入图片描述
函数图像:
在这里插入图片描述

导数图像:
在这里插入图片描述

4.3.Relu

计算公式:
在这里插入图片描述
函数图像:
在这里插入图片描述
导数图像:
在这里插入图片描述

此外,还有LeakRelu、ERelu、Silu等。

五、标准化和归一化

参考此处

1.标准化

将数据变换为均值为0,标准差为1的分布

1.1.批标准化(Batch Normalization)

每个激活函数都有自己的非饱和区,在激活函数前如果没有BN的话,在非饱和区外的数据都会导致梯度消失,只有非饱和区的数据可用,也加快收敛,防止了过拟合,所以一般会在激活函数前加入BN。

2.归一化

将数据变换到某个区间范围,如[0,1]
在这里插入图片描述
总结:归一化是根据极小极大值缩放范围的,从这个定义出发,看自己的数据是否需要这样处理
标准化相比更常见,如在梯度计算时能加快收敛速度,处理不同尺度的特征等

六、保存和加载模型

1.仅保存学习到的参数

1.1.保存模型:torch.save(model.state_dict(), PATH)

1.2.调用模型:model.load_state_dict(torch.load(PATH));model.eval()

2.保存整个model

2.1.保存模型:torch.save(model,PATH)

2.2.调用模型:model = torch.load(PATH)

七、model.eval()和with torch.no_grad()的作用和区别

参考此处
在train模式下,dropout网络层会按照设定的参数p设置保留激活单元的概率(保留概率=p); batchnorm层会继续计算数据的mean和var等参数并更新。

在val模式下,dropout层会让所有的激活单元都通过,而batchnorm层会停止计算和更新mean和var,直接使用在训练阶段已经学出的mean和var值

model.eval()中的数据不会进行反向传播,但是仍然需要计算梯度。
with torch.no_grad()中的数据不需要计算梯度,也不会进行反向传播。

可以看到测试要用model.eval()模式,加上with torch.no_grad()能更节省计算资源

八、Copy

赋值:内存地址不变,相当于引用,一改都改。
copy.copy():浅复制,增加元素没影响,但改变共有的元素则原数据也改变。
copy.deepcopy():深复制,就是完全复制,包括内存地址都是新的。

九、微调

参考此处
什么情况下可以微调呢?
(1) 你要使用的数据集和预训练模型的数据集相似
(2) 自己搭建或者使用的CNN模型正确率太低。
(3)数据集相似,但数据集数量太少。
(4)计算资源太少。
根据自己的数据判断是否需要预训练

针对不同情况,也有不同的微调方式:
数据集1 - 数据量少,但数据相似度非常高 - 在这种情况下,我们所做的只是修改最后几层或最终的softmax图层的输出类别。

数据集2 - 数据量少,数据相似度低 - 在这种情况下,我们可以冻结预训练模型的初始层(比如k层),并再次训练剩余的(n-k)层。由于新数据集的相似度较低,因此根据新数据集对较高层进行重新训练具有重要意义。

数据集3 - 数据量大,数据相似度低 - 在这种情况下,由于我们有一个大的数据集,我们的神经网络训练将会很有效。但是,由于我们的数据与用于训练我们的预训练模型的数据相比有很大不同。使用预训练模型进行的预测不会有效。因此,最好根据你的数据从头开始训练神经网络(Training from scatch)

数据集4 - 数据量大,数据相似度高 - 这是理想情况。在这种情况下,预训练模型应该是最有效的。使用模型的最好方法是保留模型的体系结构和模型的初始权重。然后,我们可以使用在预先训练的模型中的权重来重新训练该模型。

1.冻结

参考此处
冻结就是让某些层不反向传播:

for layer in list(model.parameters())[:]:#这里就写你要要冻结的层
	layer.requires_grad = False #这里不计算梯度
optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=0.0001)#过滤掉不需要反向传播的层

解冻:

for layer in list(model.parameters())[:]:
    layer.requires_grad = True
	optimizer.add_param_group({'params': layer})

2.修改层

查看model的结构后,得到的是
model(
    (feature):Sequential(
        (0):Conv(
        (conv):Conv2d(3,24,kernel_size=(3,3),stride=(2,2),padding=(1,1),bias=False)
        …
        )
        …
        …
    (fc):Sequantial(
        (0):Dropout(p=0.3,inplace=True)
        (1):Linear(in_features=1792,out_features=1000,bias=True)
        )
    )

比如你要修改fc层,类别从1000改为10:

model.fc = nn.Linear(1792,10)

那么输出的fc层就是
(fc):Sequantial(
    (0):Dropout(p=0.3,inplace=True)
    (1):Linear(in_features=1792,out_features=1000,bias=True)

十、评价指标

参考此处
TP: 预测为1(Positive),实际也为1(Truth-预测对了)
TN: 预测为0(Negative),实际也为0(Truth-预测对了)
FP: 预测为1(Positive),实际为0(False-预测错了)
FN: 预测为0(Negative),实际为1(False-预测错了)
总样本数为:TP+TN+FP+FN

一般直接看到的是准确率Accuracy=(TP+TN)/(TP+TN+FP+FN)

查准率Precision = TP/(TP+FP)

查全率Recall = TP/(TP+FN)

F1 = 2*(PrecisionRecall)/(Precision+Recall)=2TP/(2*TP+FP+FN)
AR = TP/(TP+FP)

### 卷积神经网络 (CNN) 的公式推导与解释 #### 前向传播过程中的卷积操作 在卷积层中,输入图像 \( X \in R^{H_{\text{in}} \times W_{\text{in}}} \) 滤波器(或称为核)\( K \in R^{k_h \times k_w} \),其中 \( H_{\text{in}}, W_{\text{in}} \) 表示输入的高度宽度;而 \( k_h, k_w \) 则表示滤波器的高度宽度。卷积的结果可以被定义为: \[ Z(i,j)=\sum _{{m=0}}^{{k_{{h}}-1}}\sum _{{n=0}}^{{k_{{w}}-1}}X(i+m,j+n)\cdot K(m,n)+b \] 这里 \( b \) 是偏置项[^1]。 为了简化表达,在实际应用中通常会引入零填充(padding),使得输出尺寸保持不变或者按照需求调整大小。另外步幅(stride) s 控制着每次移动的距离,从而影响最终特征图的分辨率。 #### 反向传播过程中误差梯度计算 当涉及到反向传播时,目标是在给定损失函数 L 下更新模型参数 θ 。对于卷积层而言,主要关注的是如何高效地计算相对于权重矩阵 W 偏差向量 b 的梯度 ∂L/∂W ∂L/∂b ,以及输入激活 A_prev 对应位置上的梯度 ∂A_prev/∂Z 。 假设当前正在处理第 l 层,则有如下关系成立: \[ dA\_prev = W * dZ + pad(0), \quad dB = sum(dZ,axis=(0,1)),\\ dW=\delta ^{(l)}*A^{(l-1)}, \quad db=sum(\delta ^{(l)}) \] 这里的 δ^(l) 表达了本层关于成本 J 的敏感程度即所谓的“残差”,它通过链式法则由后续各层传递而来并乘以前一层输出得到新的 Δ 权重用于修正原有值[^4]。 #### 参数优化方法 一旦获得了上述提到的各种梯度信息之后就可以采用诸如随机梯度下降(SGD)这样的迭代方式来最小化整体的目标函数 E : \[ w := w-\eta\nabla f(w) \] η 称作学习率决定了每一步前进的步伐长度,适当调节该超参有助于加快收敛速度同时避免陷入局部极小点附近震荡不定的情况发生。 ```python import torch.nn as nn class SimpleCNN(nn.Module): def __init__(self): super().__init__() self.conv_layer = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3) def forward(self, x): return self.conv_layer(x) ```
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值