实验5 卷积神经网络实验

一、实验要求

在计算机上验证和测试Pytorch卷积神经网络的原理和算法实现,测试卷积神经网络的训练效果,同时查阅相关资料。

  • 实验目的

1、掌握PyTorch的基本使用;

2、掌握PyTorch的卷积神经网络;

3、掌握PyTorch的图像分类训练流程;

三、实验内容

实验步骤

import os
os.environ["CUDA_VISIBLE_DEVICES"] = '0'  #默认为显卡0
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

# torchvision 包收录了若干重要的公开数据集、网络模型和计算机视觉中的常用图像变换
from torchvision import datasets, transforms #做图片处理的库
#from torch.autograd import Variable
import time

# Training settings
BATCH_SIZE = 512  # 一个batch 的大小,大概需要2G的显存 
EPOCHS = 10 # 总共训练批次

# 设备配置
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") 
print(DEVICE.type)#输出设备类型
# MNIST Dataset

# transform=transforms.ToTensor():将图像转化为Tensor,在加载数据的时候,就可以对图像做预处理
train_dataset = datasets.MNIST(root='./data/',
                train=True, download=True,
                transform=transforms.Compose([
                    transforms.ToTensor(),
                    transforms.Normalize((0.1037,), (0.3081,))
                    ]))

test_dataset = datasets.MNIST(root='./data/',
               train=False,download=False,
               transform=transforms.Compose([
                    transforms.ToTensor(),
                    transforms.Normalize((0.1037,), (0.3081,))
                    ]))

# Data Loader (Input Pipeline)

# 训练数据集的加载器,自动将数据分割成batch,顺序随机打乱
train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
                      batch_size=BATCH_SIZE, #显存有限制
                      shuffle=True)

# 训测试数据集的加载器,自动将数据分割成batch,顺序随机打乱
test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
                     batch_size=BATCH_SIZE,
                     shuffle=True)


# 定义模型
class ConvNet(nn.Module):
    def __init__(self):
        super().__init__()
        #输入图像1*1*28*28
        self.conv1 = nn.Conv2d(1, 10, 5) 
        # 第一层卷积1 input channel, 10 output channels, 5x5 square convolution kernel
        self.conv2 = nn.Conv2d(10, 20, 3) 
        # 第二层卷积:10input channel, 20 output channels, 3x3 square convolution kernel
        self.fc1 = nn.Linear(20 * 10 * 10, 500)
        # 线性连接层的输入尺寸为最后一层立方体的平铺,输出层500个节点
        self.fc2 = nn.Linear(500, 10)
        # 最后一层线性分类单元,输入为500,输出为要做分类的类别数
    def forward(self, x): #forward() 函数ConvNet的前向传播
        # x尺寸:(batch_size, image_channels, image_width, image_height)
        #卷积层->池化层->激活函数,两个卷积层
        in_size = x.size(0)
        out= self.conv1(x) # 1* 10 * 24 *24  第一层卷积
        out = F.relu(out)  # 激活函数用ReLU,防止过拟合
        
        #最大池化层:将图像分成小块,在每一块中寻找最大值,返回给输出,
        out = F.max_pool2d(out, 2, 2) # 1* 10 * 12 * 12 第二层池化,将图片变小
        
        out = self.conv2(out) # 1* 20 * 10 * 10  # 第三层又是卷积
        out = F.relu(out) # 非线性函数
        
        # 将立体的特征图 tensor 压成一个一维的向量
        # view 函数可以将一个tensor 按指定的方式重新排布        
        out = out.view(in_size, -1) # 1 * 2000
        
        # 一个线性连接层,输入尺寸为最后一层立方体的线性平铺,输出层 500个节点
        out = self.fc1(out) # 1 * 500
        out = F.relu(out) # 第五层为全连接,ReLU激活函数
        
        # 最后一层线性分类单元,输入为 500,输出为要做分类的类别数10个
        out = self.fc2(out) # 1 * 10
        
        # out的尺寸:(batch_size, num_classes)
        # # 输出层为 log_Softmax,即概率对数值 log(p(×))。采用log_softmax可以使后面的交叉熵计算更快
        # dim=0 ,即softmax后横向的和为1
        out = F.log_softmax(out, dim = 1)
        return out

# 定义训练函数
def train(model, device, train_loader, optimizer, epoch):
    model.train() # 新建一个卷积神经网络的实例
    for batch_idx, (data, target) in enumerate(train_loader): # 针对容器中的每一个批进行循环
        # 将数据送入GPU中计算 data 为一批图像,target 为一批标签
        data, target = data.to(device), target.to(device)
#         optimizer.zero_grad() # 清空梯度
        output = model(data) ## 神经网络完成一次前馈的计算过程,得到预测输出output
        loss = F.nll_loss(output, target) # 将output与标签target比较,计算误差
        optimizer.zero_grad() # 清空梯度
        loss.backward() # 反向传播
        optimizer.step() ## 一步随机梯度下降算法
        if (batch_idx + 1) % 30 == 0: # 每间隔batch_idx + 1个batch 执行一次打印操作
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), loss.item()))

# 定义测试函数
def test(model, device, test_loader):
    model.eval() # 给网络楧型做标记,标志着模型在训练集上训练
    test_loss =0 #损失率
    correct = 0 #准确率
    with torch.no_grad(): #不需要计算梯度
        for data, target in test_loader:  #遍历数据集中的每一个batch
            data, target = data.to(device), target.to(device) #保存测试的输入和输出,将数据送入GPU
            output = model(data) #模型输出
            test_loss += F.nll_loss(output, target, reduction = 'sum') # 将一批的损失相加
            pred = output.max(1, keepdim = True)[1] # 找到概率最大的下标
            correct += pred.eq(target.view_as(pred)).sum().item() #准确率
    
    test_loss /= len(test_loader.dataset) #错误率
    print("\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%) \n".format(
        test_loss, correct, len(test_loader.dataset),
        100.* correct / len(test_loader.dataset))) #输出准确率,损失率

start = time.perf_counter() #perf_counter()返回当前的计算机系统时间
#生成模型和优化器
model = ConvNet().to(DEVICE)
optimizer = optim.Adam(model.parameters())
# 最后开始训练和测试
for epoch in range(1, EPOCHS + 1): # 总共训练批次为EPOCHS+1
    train(model,  DEVICE, train_loader, optimizer, epoch) #训练数据
    test(model, DEVICE, test_loader) #测试数据
end = time.perf_counter() #系统终止时间
print(DEVICE.type,'时间',end) #输出当前时间

四、实验总结

        整个卷积神经网络的运作分成了两个阶段:前馈运算阶段和反馈学习阶段。在网络的前馈阶段(从输人图像到输出数字),所有连接的权重值都不改变,系统会根据输人图像计算输出分类,并根据网络的分类与数据中的标签(标准答案)进行比较计算出交叉熵作为损失函数。接下来,在反馈阶段,根据前馈阶段的损失两数调整所有连接上的权重值,从而完成神经网络的学习过程。

你可能感兴趣的:(深度学习,cnn,pytorch,深度学习)