Skip to content

Latest commit

 

History

History
145 lines (101 loc) · 5.68 KB

11_卷积神经网络(高级).md

File metadata and controls

145 lines (101 loc) · 5.68 KB

卷积神经网络-高级

​ 下图所示的是GoogleNet,这是一个很常用的神经网络基础架构。在实现这一基础架构时,可以先实现 Inception Module 等模块,然后再拼接这个大模块。

image-20200821151454723

​ 这里的 Inception Module是这门课程给出的,和吴恩达深度学习课程中给出的不太一样。但都需要注意的一点是,各个分支最后得到的输出,他们的宽高必须能匹配上。至于各自的通道数是多少,这个没有规定,反正都能拼接上。

​ 在实现神经网络时需要注意,并不是越层数越多越好,下图的数据就证明了这一点。造成这一现象的原因有:过拟合、梯度消失等诸多原因。当然,这只是对于 PlainNet 而言的,对于 ResNet,那就是多多益善了。

​ 在 pytorch 中实现 ResNet 时,其实就是在 identity block 或 convolutional block中把返回值改成 x + x_0 即可。

image-20200821154832613

代码示例1

代码功能:实现了上图中的 Inception Module

image-20200821153023617

image-20200821153038578

  • 最后的线性单元的输入是1408维的,来源如下:
    • 通道变化过程:10 ==> 88 ==> 20 ==> 88 ==> 展开得到输入为1408维的向量。其中,1408 = 4*4*88,4*4是最终输出的图像的宽和高。
    • 注意这里使用的 mnist 数据集。
    • 注意这里 Net 模块中 forward 方法中的 view 的用法,in_size 是输入数据集的规模,通过保留规模,自动算出展开后应有的维数。实践中不需要自己去算,就把 init 中最后几行代码略去,然后在 forward 中把维数输出出来看一眼就行了。

image-20200821153112397

代码示例2

代码功能:基于 ResNet 的 mnist 数据集训练

  • skip over 2层的 identity block,也可以加上 NormBatch
  • 实现时,可以在每一步检查一下输出的张量的 size 是否和期望的一样

image-20200821155617427

image-20200821155718170

image-20200821234058617

import torch
import torchvision
import numpy as np
import matplotlib.pyplot as plt
from torch.utils.data import Dataset
from torch.utils.data import DataLoader

####################### Part1. Prepare Dataset #######################

batch_size = 128

transform = torchvision.transforms.Compose([
    torchvision.transforms.ToTensor(),
    torchvision.transforms.Normalize(0.1307, 0.3081)
])

x_train = torchvision.datasets.MNIST(root="D:/Drafts/mnist", train=True, transform=transform, download=False)
train_loader = DataLoader(x_train, batch_size=batch_size, shuffle=True, num_workers=2)

x_test = torchvision.datasets.MNIST(root="D:/Drafts/mnist", train=False, transform=transform, download=False)
test_loader = DataLoader(x_test, batch_size=batch_size, shuffle=False, num_workers=2)


####################### Part2. Design Model #######################

# 这里实现的其实是一个卷积块,不过实践中也不必太纠结这个
class IdentityBlock(torch.nn.Module):
    def __init__(self, in_channels, out_channels):
        super(IdentityBlock, self).__init__()
        self.conv1 = torch.nn.Conv2d(in_channels, in_channels, kernel_size=3, padding=1)
        self.conv2 = torch.nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)
        # 用于统一x和y的通道数,最好不要复用conv2,参数单独训练
        self.conv = torch.nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)
        self.activate = torch.nn.ReLU()

    def forward(self, x):
        y = self.activate(self.conv1(x))
        y = self.conv2(y)
        x = self.conv(x)
        return self.activate(x + y)


class MyModule(torch.nn.Module):
    def __init__(self):
        super(MyModule, self).__init__()
        self.r1 = IdentityBlock(1, 10)
        self.p1 = torch.nn.MaxPool2d(2)
        self.r2 = IdentityBlock(10, 20)
        self.p2 = torch.nn.MaxPool2d(2)
        self.fc = torch.nn.Linear(20 * 7 * 7, 10)
        self.activate = torch.nn.ReLU()

    def forward(self, x):
        x = self.r1(x)
        x = self.activate(self.p1(x))
        x = self.r2(x)
        x = self.activate(self.p2(x))
        x = x.view(-1, 20 * 7 * 7)
        x = self.fc(x)
        return x


model = MyModule()

####################### Part3. Construct Loss and Optimizer #######################

criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)


####################### Part4. Train and Test #######################

def train():
    for (inputs, labels) in train_loader:
        y_pred = model(inputs)
        loss = criterion(y_pred, labels)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

def test():
    correct = 0
    total = 0
    with torch.no_grad():
        for (inputs, labels) in test_loader:
            y_pred = model(inputs)
            _, outputs = torch.max(y_pred, dim=1)

            total += labels.size(0)
            correct += (outputs == labels).sum().item()

    print("test accuracy:", correct / total)


if __name__ == "__main__":
    for epoch in range(10):
        print("<----- %d ----->" % epoch)
        train()
        test() # 最终的准确率大致是98%