4.初识分类
2026/9/12 16:11:19 网站建设 项目流程

0. 回顾

主要掌握了全连接。 代码写作 nn.linear(A, B)。

它的作用是将矩阵从 A维度转为B维度。

比如 输入有4个变量, 回归任务, 需要输出1个值。 就使用: nn.linear(4, 1)

一个(16,4) 的矩阵 经过nn.linear(4, 1) 会转为 (16,1)

但是想中间多算几次, 加深网络加强效果。 可以 nn.linear(4, 64)- nn.linear(64, 1)

还有梯度下降算法

神经网络训练流程的几个模块:模型,数据,超参,训练过程

1.分类输出

现实中有很多问题并不是预测问题。

比如:

根据一封邮件的内容判断它是否是垃圾邮件。

根据两个人的样貌判断是否为直系亲属。

判断一个图片里的动物是鸟还是人,还是猫,狗。

以上都是分类任务

我们可以像回归任务那样输出一个值吗?

Linear (?,1)

根据值差判断类别可以吗?

比如得到预测值为1.3,有1,2,3三个类别

如果把1.3归为第一类,那么1.3与2相距0.7,与3相距1.7,可以说1.3比起第三类更像第二类吗?

显然不对

所以,我们不能只输出一个值,而是输出每种类别的概率,取最大

然后对于标签值,只在正确类别标1,其余标0,这样就可以求loss

2.图片输入处理

我们上次的数据是一些数字,直接转化为矩阵输入

那么其实图片也是这样的

图片有三个通道,R,G,B代表red,green,blue

2.1 卷积

3*224*224的图片,直接拉直?

那么最后进入全连接就是

linear(3*224*224,1000)

数据量实在太大,需要减小数据量

所以引入卷积来减少输入---去掉部分不重要的数据

我们人眼相当于制作一个框,框大小为9,依次比对,框扫过每行每列得到答案

(其实并不一定严格按照顺序)

卷积核的原理就是这样

将红色设为1,黑色设为-1

进行卷积,如果完全一致,那么就会得到9

我们识别图片的物体类别,完全不需要关注图片每一个部分,只需要小部分特征就好

那么怎么确定这个卷积核就代表鸟嘴?

这其实就是训练的目标,我们训练过程,就是在训练这个卷积核,就是在找什么样的卷积核适配鸟嘴

如果我们不想卷积将我们图片特征图变得越来越小,那么就可以加入padding

在周围加一圈0

从左侧一开始的深度为3的原始特征图,到右侧深度为5的新特征图,需要经过一个卷积层

原始特征图的深度就是卷积核的深度,卷积核的个数就是新特征图的深度

原始特征图是输入,不是参数;新特侦图是输出,不是参数。

卷积核是参数

这里参数量为5*3*3*3,即个数*深度**

以下是一些训练

  1. 3*3 、2*2
  2. 2*2
  3. 4*4
  4. 98*98
  5. 100*100
  6. 2*2、7*7
  7. 94*94

第二套

  1. 3
  2. 224*224
  3. 3*3*3、27
  4. 7*4*4
  5. 64*224*224
  6. 128*224*224、64、128*64*3*3

2.2 池化(Pooling)

特征图一直大小不变, 你怎么卷参数展平后都需要大量参数。

有两个方法减小特征图大小

原理:一条线上的点去掉一般,线基本不变

但是相较于增大步长,一般更青睐于池化

池化中一般更青睐最大池化,因为深度学习中越简单越好

●一张图片通常被转换为3*224*224.

●你能将其变为1024*7*7么?

●最少一次卷积就可以。 但在实战中, 常常卷积和池化相应变化。

● 3 * 224*224 -> 64*224*224 ->(128 * 224*224)->128*112*112

● –> 256*56*56 -> 512 * 28*28 -> 1024 * 14*14 ->1024*7*7

最后要输出一个类别,那么就要将特征图拉直输入全连接

2.3 loss

通过softmax,将输出值大小变为概率大小

使用交叉熵损失

例如

总体来看如下

和回归网络有很大相似之处

所以要训练,需要大量带标签的图片

3.图像分类网络历史

sota模型:sort state of the art

达到了艺术状态

3.1 AlexNet

现代神经网络热潮的开始 AlexNet

归一化可以在深度学习的各个角落看到。

它可以让模型关注数据的分布,而不受数据量纲的影响。

归一化可以 保持学习有效性, 缓解梯度消失和梯度爆炸。

Dropout 可以缓解 过拟合

计算特征图的变化过程

ps1:pool(3,2) 三个一组,步长为2

比如1234567

先在123中取3

再在345中取5

pool对特征图的影响主要看步数

ps2:向下取整

3*224*224->

64*54*54->64*27*27->

192*27*27->192*13*13->

384*13*13-3->256*13*13->256*13*13->

256*6*6->256*6*6->

9216->4096->4096->1000

下面是自己写一个alexnet

