卷积神经网络CNN入门【pytorch学习】

简述

在学习GANs的时候遇到一篇论文DCGANs,说是其中用到了卷积神经网络。
所以,就抽空学习一下,结果,真没想到有那么多的坑。

文章目录

    • 简述
    • 数据配置
      • 配套的代码段
    • 参数设置
    • 训练集批处理构建
    • 测试集
    • 构建CNN框架
    • 训练
    • 测试结果
    • 全部代码
    • 参考

数据配置

第一步配置数据的时候就贼坑了。。。

  • 看下面的这一篇文章就可以解决,就是手动下载之后,放在一个目录下,之后,再修改源码中指定的位置,之后再运行,代码会从本地下载(其实就是转移位置),但是由于它同时也会生成两个c文件。所以,不推荐直接手动的建目录之类的操作
  • pytorch下载mnist超时解决方案

配套的代码段

import torch
import torch.nn as nn
import torchvision
import torch.utils.data as Data

DOWNLOAD_MNIST = True  # 已经下载好的话,会自动跳过的

# Mnist 手写数字
train_data = torchvision.datasets.MNIST(
    root='./mnist/',  # 保存或者提取位置
    train=True,  # this is training data
    transform=torchvision.transforms.ToTensor(),  # 转换 PIL.Image or numpy.ndarray 成
    # torch.FloatTensor (C x H x W), 训练的时候 normalize 成 [0.0, 1.0] 区间
    download=DOWNLOAD_MNIST,  # 没下载就下载, 下载了就不用再下了
)

test_data = torchvision.datasets.MNIST(
    root='./mnist/',
    train=False
)

参数设置

  • 这里只测试一次的原因其实是,训练集有60000个。虽然之后使用批处理的方式,但是我们BATCH_SIZE设置为了50,所以,也有1200次的训练了。所以,只用一次就好了。
  • BATCH_SIZE 就是每一次训练的那个块中的数据数量
  • LR学习率

这些参数在建立GANs的时候也用到了。

# Hyper Parameters
EPOCH = 1  # 训练整批数据多少次, 为了节约时间, 我们只训练一次
BATCH_SIZE = 50
LR = 0.001  # 学习率

训练集批处理构建

# 训练集丢BATCH_SIZE个, 图片大小为28*28
train_loader = Data.DataLoader(
    dataset=train_data,
    batch_size=BATCH_SIZE,
    shuffle=True  # 是否打乱顺序
)

测试集

其实这里调用出来是没有什么用,但是任然放出来了,主要是为了跟学习的一份代码中保持一致性。找bug的时候,这样很方便。

但是这里有一个重点(对于新手)

  • torch.unsqueeze()函数,给数组加上一个维度。dim=1表示在添加的这个维度是再哪?
  • 比如dim=1时候
  • (10,20)变成了(10,1,20)
# test_data为 [10000, 28, 28]这样的一个数组,这里就只截取一段就好了
test_x = torch.unsqueeze(test_data.test_data, dim=1).type(torch.FloatTensor)
test_y = test_data.test_labels

构建CNN框架

  • nn.Module非常常见的自定义类,所有模型的基类
  • 第一个网络是:先是一个卷积,再是一个ReLU激活函数,最后再来个最大池化

如果真的是新手的话,会发下这里贼多知识点。

  • 先看懂什么是卷积
  • 再搞定padding,stride这些参数什么意思
  • 池化: 这个反而是最简单的。就是给一个矩形(小一点的),然后通过一定的移动方式,在这个区间上找最大值。然后不重复的这样遍历完所有的像素点。得到的一张新图(新的张量)
  • 所以,我在注释的地方表示的是到这里的时候这个数据的shape
  • 通过.view(shape(0),-1) 这样的方式,将数据展开为一个一维向量。之后,再通过一个线性函数,转成10个线性函数的结果来。(表示对应10个数字的概率(其实可能是负数的,但是会逐渐的改善,大致上能拟合出结果来)
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.layer1 = nn.Sequential(
            # (1, 28, 28)
            nn.Conv2d(
                in_channels=1,
                out_channels=16,
                kernel_size=5,  # 卷积filter, 移动块长
                stride=1,  # filter的每次移动步长
                padding=2,
                groups=1
            ),
            # (16, 28, 38)
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2)
            # (16, 14, 14)
        )
        self.layer2 = nn.Sequential(

            nn.Conv2d(
                in_channels=16,
                out_channels=32,
                kernel_size=5,
                stride=1,
                padding=2
            ),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2)
        )
        self.layer3 = nn.Linear(32 * 7 * 7, 10)

    def forward(self, x):
        # print(x.shape)
        x = self.layer1(x)
        # print(x.shape)
        x = self.layer2(x)
        # print(x.shape)
        x = x.view(x.size(0), -1)
        # print(x.shape)
        x = self.layer3(x)
        # print(x.shape)
        return x

