深度学习笔记020 LeNet

LeNet卷积神经网络

所谓卷积Net,就是将空间信息不停地压缩,压缩,在压缩,最后将特征变得很小很小,通道数变得越来越多,最后甚至特征会变成1,通道数会变成上千,最后做全连接输出,这便是卷积神经网络的内核。

feature map:输出

LeNet:

深度学习笔记020 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数据集,结果如下:

深度学习笔记020 LeNet

 

跑50次,可以达到90%:

深度学习笔记020 LeNet

 

 

 准确率达到了81%,loss降低到了0.475,准确度不是很高,在之前MLP中,精度也是80多,但是明显看到在MLP中有一定的过拟合,因为MLP的模型复杂度更大一些,所以过拟合现象比较明显,如下:

深度学习笔记008MultilayerPerceptron多层感知机AssertionError:https://www.cnblogs.com/loveandninenine/p/15810917.html

深度学习笔记020 LeNet

 

 

沐神:一般没有过拟合的模型,都是欠拟合了。

 

这个网络是神经网络中唯一一个能在CPU上跑的代码了……

因为这个网络是80年代的网络了,当年都是超级计算机跑的,要10w美金的那种计算机才能跑得动;但是现在,沐神只用了10秒钟就跑完了,而我在google平台上用GPU跑了1分钟左右;而在我可怜巴巴的thinkpad用CPU跑了5min,结果如下:

深度学习笔记020 LeNet

 

 所以,后面的学习基本用不到我的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())

 

上一篇:Android硬件抽象层HAL总结


下一篇:Mini2440之linux驱动移植-DM9000网卡驱动