PyTorch深度学习(15)MNIST手写数据集训练

  • Post author:
  • Post category:其他


专业名词


参数和超参数


参数

:模型

f(x,θ)



θ

称为模型的参数,可以通过优化算法进行学习


超参数

:用来定义模型结构或优化策略


batch_size 批处理

每次处理的数据数量


epoch 轮次

把一个数据集,循环运行几轮


transforms变换

主要将图片转换为tensor,旋转图片,以及正则化


normalize 正则化

模型出现过拟合现象时,降低模型复杂度


卷积层

:由卷积核构建,卷积核简称为卷积,也称为滤波器,卷积的大小可以在实际需要时自定义其长和宽(1×1、3×3、5×5)


池化层

:对图片进行压缩(降采样)的一种方法,如max_pooling,average_pooling等


激活层

:激活函数的作用是在所有隐藏层之间添加一个激活函数,这样的输出就是一个非线性函数,因而神经网络的表达能力更加强大


损失函数

:在深度学习中,损失反映模型最后预测结果与实际真值之间的差距,可以用来分析训练过程的好坏、模型是否收敛等,例如:均方损失、交叉熵损失等。

具体代码

# 加载必要库
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader

# 定义超参数
BATCH_SIZE = 128
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
EPOCHS = 10

# 构建pipeline(transforms),对图像做处理
pipeline = transforms.Compose([
    # 将图像转换为tensor格式
    transforms.ToTensor(),
    # 正则化 模型过拟合时降低模型复杂度
    transforms.Normalize((0.1307, ), (0.3081, ))
])

# 下载、加载数据集MNIST
train_set = datasets.MNIST("data", train=True, transform=pipeline, download=True)
test_set = datasets.MNIST("data", train=False, transform=pipeline, download=True)

train_loader = DataLoader(train_set, batch_size=BATCH_SIZE, shuffle=True)
test_loader = DataLoader(test_set, batch_size=BATCH_SIZE, shuffle=True)

'''
# 显示MNIST中的图片
with open("./data/MNIST/raw/train-image-idx3-ubyte", "rb") as f
    file = f.read()
image1 = [int(str(item).encode('ascii'), 16) for item in file[16:16+784]]
print(image1)
import cv2
import numpy as np
image_np = np.array(image1, dtype=np.unit8).reshape(28,28,1)
print(image_np.shape)
cv2.imwrite("digit.jpg", image_np)
'''

# 构建网络模型
class Net(nn.Module):

    def __init__(self):
        super().__init__()
        # 灰度图片通道数为1, 输出通道数为10,kernel为5
        self.conv1 = nn.Conv2d(1, 10, 5)
        # 输入通道10,输出通道20,kernel为3
        self.conv2 = nn.Conv2d(10, 20, 3)
        # 输入通道2000,输出通道500
        self.fc1 = nn.Linear(2000, 500)
        # 输入通道500,输出通道10
        self.fc2 = nn.Linear(500, 10)

    def forward(self, x):
        # batch_size * 通道1 * 28 * 28
        input_size = x.size(0)
        # 输入:batch * 1 * 28 * 28 输出:batch * 10 * 24 * 24
        x = self.conv1(x)
        # 保持shape不变,输出batch * 10 * 24 * 24
        x = F.relu(x)
        # 输入batch * 10 * 24 * 24  输出:batch * 10 * 12 * 12
        x = F.max_pool2d(x, 2, 2)

        # 输出batch * 20 * 10 * 10
        x = self.conv2(x)
        x = F.relu(x)
        # 展平
        x = x.view(input_size, -1)

        # 全连接层
        # 输入batch * 2000,输出batch * 500
        x = self.fc1(x)
        # 模型表达更加充分,保持shape不变
        x = F.relu(x)

        # 输入batch * 500 输出:batch * 10
        x = self.fc2(x)

        # 计算分类后,每个数字的概率值
        output = F.log_softmax(x, dim=1)
        return output


# 定义模型和优化器,优化模型参数
net = Net().to(DEVICE)
# 更新模型的参数
optimizer = optim.Adam(net.parameters())