训练

  • 这里的遍历,其实是会把所有的训练集数据都训练过一遍为止。
  • 损失函数调用的是交叉熵。https://blog.csdn.net/zziahgf/article/details/80196376
  • 公式的含义,其实非常简单,就是希望目标数对应下标的那个数值要大一点。但是又不能是因为所有为止上的点的数值都变大导致了。
cnn = CNN()

optimizer = torch.optim.Adam(cnn.parameters(), lr=LR)
loss_function = nn.CrossEntropyLoss()
for epoch in range(EPOCH):
    for step, (b_x, b_y) in enumerate(train_loader):
        output = cnn(b_x)
        loss = loss_function(output, b_y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

测试结果

print('finished training')
test_out = cnn(test_x)
predict_y = torch.argmax(test_out, 1).data.numpy()
print('Accuracy in Test : %.4f%%' % (sum(predict_y == test_y.data.numpy()) * 100/ len(predict_y)))

我这里跑的一个结果是

finished training
Accuracy in Test : 98.2000%

然后速度其实是有点慢的。之后会再看看其他的实现。

全部代码

import torch
import torch.nn as nn
import torchvision
import torch.utils.data as Data

# Hyper Parameters
EPOCH = 1  # 训练整批数据多少次, 为了节约时间, 我们只训练一次
BATCH_SIZE = 50
LR = 0.001  # 学习率
DOWNLOAD_MNIST = True  # 已经下载好的话,会自动跳过的

# Mnist 手写数字
train_data = torchvision.datasets.MNIST(
    root='./mnist/',  # 保存或者提取位置
    train=True,  # this is training data
    transform=torchvision.transforms.ToTensor(),  # 转换 PIL.Image or numpy.ndarray 成
    # torch.FloatTensor (C x H x W), 训练的时候 normalize 成 [0.0, 1.0] 区间
    download=DOWNLOAD_MNIST,  # 没下载就下载, 下载了就不用再下了
)

test_data = torchvision.datasets.MNIST(
    root='./mnist/',
    train=False
)

# 训练集丢BATCH_SIZE个, 图片大小为28*28
train_loader = Data.DataLoader(
    dataset=train_data,
    batch_size=BATCH_SIZE,
    shuffle=True  # 是否打乱顺序
)

# test_data为 [10000, 28, 28]这样的一个数组,这里就只截取一段就好了
test_x = torch.unsqueeze(test_data.test_data, dim=1).type(torch.FloatTensor)
test_y = test_data.test_labels


# cnn

class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.layer1 = nn.Sequential(
            # (1, 28, 28)
            nn.Conv2d(
                in_channels=1,
                out_channels=16,
                kernel_size=5,  # 卷积filter, 移动块长
                stride=1,  # filter的每次移动步长
                padding=2,
                groups=1
            ),
            # (16, 28, 38)
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2)
            # (16, 14, 14)
        )
        self.layer2 = nn.Sequential(

            nn.Conv2d(
                in_channels=16,
                out_channels=32,
                kernel_size=5,
                stride=1,
                padding=2
            ),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2)
        )
        self.layer3 = nn.Linear(32 * 7 * 7, 10)

    def forward(self, x):
        # print(x.shape)
        x = self.layer1(x)
        # print(x.shape)
        x = self.layer2(x)
        # print(x.shape)
        x = x.view(x.size(0), -1)
        # print(x.shape)
        x = self.layer3(x)
        # print(x.shape)
        return x


cnn = CNN()

optimizer = torch.optim.Adam(cnn.parameters(), lr=LR)
loss_function = nn.CrossEntropyLoss()
for epoch in range(EPOCH):
    for step, (b_x, b_y) in enumerate(train_loader):
        output = cnn(b_x)
        loss = loss_function(output, b_y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

print('finished training')
test_out = cnn(test_x)
predict_y = torch.argmax(test_out, 1).data.numpy()
print('Accuracy in Test : %.4f%%' % (sum(predict_y == test_y.data.numpy()) * 100/ len(predict_y)))

参考

  • https://morvanzhou.github.io/tutorials/machine-learning/tensorflow/5-03-A-CNN/
  • https://github.com/sunshineatnoon/Paper-Implementations

你可能感兴趣的:(Python,机器学习+深度学习+强化学习,机器学习+深度学习+强化学习,Pytorch学习)