以前一直纠结数据处理的部分,究竟数据集要处理成什么样子才能被卷积,害~现在看来是我多虑,把它看复杂了……如果又小伙伴有同样的困惑,可以留言。
代码:有注释,应该容易看懂

import torch
import torch.nn as nn  # pytorch提供设计的模块和类
import torch.nn.functional as F  # 对几个输入平面组成的输入信号应用1D卷积。
import torch.optim as optim  # 实现了各种优化算法的库
from torchvision import datasets, transforms  # datasets包含了目前流行的数据集,transforms包含常用的图片转换工具。
from torch.utils.data import DataLoader

BATCH_SIZE = 28  # 每批处理的数据
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")  # 启用GPU
EPOCHS = 20  # 训练数据集的轮数

# 构造pipeline,torchvision.transforms将PIL Image或者 ndarray 转换为tensor,
# 并且归一化至[0-1] 注意事项:归一化至[0-1]是直接除以255,若自己的ndarray数据尺度有变化,则需要自行修改。
# transforms.Normalize对数据按通道进行标准化,即先减均值,再除以标准差。
pipeline = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,))
])

# 通过datasets函数引入MNIST数据集
# root是数据的位置,train=True是下载训练有关的数据集,download是决定是否下载数据
train_set = datasets.MNIST(root='Mnistdata',
                           train=True,
                           transform=pipeline,
                           download=True)

test_set = datasets.MNIST(root='Mnistdata',
                          train=False,
                          transform=pipeline,
                          download=True)
print(train_set)

# 加载数据
# dataset:传入的数据
# shuffle = True:是否打乱数据
# batch_size:每批处理的数据个数
train_loader = DataLoader(train_set, batch_size=BATCH_SIZE, shuffle=True)
test_loader = DataLoader(test_set, batch_size=BATCH_SIZE, shuffle=True)


# 构建网络模型
# 定义网络模型用到的层
class Digit(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 10, 5)  # 第一个卷积层,1:灰度图片的通道,10:输出通道(自己定义的,还可以是20,32等等),5:卷积核(5x5)
        self.conv2 = nn.Conv2d(10, 20, 3)  # 第二个卷积层,10:输入通道,20:输出通道,3:Kernel(卷积核)
        self.fc1 = nn.Linear(20 * 10 * 10, 500)  # 第一个全连接层,20*10*10:输入通道,500:输出通道
        self.fc2 = nn.Linear(500, 10)  # 第二个全连接层,500:输入通道,10:输出通道

    # 向前传播,将各层连接起来
    def forward(self, x):
        input_size = x.size(0)  # x.size(0)指batchsize的值
        x = self.conv1(x)  # 第一个卷积层,输入:batch*1*28*28,输出:batch*10*24*24(28-5+1=24)
        x = F.relu(x)  # 激活函数
        x = F.max_pool2d(x, 2, 2)  # 池化层,输入:batch*10*24*24,输出:batch*10*12*12

        x = self.conv2(x)  # 第二个卷积层,输入:batch*10*12*12,输出:batch*20*10*10
        x = F.relu(x)  # 激活函数

        x = x.view(input_size, -1)  # 输入全连接层之前要拉平数据,例如多维数据变成一维数据,-1表示自动计算维度,这里是batch*20*10*10

        x = self.fc1(x)  # 第一个全连接层,输入:batch*2000,输出:batch*500
        x = F.relu(x)

        x = self.fc2(x)  # 第二个全连接层,输入:batch*500,输出:batch*10
        output = F.log_softmax(x, dim=1)  # 激活函数,计算分类,每个数字的概率
        return output


# 优化器,使模型找到最佳参数
model = Digit().to(DEVICE)  # Digit()是前面的网络模型,把device添加到Digit里
optimizer = optim.Adam(model.parameters())  # parameters()获取model的函数并传入给优化函数

# 定义训练方法


def train_model(model, device, train_loader, optimizer, epoch):
    # 模型训练
    model.train()
    for batch_index, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)  # 部署到DEVICE上
        optimizer.zero_grad()  # 梯度初始化为0
        output = model(data)  # 训练后的结果
        loss = F.cross_entropy(output, target)  # 计算损失
        loss.backward()  # 反向传播
        optimizer.step()
        output = output.argmax(dim=1)
        if batch_index % 3000 == 0:
            print("Train Epoch : {} \t Loss : {:.6f}".format(epoch, loss.item()))


def test_model(model, device, test_loader):
    model.eval()  # 模型验证
    correct = 0.0  # 正确率
    test_loss = 0.0  # 测试损失
    with torch.no_grad():  # 不会计算梯度,也不会进行反向传播
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)  # 部署到device上
            output = model(data)  # 测试数据
            # test_loss += F.cross_entropy(output, target).item()  # 计算测试损失
            # output = output.argmax(dim=1)
            pred = output.max(1, keepdim=True)[1]  # 值,索引
            correct += pred.eq(target.view_as(pred)).sum().item()
        test_loss /= len(test_loader.dataset)
        print("Test-Average loss : {:.4f}, Accuracy : {:.3f}\n".format(test_loss, 100.0*correct / len(test_loader.dataset)))


# 调用
for epoch in range(1, EPOCHS+1):
    train_model(model, DEVICE, train_loader, optimizer, epoch)
    test_model(model, DEVICE, test_loader)