import torch.nn as nn class my_model(nn.Module): def __init__(self): super(my_model, self).__init__() self.conv1 = nn.Conv2d(3, 64, 11, stride=4,padding=2) self.pool1 = nn.MaxPool2d(3, 2) self.relu1 = nn.ReLU() self.conv2 = nn.Conv2d(64, 192, 5, padding=2) self.pool2 = nn.MaxPool2d(3, 2) self.relu2 = nn.ReLU() self.conv3 = nn.Conv2d(192, 384, 3, padding=1) self.conv4 = nn.Conv2d(384, 256, 3, padding=1) self.conv5 = nn.Conv2d(256, 256, 3, padding=1) self.pool3 = nn.MaxPool2d(3, 2) self.relu3 = nn.ReLU() self.pool4 = nn.AdaptiveAvgPool2d(6) self.relu4 = nn.ReLU() self.fc1 = nn.Linear(256 * 6 * 6, 4096) self.relu5 = nn.ReLU() self.fc2 = nn.Linear(4096, 4096) self.relu6 = nn.ReLU() self.fc3 = nn.Linear(4096, 1000) def forward(self, x): x = self.conv1(x) x = self.relu1(x) #注意激活函数也要定义 x = self.pool1(x) x = self.pool2(self.relu2(self.conv2(x))) x = self.conv3(x) x = self.conv4(x) x = self.conv5(x) x = self.pool3(self.relu3(x)) x = self.pool4(self.relu4(x)) x = x.view(x.size()[0], -1) # 将数据拉平,x.size()[0]表示batchsize,-1表示自动算出剩下的维度,flatten x=self.relu5(self.fc1(x)) x=self.relu6(self.fc2(x)) x=self.fc3(x) return x import torch model=my_model() img=torch.zeros((4,3,224,224)) y=model(img) print(y.shape)

3.2 VGG

为什么要用小的卷积核代替大的呢?

节省参数量

图中5*5的卷积核与两个3*3的卷积核感受野一样大

但是参数量

5*5=25

2*3*3=18

节省了25-18=7

3*224*224->

64*224*224->64*224*224->64*112*112-> 参数量:64*3*3*3、64*64*3*3

128*112*112->128*112*112->128*56*56-> 参数量:128*64*3*3、128*128*3*3

256*56*56->256*56*56->256*28*28-> 参数量:256*128*3*3、256*256*3*3

512*28*28->512*28*28->512*14*14-> 参数量:512*256*3*3、512*512*3*3

512*14*14->512*14*14->512*7*7->参数量:512*512*3*3、512*512*3*3

512*7*7->

25088->4096->4096->1000

vgg中有很多重复的子模块

所以可以类套类来写

import torch.nn as nn class vgglayer(nn.Module): def __init__(self,in_channels,out_channels): super().__init__() #等于super(vgglayer, self).__init__() self.conv1 = nn.Conv2d(in_channels, out_channels, 3, padding=1) self.conv2 = nn.Conv2d(out_channels, out_channels, 3, padding=1) self.pool1 = nn.MaxPool2d(2) self.relu1 = nn.ReLU() def forward(self,x): x = self.conv1(x) x = self.relu1(x) x = self.conv2(x) x = self.relu1(x) x = self.pool1(x) return x class myvgg(nn.Module): def __init__(self): super(myvgg, self).__init__() self.layer1 = vgglayer(3,64) self.layer2 = vgglayer(64,128) self.layer3 = vgglayer(128,256) self.layer4 = vgglayer(256,512) self.layer5 = vgglayer(512,512) self.pool1 = nn.AdaptiveAvgPool2d(7) self.relu1 = nn.ReLU() self.fc1 = nn.Linear(25088,4096) self.relu2 = nn.ReLU() self.fc2 = nn.Linear(4096,4096) self.relu3 = nn.ReLU() self.fc3 = nn.Linear(4096,1000) def forward(self,x): x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) x = self.layer5(x) x = self.pool1(x) x = x.view(x.size()[0], -1) x = self.relu2(self.fc1(x)) x = self.relu3(self.fc2(x)) x = self.fc3(x) return x def get_parameter_number(model): total_num = sum(p.numel() for p in model.parameters()) trainable_num = sum(p.numel() for p in model.parameters() if p.requires_grad) return {'Total': total_num, 'Trainable': trainable_num} import torch myVgg = myvgg() img = torch.zeros((1, 3, 224,224)) out = myVgg(img) print(get_parameter_number(myVgg)) print(get_parameter_number(myVgg.layer1)) print(get_parameter_number(myVgg.layer1.conv1))

3.3 ResNet

创新在于残差连接和1*1卷积

残差连接用来防止梯度消失

1*1卷积用来改变维度数

如图,在卷积过程中使用1*1卷积,可以节省参数量

残差连接起作用的原因

在深层网络中,对于浅层网络的偏导是要通过很多层的偏导

如果每一层偏导小于1,那么乘下来对于浅层几乎等于0

如果每一层偏导大于1,那么乘下来对于浅层几乎等于无穷

由于加上了x,求偏导一定大于1,所以缓解了梯度消失

可以更新浅层网络

如果维度一样直接加,

如果不一样使用1*1卷积,调整步数

4. 透析

4.1 真正的推动者

4.2 卷积和全连接的关系

卷积是一个参数共享不全连接

显著缩小参数量

4.3 玩特征

5.总结

深度学习还是多尝试,它是一个黑盒子

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询