LeNet卷积神经网络
所谓卷积Net,就是将空间信息不停地压缩,压缩,在压缩,最后将特征变得很小很小,通道数变得越来越多,最后甚至特征会变成1,通道数会变成上千,最后做全连接输出,这便是卷积神经网络的内核。
feature map:输出
LeNet:
输入是一个32x32的图,第一层卷积,大概是用的3x3的核,所以输出的形状是28x28,多通道将输出改为6通道;随后将这6个通道分别做池化操作,池化将输入大小减半;随后又是一层5x5的卷积层,将输出结果变为16层的10x10的图;随后又是一层大小减半的池化;最后输入到三个全连接层,在这之前,将16通道的结果拉成一个向量,最后用Softmax得到一个概率。
总结:
LeNet是早期的成功的神经网络;
先用卷积层学习图片空间信息,然后用池化降低空间位置敏感度,最后用全连接层来转换到类别空间。
pytorch中view和reshape的区别:https://www.cnblogs.com/regain/p/14499449.html
用这个卷积神经网络跑了一下d2l里面那个fashion_mnist数据集,结果如下:
跑50次,可以达到90%:
准确率达到了81%,loss降低到了0.475,准确度不是很高,在之前MLP中,精度也是80多,但是明显看到在MLP中有一定的过拟合,因为MLP的模型复杂度更大一些,所以过拟合现象比较明显,如下:
深度学习笔记008MultilayerPerceptron多层感知机AssertionError:https://www.cnblogs.com/loveandninenine/p/15810917.html
沐神:一般没有过拟合的模型,都是欠拟合了。
这个网络是神经网络中唯一一个能在CPU上跑的代码了……
因为这个网络是80年代的网络了,当年都是超级计算机跑的,要10w美金的那种计算机才能跑得动;但是现在,沐神只用了10秒钟就跑完了,而我在google平台上用GPU跑了1分钟左右;而在我可怜巴巴的thinkpad用CPU跑了5min,结果如下:
所以,后面的学习基本用不到我的pycharm了……
Q&A:
1、通常输入的高宽减半的时候,通道数会翻倍,相当于把多个模式分散放入了其他的通道中。当然了,信息在本质上一直在损失。
2、LeNet中的6和16这个参数很奇特,没有理论依据。比如,改成5和15,模型变小了,所以更不该出现过拟合,但是,沐神跑了一下,过拟合了,模型大的时候没有过拟合,模型小了反而过拟合了,神用自己的实际行动证明了炼丹这种事情是没有理论依据的。
3、用Max只关心最大的信号量,在实际中max比avg更好用一些。
代码:
import torch from torch import nn from d2l import torch as d2l class Reshape(torch.nn.Module): def forward(self,x): return x.view(-1,1,28,28) #-1代表自适应,也就是样本数不变;通道数改为1,宽高为28 ''' view 函数只能用于 contiguous 后的 tensor 上,也就是只能用于内存中连续存储的 tensor。 如果对 tensor 调用过 transpose, permute 等操作的话会使该 tensor 在内存中变得不再连续,此时就不能再调用 view 函数。 因此,需要先使用 contiguous 来返回一个 contiguous copy。 reshape 则不需要依赖目标 tensor 是否在内存中是连续的。 总结:reshape Yes! ''' net = nn.Sequential( Reshape(), nn.Conv2d(1, 6, kernel_size=5, padding=2), #输入是1,输出是6,上下填了两个空,因为原始输入是32x32,当时在边上pad了两列两行. # 这里也因为不加padding的话,边边的像素信息就会减少 nn.Sigmoid(), # 为了非线性性,加入sigmoid nn.AvgPool2d(kernel_size=2, stride=2), # 步长为2、大小为2x2的pool nn.Conv2d(6, 16, kernel_size=5), nn.Sigmoid(), nn.AvgPool2d(kernel_size=2, stride=2), nn.Flatten(), # 将输出拉成一个向量,输入到后面的感知机中。第一维度批量保持住,后面的都拉成一个向量 nn.Linear(16 * 5 * 5, 120), nn.Sigmoid(), nn.Linear(120, 84), nn.Sigmoid(), nn.Linear(84, 10)) X = torch.rand(size=(1, 1, 28, 28), dtype=torch.float32) for layer in net: X = layer(X) print(layer.__class__.__name__,'output shape: \t',X.shape) batch_size = 256 train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size) def evaluate_accuracy_gpu(net, data_iter, device=None): """使用GPU计算模型在数据集上的精度""" if isinstance(net, nn.Module): net.eval() # 设置为评估模式 if not device: device = next(iter(net.parameters())).device # 正确预测的数量,总预测的数量 metric = d2l.Accumulator(2) with torch.no_grad(): for X, y in data_iter: if isinstance(X, list): # BERT微调所需的(之后将介绍) X = [x.to(device) for x in X] else: X = X.to(device) y = y.to(device) metric.add(d2l.accuracy(net(X), y), y.numel()) return metric[0] / metric[1] def train_ch6(net, train_iter, test_iter, num_epochs, lr, device): """用GPU训练模型(在第六章定义)""" def init_weights(m): if type(m) == nn.Linear or type(m) == nn.Conv2d: nn.init.xavier_uniform_(m.weight) net.apply(init_weights) print('training on', device) net.to(device) optimizer = torch.optim.SGD(net.parameters(), lr=lr) loss = nn.CrossEntropyLoss() animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs], legend=['train loss', 'train acc', 'test acc']) timer, num_batches = d2l.Timer(), len(train_iter) for epoch in range(num_epochs): # 训练损失之和,训练准确率之和,样本数 metric = d2l.Accumulator(3) net.train() for i, (X, y) in enumerate(train_iter): timer.start() optimizer.zero_grad() X, y = X.to(device), y.to(device) y_hat = net(X) l = loss(y_hat, y) l.backward() optimizer.step() with torch.no_grad(): metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0]) timer.stop() train_l = metric[0] / metric[2] train_acc = metric[1] / metric[2] if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1: animator.add(epoch + (i + 1) / num_batches, (train_l, train_acc, None)) test_acc = evaluate_accuracy_gpu(net, test_iter) animator.add(epoch + 1, (None, None, test_acc)) print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, ' f'test acc {test_acc:.3f}') print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec ' f'on {str(device)}') d2l.plt.show() lr, num_epochs = 0.9, 10 train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())