# 定义训练方法
def train_model(model, device, dataset, optimizers, epochs):
    # 模型训练
    model.train()
    for batch_index, (data, target) in enumerate(dataset):
        # 部署到DEVICE上
        data, target = data.to(device), target.to(device)
        # 梯度初始化为0
        optimizers.zero_grad()
        # 训练后的结果
        output = model(data)
        # 计算交叉熵损失
        loss = F.cross_entropy(output, target)
        # 找到概率值最大的下标
        pred = output.max(1, keepdim=True)
        # 反向传播
        loss.backward()
        # 参数优化
        optimizers.step()
        if batch_index % 3000 == 0:
            print("Train Epoch: {} \t Loss : {:.6f}".format(epochs, loss.item()))

# 定义测试方法
def test_model(model, device, dataset):
    # 模型验证
    model.eval()
    # 正确率
    correct = 0.0
    # 测试损失
    test_loss = 0.0
    with torch.no_grad(): # 不会计算梯度,也不会进行反向传播
        for data, target in dataset:
            # 部署到device上
            data, target = data.to(device), target.to(device)
            # 测试数据
            output = model(data)
            # 计算测试损失
            test_loss += F.cross_entropy(output, target).item()
            # 找到概率最大的下标
            pred = output.max(1, keepdim=True)[1]
            # pred = torch.max(output, dim=1)
            # pred = output.argmax(dim=1)
            # 累积正确的值
            correct += pred.eq(target.view_as(pred)).sum().item()

        # 计算测试损失值
        test_loss /= len(dataset.dataset)
        print("Test -- Average loss: {:.4f}, Accuracy: {:.3f} \n".
              format(test_loss, 100 * correct / len(dataset.dataset)))


if __name__ == '__main__':
    # 开始训练,输出预测结果
    for epoch in range(1, EPOCHS + 1):
        train_model(net, DEVICE, train_loader, optimizer, epoch)
        test_model(net, DEVICE, test_loader)

官方MNIST 模型及训练、测试方法

# Pytorch官网mnist

# 导入库
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import transforms, datasets
from torch.utils.data import DataLoader
import torch.optim as optim

# 定义超参数
BATCH_SIZE = 64
EPOCHS = 10
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# pipeline
pipeline = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,))
])

# 下载、加载数据集
train_data = datasets.MNIST('data', train=True, transform=pipeline, download=True)
test_data = datasets.MNIST('data', train=False, transform=pipeline, download=True)

train_loader = DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True)
test_loader = DataLoader(test_data, batch_size=BATCH_SIZE, shuffle=True)

# 定义神经网络
class Net(nn.Module):

    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.dropout1 = nn.Dropout(0.25)
        self.dropout2 = nn.Dropout(0.5)
        self.fc1 = nn.Linear(9216, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = F.max_pool2d(x, 2)

        x = self.dropout1(x)
        x = torch.flatten(x, 1)

        x = self.fc1(x)
        x = self.dropout2(x)

        x = self.fc2(x)
        output = F.log_softmax(x, dim=1)
        return output


# 定义神经网络及优化器
net = Net().to(DEVICE)
optimizer = optim.Adadelta(net.parameters())

# 定义训练函数
def train_model(model, device, dataset, optimizers, epochs):
    model.train()
    for batch_index, (data, target) in enumerate(dataset):
        optimizers.zero_grad()
        data, target = data.to(device), target.to(device)
        output = net(data)
        loss = F.nll_loss(output, target)
        loss.backward()
        optimizers.step()
        if batch_index % 100 == 0:
            print('Train Epoch: {} \t loss: {:.6f}'.format(epochs, loss))


# 定义测试函数
def test_model(model, device, dataset):
    model.eval()
    test_loss = 0.0
    correct = 0.0
    with torch.no_grad():
        for data, target in dataset:
            data, target = data.to(device), target.to(device)
            output = model(data)
            test_loss += F.nll_loss(output, target, reduction='sum').item()  # sum up batch loss
            pred = output.argmax(dim=1, keepdim=True)  # get the index of the max log-probability
            correct += pred.eq(target.view_as(pred)).sum().item()

    test_loss /= len(dataset.dataset)

    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.2f}%)\n'.format(
        test_loss, correct, len(dataset.dataset), 100. * correct / len(dataset.dataset)
    ))


if __name__ == '__main__':
    for epoch in range(1, EPOCHS + 1):
        train_model(net, DEVICE, train_loader, optimizer, epoch)
        test_model(net, DEVICE, test_loader)



版权声明:本文为jiangyangll原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。