目录
一、LeNet
1、产生由来,是当时想要识别邮政上的邮编,然后投递到对应位置,节省人力
卷积层的处理方法,我们可以在图像中保留空间结构。 同时,用卷积层代替全连接层的另一个好处是:模型更简洁、所需的参数更少。
LeNet,它是最早发布的卷积神经网络之一,因其在计算机视觉任务中的高效性能而受到广泛关注。 这个模型是由AT&T贝尔实验室的研究员Yann LeCun在1989年提出的(并以其命名),目的是识别图像 (LeCun et al., 1998)中的手写数字。
2、这个项目带来的一个很有用的数据集
3、LeNet:里面两个卷积层,两个池化层,然后使用全连接,120再到84,最后使用高斯激活
请注意,虽然ReLU和最大汇聚层更有效,但它们在20世纪90年代还没有出现。每个卷积层使用5×5卷积核和一个sigmoid激活函数。这些层将输入映射到多个二维特征输出,通常同时增加通道的数量。
为了将卷积块的输出传递给稠密块,我们必须在小批量中展平每个样本。换言之,我们将这个四维输入转换成全连接层所期望的二维输入。
4、总结,好像看着挺简单的,但是前人能想出这样的方法真是不可思议,好聪明,下面代码实现有21min,加油!!!
二、代码实现
1、LeNet由两个部分组成:卷积编码器和全连接密集块
2、x.view(-1,1,28,28),这里的 -1 指的是批量数不变,自动计算;不直接用reshape是因为这样可以放到nn.sequential里面;(批量数,通道数,行,列);批量数不变,通道数为1
3、Flatten是保留第一维批量维度的情况下,其他维度全部展平
4、mnist原始数据是28*28,这里加了padding就能实现论文里说的输入32*32了吧
5、建立LeNet:
- 首先你要先reshape一下,将你的向量变成x.view(-1,1,28,28);
- 卷积层,(1,6,kernel_size =5,padding=2),输入通道是1,输出通道是6; 输出的大小是(28+4-5+1)/1 ,(28*28);再sigmoid一下
- 平均池化,(kernel_size=2,stride=2) ;输出大小,(28+0-2+2)/2 ,(14*14)
- 卷积,(6,16,kernel_size =5);输出大小,(14+0-5+1)/1 ,(10*10);再sigmoid一下
- 平均池化,(kernel_size=2,stride=2);输出大小,(10+0-2+2)/2 ,(5*5);做了一下flatten,展平了;
- 多层感知机,第一层,nn.Linear(16*5*5,120);再sigmoid一下
- 多层感知机,第二层,nn.Linear(120,84);再sigmoid一下
- 多层感知机,第三层,nn.Linear(84,10);
在整个卷积块中,与上一层相比,每一层特征的高度和宽度都减小了。
第一个卷积层使用2个像素的填充,来补偿5×5卷积核导致的特征减少。
相反,第二个卷积层没有填充,因此高度和宽度都减少了4个像素。
随着层叠的上升,通道的数量从输入时的1个,增加到第一个卷积层之后的6个,再到第二个卷积层之后的16个。
同时,每个汇聚层的高度和宽度都减半。
最后,每个全连接层减少维数,最终输出一个维数与结果分类数相匹配的输出。
6、GPU实现
- device = next(iter(net.parameters())).device 把第一个network的参数拿出来,看一下它的device
- 多了一个device
- Xavier 函数作用是调整初始值,让输入和输出在一个合理区间,防止出现梯度消失或者梯度爆炸
- 这里l 是nn.CrossEntropyLoss,它是求多个样本的交叉熵损失的求和平均, l*X.shape[0]表示每个样本的损失乘以批量大小,等于这个批量样本的总损失
- 这里metric[0]的值是l*x.shape[0],最后又除以了x.shape[0],直接把l作为metric[0]的值不就好了吗
- train的损失和准确率是最后一个batch的,test的损失是整个test数据集上的?
三、问题回答
- view 数据本身不变
- reshape 可以做一些数据的copy