DIDL笔记(pytorch版)(七)

文章目录

前言

大致总结一下深度学习的流程:

  • 配置变量:批次,学习率,迭代次数设备等。
  • 导入数据:数据预处理(标准化,清洗,去噪,划分数据集),弹性形变等。
  • 搭建网络:卷积、池化、激活函数等。
  • 训练模型:选择损失函数,选择优化方法,迭代循环嵌套批次循环。(训练外层可以套k折交叉验证)
    • 内层循环执行过程:x输入网络得到输出y->y与标签比对得到损失->梯度清零->计算梯度->反馈->记录损失以及正确率方便每次迭代后展示。

LeNet

第一次将卷积神经网络推上舞台,为世人所知。
DIDL笔记(pytorch版)(七)

import time
import torch
from torch import nn, optim
import d2l as d2l


# 设计网络
class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(1, 6, 5),     # in_channels, out_channels, kernel_size
            nn.Sigmoid(),
            nn.MaxPool2d(2, 2),     # kernel_size, stride
            nn.Conv2d(6, 16, 5),
            nn.Sigmoid(),
            nn.MaxPool2d(2, 2)
        )
        self.fc = nn.Sequential(
            nn.Linear(16*4*4, 120),
            nn.Sigmoid(),
            nn.Linear(120, 84),
            nn.Sigmoid(),
            nn.Linear(84, 10)
        )

    def forward(self, img):
        feature = self.conv(img)
        output = self.fc(feature.view(img.shape[0], -1))
        return output


def train_ch5(net, train_iter, test_iter, batch_size, loss, optimizer, device, num_epochs):
    net = net.to(device)
    print("training on", device)
    for epoch in range(num_epochs):
        train_l_sum, train_acc_sum, n, batch_count, start = 0.0, 0.0, 0, 0, time.time()
        for X, y in train_iter:
            X = X.to(device)
            y = y.to(device)

            y_hat = net(X)
            l = loss(y_hat, y)
            optimizer.zero_grad()
            l.backward()
            optimizer.step()

            # 计算损失,呈现数据
            train_l_sum += l.cpu().item()
            train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()
            n += y.shape[0]
            batch_count += 1
        # 一个周期,计算一次test,其实也非必要
        test_acc = evaluate_accuracy(test_iter, net)
        print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f, time %.1f sec'
              % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n, test_acc, time.time() - start))


def evaluate_accuracy(data_iter, net, device=None):
    if device is None and isinstance(net, torch.nn.Module):
        # 如果没指定device就使用net的device
        device = list(net.parameters())[0].device
    acc_sum, n = 0.0, 0
    with torch.no_grad():
        for X, y in data_iter:
            net.eval()  # 评估模式, 这会关闭dropout
            acc_sum += (net(X.to(device)).argmax(dim=1) == y.to(device)).float().sum().cpu().item()
            net.train()     # 改回训练模式
            n += y.shape[0]
    return acc_sum / n

if __name__ == "__main__":
    # 配置
    lr, num_epochs = 0.001, 5
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    batch_size = 256
    # 导入数据
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)
    # 网络、损失、优化方法
    net = LeNet()
    loss = torch.nn.CrossEntropyLoss()
    optimizer = torch.optim.Adam(net.parameters(), lr=lr)
    train_ch5(net, train_iter, test_iter, batch_size, loss, optimizer, device, num_epochs)

AlexNet

LeNet被其他机器学习方法超越了,因为在小数据集上取得好成绩,但是在大数据集上不行;而且计算开销大。想要设计一个多通道、多层、多参数的无法完成。从上面也可以看到层数少,通道少。

当时认为机器学习只做分类即可。但是有些科学家认为神经网络可以自己提取特征并且分类。在以前,特征是基于各种手工设计的函数从数据中提取出来的。机器学习只负责分类就好。例如,分类癌细胞与非癌细胞,机器学习要计算出每个细胞的大小,形状、细胞间的距离等等。这些都是设计函数计算得到的特征,然后把特征给机器学习分类。而且,计算机视觉的人认为数据和特征比选择一个机器学习的模型更重要

  • AlexNet首次证明了学习到的特征可以超越手工设计的特征,从而一举打破计算机视觉研究的前状。
  • AlexNet提出丢弃法。
  • AlexNet引入旋转和颜色变换等数据增强。

下面的代码与论文网络结构相比有改动,因为之前显存有限设置双数据流,现在不需要了。

class AlexNet(nn.Module):
    def __init__(self):
        super(AlexNet, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(1, 96, 11, 4), # in_channels, out_channels, kernel_size, stride
            nn.ReLU(),
            nn.MaxPool2d(3, 2), # kernel_size, stride
            # 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
            nn.Conv2d(96, 256, 5, 1, 2),# in_channels, out_channels, kernel_size, stride, padding
            nn.ReLU(),
            nn.MaxPool2d(3, 2),
            # 连续3个卷积层,且使用更小的卷积窗口。除了最后的卷积层外,进一步增大了输出通道数。前两个卷积层后不使用池化层来减小输入的高和宽
            nn.Conv2d(256, 384, 3, 1, 1),
            nn.ReLU(),
            nn.Conv2d(384, 384, 3, 1, 1),
            nn.ReLU(),
            nn.Conv2d(384, 256, 3, 1, 1),
            nn.ReLU(),
            nn.MaxPool2d(3, 2)
        )
         # 这里全连接层的输出个数比LeNet中的大数倍。使用丢弃层来缓解过拟合
        self.fc = nn.Sequential(
            nn.Linear(256*5*5, 4096),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(4096, 4096),
            nn.ReLU(),
            nn.Dropout(0.5),
            # 输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
            nn.Linear(4096, 10),
        )

    def forward(self, img):
        feature = self.conv(img)
        output = self.fc(feature.view(img.shape[0], -1))
        return output

VGGNet

论文总结

import time
import torch
from torch import nn, optim

import d2l as d2l
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')


# 添加多少卷积层,设计多层vgg更加灵活
def vgg_block(num_convs, in_channels, out_channels):
    blk = []
    for i in range(num_convs):
        if i == 0:
            blk.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))
        else:
            blk.append(nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1))
        blk.append(nn.ReLU())
    blk.append(nn.MaxPool2d(kernel_size=2, stride=2))
    return nn.Sequential(*blk)


def vgg(conv_arch, fc_features, fc_hidden_units=4096):
    net = nn.Sequential()
    # 卷积层部分
    for i, (num_convs, in_channels, out_channels) in enumerate(conv_arch):
        # 每经过一个vgg_block都会使宽高减半
        net.add_module("vgg_block_" + str(i+1), vgg_block(num_convs, in_channels, out_channels))
    # 全连接层部分
    net.add_module("fc", nn.Sequential(d2l.FlattenLayer(),  # 全连接层,一张图片要拉成一维数组
                                 nn.Linear(fc_features, fc_hidden_units),
                                 nn.ReLU(),
                                 nn.Dropout(0.5),
                                 nn.Linear(fc_hidden_units, fc_hidden_units),
                                 nn.ReLU(),
                                 nn.Dropout(0.5),
                                 nn.Linear(fc_hidden_units, 10)
                                ))
    return net
上一篇:Spring Cloud微服务架构进阶


下一篇:conda查看源和添加本地源