Pytorch实战 | P1 实现mnist手写数字识别(深度学习实践pytorch)

一、数据准备与模型调用(Main.py)

# --- 1、GPU设置 ---
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# --- 2、导入数据 ---
# 获取训练集
train_ds = torchvision.datasets.MNIST('data', train=True, transform=torchvision.transforms.ToTensor(), download=False)

print(len(train_ds))
# 获取测试集
test_ds = torchvision.datasets.MNIST('data', train=False, transform=torchvision.transforms.ToTensor(), download=False)

batch_size = 32

train_dl = torch.utils.data.DataLoader(train_ds,
                                       batch_size=batch_size,
                                       shuffle=True)
test_dl = torch.utils.data.DataLoader(test_ds, batch_size=batch_size)

imgs, labels = next(iter(train_dl))
print(imgs.shape)

# --- 3、数据可视化 ---
plt.figure(figsize=(20, 5))
for i, imgs in enumerate(imgs[:20]):
    npimg = np.squeeze(imgs.numpy())
    plt.subplot(2, 10, i + 1)
    plt.imshow(npimg, cmap=plt.cm.binary)
    plt.axis('off')
plt.show()


# --- 模型参数设置
model = Model().to(device)
# summary(model)

loss_fn = nn.CrossEntropyLoss()  # 创建损失函数
learn_rate = 1e-2  # 学习率
opt = torch.optim.SGD(model.parameters(), lr=learn_rate)

# --- 4、模型训练 ---
epochs = 1
train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
    model.train()
    epoch_train_acc, epoch_train_loss = model.train1(train_dl, model, loss_fn, opt)

    # model.eval()
    # epoch_test_acc, epoch_test_loss = model.test1(test_dl, model, loss_fn)
    #
    # train_acc.append(epoch_train_acc)
    # train_loss.append(epoch_train_loss)
    # test_acc.append(epoch_test_acc)
    # test_loss.append(epoch_test_loss)
    #
    # template = 'Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%,Test_loss:{:.3f}'
    #
    # print(template.format(epoch + 1, epoch_train_acc * 100, epoch_train_loss, epoch_test_acc * 100, epoch_test_loss))
    # print('Done')

# --- 5、结果可视化 ---
import matplotlib.pyplot as plt
# 隐藏警告
import warnings

# warnings.filterwarnings("ignore")  # 忽略警告信息
# plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
# plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
# plt.rcParams['figure.dpi'] = 100  # 分辨率
#
# epochs_range = range(epochs)
#
# plt.figure(figsize=(12, 3))
# plt.subplot(1, 2, 1)  # 1行2列  后面1表示图的编号
#
# plt.plot(epochs_range, train_acc, label='Training Accuracy')
# plt.plot(epochs_range, test_acc, label='Test Accuracy')
# plt.legend(loc='lower right')
# plt.title('Training and Validation Accuracy')
#
# plt.subplot(1, 2, 2)
# plt.plot(epochs_range, train_loss, label='Training Loss')
# plt.plot(epochs_range, test_loss, label='Test Loss')
# plt.legend(loc='upper right')
# plt.title('Training and Validation Loss')
# plt.show()

# --- 6、单个图片预测 ---
# 从测试集中找一个图片来测试

for X, y in test_dl:
    print(y.shape)
    print(y)
    plt.figure(figsize=(2, 2))
    npimg = np.squeeze(X[1:2, :].numpy())
    plt.subplot(1, 1, 1)
    plt.imshow(npimg, cmap=plt.cm.binary)
    plt.axis('off')
    plt.show()
    Z = X[1:2, :]
    print(Z.shape)
    result = model.predict(Z, model)
    item1 = result.item()
    item2 = y[1].item()
    print('real:' + str(item2))
    print('predict:' + str(item1))
    print('结束一轮')

二、模型构建、训练与预测(Model.py)

import torch
import torch.nn.functional as F
import torch.nn as nn

num_classes = 10  # 图片的类别
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")


class Model(nn.Module):
    def __init__(self):
        super().__init__()
        # 特征提取网络构建
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3)  # 第一层卷积,卷积核大小为3*3
        self.pool1 = nn.MaxPool2d(2)  # 设置池化层,池化核大小为2*2
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3)  # 第二层卷积,卷积核大小为3*3
        self.pool2 = nn.MaxPool2d(2)

        # 分类网络
        self.fc1 = nn.Linear(1600, 64)
        self.fc2 = nn.Linear(64, num_classes)

    # 前向传播方法
    def forward(self, x):
        x = self.pool1(F.relu(self.conv1(x)))
        x = self.pool2(F.relu(self.conv2(x)))

        x = torch.flatten(x, start_dim=1)

        x = F.relu(self.fc1(x))
        x = self.fc2(x)

        return x

    # 模型训练
    def train1(self, dataloader, model, loss_fn, optimizer):
        size = len(dataloader.dataset)  # 训练集大小,一共6000张图片
        num_batches = len(dataloader)  # 批次数目, 6000/32 = 1875

        train_loss, train_acc = 0, 0  # 初始化训练损失和正确值
        i = 0
        for X, y in dataloader:  # 获取图片及其标签
            X, y = X.to(device), y.to(device)

            # 计算预测误差
            pred = model.forward(X)  # 网络输出

            loss = loss_fn(pred, y)  # 计算网络输出和真实值之间的差距,targets真实值,计算二者差值即为损失 (pred为minibatch的预测类别的概率, y为所属类别的索引)

            # 反向传播
            optimizer.zero_grad()  # grad属性归零
            loss.backward()  # 反向传播
            optimizer.step()  # 每一步自动更新

            # 记录acc  argmax(1)求每行 最大值的索引值  添加batch里面正确预测的个数。 argmax(0)表示求列最大值的索引
            train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()
            train_loss += loss.item()
        # 跑完一个epoch,计算所有图片的平均预测准确率
        train_acc /= size
        # 跑完一个epoch,计算所有batch的平均loss
        train_loss /= num_batches

        return train_acc, train_loss

    # 模型测试
    def test1(self, dataloader, model, loss_fn):
        size = len(dataloader.dataset)  # 测试集的大小,一共10000张图片
        num_batches = len(dataloader)  # 批次数目,313(10000/32=312.5,向上取整)

        test_loss, test_acc = 0, 0  # 初始化训练损失和正确值

        # 当不尽兴训练时,停止梯度更新,节省计算内存消耗
        with torch.no_grad():
            for imgs, target in dataloader:
                imgs, target = imgs.to(device), target.to(device)

                # 计算loss
                target_pred = model(imgs)
                loss = loss_fn(target_pred, target)

                test_loss += loss.item()
                test_acc += (target_pred.argmax(1) == target).type(torch.float).sum().item()

        test_acc /= size
        test_loss /= num_batches

        return test_acc, test_loss

    def predict(self, img, model):
        pt = model.forward(img)
        result = pt.argmax(1)
        return result

你可能感兴趣的:(深度学习实践100例,深度学习,人工智能,机器学习)