• 第二次作业:卷积神经网络 part 2


    1 问题总结

    最近一段时间内比较困扰我的问题:

    • 做代码练习时,代码有些细节看不太明白,最近在学习pytorch的官方文档,希望能有一些帮助
    • 在transform.normalize()中的数字每次都不太一样,这个是有什么计算方法吗

    本周学习内容的问题:

    • MobileNet V2 代码练习中,“因为 CIFAR10 是 32*32,因此,网络有一定修改”,所以第二层网络的 stride 改为了 1, 为什么要做这样的修改? 其他网络也会根据数据集来修改网络吗?

    2 代码练习

    2.1 MobileNet

    1.论文阅读
    https://www.cnblogs.com/anxifeng/p/13443330.html

    2.代码练习

    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    import torchvision
    import torchvision.transforms as transforms
    import matplotlib.pyplot as plt
    import numpy as np
    import torch.optim as optim
    
    class Block(nn.Module):
        '''Depthwise conv + Pointwise conv'''
        def __init__(self, in_planes, out_planes, stride=1):
            super(Block, self).__init__()
            # Depthwise 卷积,3*3 的卷积核,分为 in_planes,即各层单独进行卷积
            self.conv1 = nn.Conv2d(in_planes, in_planes, kernel_size=3, stride=stride, padding=1, groups=in_planes, bias=False)
            self.bn1 = nn.BatchNorm2d(in_planes)
            # Pointwise 卷积,1*1 的卷积核
            self.conv2 = nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
            self.bn2 = nn.BatchNorm2d(out_planes)
    
        def forward(self, x):
            out = F.relu(self.bn1(self.conv1(x)))
            out = F.relu(self.bn2(self.conv2(out)))
            return out
    

    创建DataLoader

    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    
    transform_train = transforms.Compose([
        transforms.RandomCrop(32, padding=4),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))])
    
    transform_test = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))])
    
    trainset = torchvision.datasets.CIFAR10(root='./data', train=True,  download=True, transform=transform_train)
    testset  = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)
    
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=128, shuffle=True, num_workers=2)
    testloader = torch.utils.data.DataLoader(testset, batch_size=128, shuffle=False, num_workers=2)
    

    创建 MobileNetV1 网络
    32×32×3 ==>
    32×32×32 ==> 32×32×64 ==> 16×16×128 ==> 16×16×128 ==>
    8×8×256 ==> 8×8×256 ==> 4×4×512 ==> 4×4×512 ==>
    2×2×1024 ==> 2×2×1024
    接下来为均值 pooling ==> 1×1×1024
    最后全连接到 10个输出节点

    class MobileNetV1(nn.Module):
        # (128,2) means conv planes=128, stride=2
        cfg = [(64,1), (128,2), (128,1), (256,2), (256,1), (512,2), (512,1), 
               (1024,2), (1024,1)]
    
        def __init__(self, num_classes=10):
            super(MobileNetV1, self).__init__()
            self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1, bias=False)
            self.bn1 = nn.BatchNorm2d(32)
            self.layers = self._make_layers(in_planes=32)
            self.linear = nn.Linear(1024, num_classes)
    
        def _make_layers(self, in_planes):
            layers = []
            for x in self.cfg:
                out_planes = x[0]
                stride = x[1]
                layers.append(Block(in_planes, out_planes, stride))
                in_planes = out_planes
            return nn.Sequential(*layers)
    
        def forward(self, x):
            out = F.relu(self.bn1(self.conv1(x)))
            out = self.layers(out)
            out = F.avg_pool2d(out, 2)
            out = out.view(out.size(0), -1)
            out = self.linear(out)
            return out
    

    实例化网络

    # 网络放到GPU上
    net = MobileNetV1().to(device)
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(net.parameters(), lr=0.001)
    

    创建网络

    for epoch in range(10):  # 重复多轮训练
        for i, (inputs, labels) in enumerate(trainloader):
            inputs = inputs.to(device)
            labels = labels.to(device)
            # 优化器梯度归零
            optimizer.zero_grad()
            # 正向传播 + 反向传播 + 优化 
            outputs = net(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            # 输出统计信息
            if i % 100 == 0:   
                print('Epoch: %d Minibatch: %5d loss: %.3f' %(epoch + 1, i + 1, loss.item()))
    
    print('Finished Training')
    

    模型测试

    correct = 0
    total = 0
    
    for data in testloader:
        images, labels = data
        images, labels = images.to(device), labels.to(device)
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
    
    print('Accuracy of the network on the 10000 test images: %.2f %%' % (
        100 * correct / total))
    

    Accuracy of the network on the 10000 test images: 78.11 %

    2.2 MobileNet V2

    1.论文阅读
    https://www.cnblogs.com/anxifeng/p/13458998.html

    2.代码练习

    下面就是 Inverted residual block 部分的代码,主要思路就是:

    expand + Depthwise + Pointwise 其中,expand就是增大feature map数量的意思。需要指出的是,当步长为1的时候,要加一个 shortcut;步长为2的时候,目的是降低feature map尺寸,就不需要加 shortcut 了。

    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    import torchvision
    import torchvision.transforms as transforms
    import matplotlib.pyplot as plt
    import numpy as np
    import torch.optim as optim
    
    class Block(nn.Module):
        '''expand + depthwise + pointwise'''
        def __init__(self, in_planes, out_planes, expansion, stride):
            super(Block, self).__init__()
            self.stride = stride
            # 通过 expansion 增大 feature map 的数量
            planes = expansion * in_planes
            self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, stride=1, padding=0, bias=False)
            self.bn1 = nn.BatchNorm2d(planes)
            self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, groups=planes, bias=False)
            self.bn2 = nn.BatchNorm2d(planes)
            self.conv3 = nn.Conv2d(planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
            self.bn3 = nn.BatchNorm2d(out_planes)
    
            # 步长为 1 时,如果 in 和 out 的 feature map 通道不同,用一个卷积改变通道数
            if stride == 1 and in_planes != out_planes:
                self.shortcut = nn.Sequential(
                    nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False),
                    nn.BatchNorm2d(out_planes))
            # 步长为 1 时,如果 in 和 out 的 feature map 通道相同,直接返回输入
            if stride == 1 and in_planes == out_planes:
                self.shortcut = nn.Sequential()
    
        def forward(self, x):
            out = F.relu(self.bn1(self.conv1(x)))
            out = F.relu(self.bn2(self.conv2(out)))
            out = self.bn3(self.conv3(out))
            # 步长为1,加 shortcut 操作
            if self.stride == 1:
                return out + self.shortcut(x)
            # 步长为2,直接输出
            else:
                return out
    

    创建 MobileNetV2 网络
    注意,因为 CIFAR10 是 32*32,因此,网络有一定修改。

    class MobileNetV2(nn.Module):
        # (expansion, out_planes, num_blocks, stride)
        cfg = [(1,  16, 1, 1),
               (6,  24, 2, 1), 
               (6,  32, 3, 2),
               (6,  64, 4, 2),
               (6,  96, 3, 1),
               (6, 160, 3, 2),
               (6, 320, 1, 1)]
    
        def __init__(self, num_classes=10):
            super(MobileNetV2, self).__init__()
            self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1, bias=False)
            self.bn1 = nn.BatchNorm2d(32)
            self.layers = self._make_layers(in_planes=32)
            self.conv2 = nn.Conv2d(320, 1280, kernel_size=1, stride=1, padding=0, bias=False)
            self.bn2 = nn.BatchNorm2d(1280)
            self.linear = nn.Linear(1280, num_classes)
    
        def _make_layers(self, in_planes):
            layers = []
            for expansion, out_planes, num_blocks, stride in self.cfg:
                strides = [stride] + [1]*(num_blocks-1)
                for stride in strides:
                    layers.append(Block(in_planes, out_planes, expansion, stride))
                    in_planes = out_planes
            return nn.Sequential(*layers)
    
        def forward(self, x):
            out = F.relu(self.bn1(self.conv1(x)))
            out = self.layers(out)
            out = F.relu(self.bn2(self.conv2(out)))
            out = F.avg_pool2d(out, 4)
            out = out.view(out.size(0), -1)
            out = self.linear(out)
            return out
    

    创建 DataLoader

    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    
    transform_train = transforms.Compose([
        transforms.RandomCrop(32, padding=4),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))])
    
    transform_test = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))])
    
    trainset = torchvision.datasets.CIFAR10(root='./data', train=True,  download=True, transform=transform_train)
    testset  = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)
    
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=128, shuffle=True, num_workers=2)
    testloader = torch.utils.data.DataLoader(testset, batch_size=128, shuffle=False, num_workers=2)
    

    实例化网络

    # 网络放到GPU上
    net = MobileNetV2().to(device)
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(net.parameters(), lr=0.001)
    

    模型训练

    for epoch in range(10):  # 重复多轮训练
        for i, (inputs, labels) in enumerate(trainloader):
            inputs = inputs.to(device)
            labels = labels.to(device)
            # 优化器梯度归零
            optimizer.zero_grad()
            # 正向传播 + 反向传播 + 优化 
            outputs = net(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            # 输出统计信息
            if i % 100 == 0:   
                print('Epoch: %d Minibatch: %5d loss: %.3f' %(epoch + 1, i + 1, loss.item()))
    
    print('Finished Training')
    

    模型测试

    correct = 0
    total = 0
    
    for data in testloader:
        images, labels = data
        images, labels = images.to(device), labels.to(device)
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
    
    print('Accuracy of the network on the 10000 test images: %.2f %%' % (
        100 * correct / total))
    

    Accuracy of the network on the 10000 test images: 82.13 %

  • 相关阅读:
    小技巧
    常用的交互设计软件
    Android studio 使用SVN需要忽略的文件
    android studio 使用SVN 锁定文件,防止别人修改(基于Android studio 1.4 )
    git 和 github 关系?
    Double 数据保留两位小数一:五舍六入
    设计模式
    Java中关于日期类那些方法
    ios 开源免费接口
    华为招聘机试整理5:简单四则运算
  • 原文地址:https://www.cnblogs.com/anxifeng/p/13458835.html
Copyright © 2020-2023  润新知