深度学习CNN-(1)

发布于 2020-10-14  2077 次阅读


CNN-LeNet

总述

CNN基本概念

  1. 卷积层:卷积层可通过重复使用卷积核有效地表征局部空间

  2. 池化层:池化层是为了缓解卷积层对位置的过度敏感性

  3. 卷积尺寸计算公式:

    定义以下参数:

    ​ 输入图片大小 W×W

    ​ 卷积核大小 F×F

    ​ 步长 S

    ​ 填充的像素数 P

    ​ 则卷积输出尺寸$N$为
    $$
    N = \frac{W-F+2P}{S}+1
    $$

  4. 池化尺寸计算公式:

    定义以下参数:

    ​ 输入图片大小 W×W

    ​ 池化核大小 F×F

    ​ 步长 S

    ​ 则卷积输出尺寸$N$为
    $$
    N = \frac{W-F}{S}+1
    $$

LeNet(卷积神经网络)

基本介绍

为了解决DNN中全连接的参数过多,CNN提出来利用卷积核来表示有效特征空间,其最开始的也是最简单的就是LeNet网络其,LeNet交替使用卷积层和最大池化层后接全连接层来进行图像分类,具体采用了两层卷积,两层池化和三层全连接层来进行搭建模型

Pytorch

pytorch是Facebook的机器学习库,可以方便的进行梯度下降等过程,因为我觉得tensorflow有点紊乱,所以用pytorch来1进行接下来的NN学习

Pytorch实现代码(对自己有用的写了注释)

import torchvision  #基于pytorch的处理图像视频工具库-torchvision
import torchvision.transforms as transforms  #transforms包括很多处理图像的方法,比如归一化,剪切..
import torch
import torch.nn as nn #最常用的torch块,封装了很多有用的东西
from torch.utils.data import Dataset, DataLoader #方便训练中数据处理,一个是数据转化类,一个是数据加载类
import sys
import numpy as np
import matplotlib.pyplot as plt
import time

def watchimg(dataset, batch_size):
    imglist = []
    for i in range(batch_size):
        imglist.append(dataset[i][0])
    grid = torchvision.utils.make_grid(imglist, padding=2, nrow=int(batch_size ** 0.5)) #把四维输出图像合成一张图像输出,其中padding是间距,nrow是每行数量
    npgrid = grid.cpu().numpy()
    plt.imshow(np.transpose(npgrid, (1, 2, 0)), interpolation='nearest')
    plt.show()

# torchvision.datasets有现成的数据集和训练集,download参数代表下载,已经是DataSet类,可以用transforms.ToTensor()进行归一处理
mnist_train = torchvision.datasets.FashionMNIST(root='./Datasets/FashionMNIST', train=True, download=True,transform=transforms.ToTensor())
mnist_test = torchvision.datasets.FashionMNIST(root='./Datasets/FashionMNIST', train=False, download=True,transform=transforms.ToTensor())

batch_size = 256
if sys.platform.startswith('win'):
    num_workers = 0 
else:
    num_workers = 4
# DataLoader负责数据加载,num_workers代表多线程加载,batch_size代表一次取出样本数,shuffle代表打乱次序
train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True, num_workers=num_workers)
test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False, num_workers=num_workers)

# 所有模型都是nn.Module的子类,要定义__init__和forward函数
class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.conv = nn.Sequential( ## nn.Sequential提供了一个训练步骤容器,可以按次序进行每一步
            nn.Conv2d(1, 6, 5), # 输入通道, 输出通道, 核大小
            nn.Sigmoid(),
            nn.MaxPool2d(2, 2), # 核大小, 步长
            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 evaluate_accuracy(data_iter, net):
    acc_sum, n = 0.0, 0
    with torch.no_grad():
        for i, data in enumerate(data_iter):# DataLoader后可以进行enumerate输出,类似list
            x, y = data
            net.eval()  # 评估模式, 这会关闭dropout
            acc_sum += (net(x.to('cuda')).argmax(dim=1) == y.to('cuda')).float().sum().cpu().item()
            n += y.shape[0]
    return acc_sum / n


def train_ch5(net, train_iter, test_iter, optimizer, num_epochs):
    net = net.to('cuda') # 在gpu上训练模型,如果模型在gpu训练,则所有的都需要定义在gpu训练
    print("training on ", 'cuda')
    loss = torch.nn.CrossEntropyLoss() # nn中的交叉熵损失函数
    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 i, data in enumerate(train_iter):
            x, y = data
            x = x.to('cuda')
            y = y.to('cuda')
            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_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))


net = LeNet() #模型实例化
lr, num_epochs = 0.001, 5 #步长和训练次数
optimizer = torch.optim.Adam(net.parameters(), lr=lr) # torch.optim是一个实现了多种优化算法的包,Adam是其中一个可以调整学习率的算法
train_ch5(net, train_iter, test_iter, optimizer, num_epochs) #开始训练

总结

像我这样的懒狗一般不爱写注释,这是因为第一个pytorch就是认真的记录了一下,至于安装啥的,用conda创建环境就好了,没有啥坑,所以就不写了,下一篇应该是更细致的一些CNN模型和一些tips 🐛🐛🐛