【实战1】手写字识别 Pytoch:全连接神经网络

1 数据集

引用

import torch
from torch import nn ##nn创建神经网络
from torch.utils.data import DataLoader #DataLoader加载数据
from torchvision import datasets #datasets加载数据集
from torchvision.transforms import ToTensor #ToTensor将数据转换为张量

下载数据集 

# 下载数据
training_data = datasets.MNIST(
    root="data",
    train=True,
    download=True,
    transform=ToTensor()
)

testing_data = datasets.MNIST(
    root="data",
    train=False,
    download=True,
    transform=ToTensor()
)

导入数据

# 加载数据
batch_size = 64
train_dataloader = DataLoader(training_data, batch_size=batch_size)
test_dataloader = DataLoader(testing_data, batch_size=batch_size)

# 打印第一个批次的数据形状 
for X, y in train_dataloader:
    print(f"Shape of X [N, C, H, W]: {X.shape}")
    print(f"Shape of y: {y.shape} {y.dtype}")
    break

2 构建神经网络的方法

2.1 构建神经网络

定义神经网络类,继承自nn.Moudule

Pytorch使用nn.Sequentail对象创建神经网络

神经网络必须实现前向传播forward()方法

使用nn.Flatten对象将图片转成列列向量【对比Kares ,pytorch是面向对象的思路】

nn.to方法可以让模型运行在不同的硬件上

device = (
    "cuda"
    if torch.cuda.is_available()
    else "mps"
    if torch.backends.mps.is_available() 
    else "cpu"
    )

# 打印设备信息
print(f"Using {device} device")

# 构建神经网络 2层 输入28*28,第一层128个神经元,激活函数relu,第二层10个神经元
class NeunalNetwork(nn.Module):
    def __init__(self):
        super().__init__()
        self.nmodel = nn.Sequential(
            nn.Linear(28*28, 128), # 输入层到隐藏层 
            nn.ReLU(), # 激活函数
            nn.Linear(128, 10) # 隐藏层到输出层
        )

    def forward(self, x):
        x = nn.Flatten(1)(x) # 将输入展平
        output = self.nmodel(x) #对模型训练
        return output
        
model = NeunalNetwork().to(device)
print(model)

2.2 训练神经网络

指定model模式:train训练
循环读取小批量数据
进行训练:前向传播
通过损失函数计算本次的损失

损失函数:

回归:均方差nn.MESLoss、平均绝对差nn.L1Loss

多分类:交叉熵nn.CrossEntopyLoss 包含了softmax、nn.NULLLoss需手动添加softmax

反向传播,计算梯度

优化器:

SGD 随机梯度下降

Adam 最佳优化器

RMSprop

更新梯度
清空本次小批量梯度,确保每次小批次都重新计算梯度
loss_fn = nn.CrossEntropyLoss()  # 交叉熵损失函数 多分类
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)  # 随机梯度下降优化器
# 训练神经网络
def train(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)  # 数据集大小
    model.train()  # 设置模型为训练模式
    train_correct, train_loss = 0, 0
    for bacth, (X, y) in enumerate(dataloader):
        X, y = X.to(device), y.to(device) # 将数据移动到GPU/或CPU上
        pred = model(X)
        loss = loss_fn(pred, y)
        loss.backward()  # 反向传播后,计算出梯度
        optimizer.step()  # 使用优化器,更新参数
        optimizer.zero_grad()  # 清除本次梯度
        
        train_loss += loss.item()  # 获取损失
        train_correct += (pred.argmax(1) == y).type(torch.float).sum().item()  # 计算正确率

        if bacth % 100 == 0:
            loss, current = loss.item(), bacth * len(X)
            print(f"loss: {loss:>7f}  [{current:>5d}/{size:>5d}]")

    train_loss /= len(dataloader)  # 所有的损失/所有批次=平均损失
    correct /= size  # 所有的正确数/所以样本=平均正确率

    print(f"Trian Error: \n Accuracy: {(100*train_correct):>0.1f}%, Avg loss: {train_loss:>8f} \n")  # 打印平均正确率和平均损失

2.3 评估神经网络

指定model模式:eval训练
禁止梯度计算与跟踪,测试阶段不需要计算梯度
进行预测:前向传播
损失函数计算损失
# 评估神经网络
def test(dataLoader, model, loss_fn):
    size = len(dataLoader.dataset)  # 数据集大小
    num_batches = len(dataLoader)  # 获取批次数
    model.eval()  # 设置模型为评估模式
    with torch.no_grad():  # 在评估时不需要计算梯度
        for X, y in dataLoader:
            X, y = X.to(device), y.to(device)
            pred = model(X)
            test_loss += loss_fn(pred, y).item() # 计算损失累加,需要张量转为python数值
            correct += (pred.argmax(1) == y).type(torch.float).sum().item() # 获取64y样本最大可能性对比y,累加后,计算正确预测的数量

        test_loss /= num_batches  # 所有损失/所有批次=平均损失
        correct /= size  # 所有的正确数/所以样本=平均正确率
        
    print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")  # 打印平均正确率和平均损失

 2.4 开始训练与评估

epochs = 5  # 训练轮数
for epoch in range(epochs):
    print(f"Epoch {epoch+1}\n-------------------------------")
    train(train_dataloader, model, loss_fn, optimizer)  # 训练模型
    test(test_dataloader, model, loss_fn)  # 测试模型
print("Done!")  # 训练完成

3 模型保存部署与使用

3.1 保存模型

# 部署模型:模拟在服务器上,将模型加载进来
saved_model = NeunalNetwork().to(device)  # 将模型加载到设备上
model_weight_only=torch.load("model_weight.pth", weights_only=True)  # 加载:已有的模型参数
saved_model.load_state_dict(model_weight_only)  # 导入:将加载的参数应用到模型中

3.2 部署与使用

saved_model.eval()  # 设置模型为评估模式
# 测试部署模型
x, y = next(iter(test_dataloader))  # 获取测试数据的第一个批次
# 获取测试数据的第一批次的第一个样本和标签
x, y = x.to(device), y.to(device)  # 将数据移动到设备
with torch.no_grad():  # 在评估时不需要计算梯度
    pred = saved_model(x)  # 使用部署模型进行预测
    print(f"Predicted: {pred.argmax(1)}")  # 打印预测结果
    print(f"Actual: {y}")  # 打印实际标签

import matplotlib.pyplot as plt  # 导入matplotlib库用于绘图
plt.imshow(x[0].cpu().numpy().squeeze(), cmap='gray')  # 显示第一个测试样本的图像
plt.title(f"Predicted: {pred.argmax(1)[0].item()}, Actual: {y[0].item()}")  # 设置图像标题
plt.axis('off')  # 关闭坐标轴显示
plt.show()  # 显示图像

4 评估与神经网络优化

优化点:增加层数
class NeunalNetwork(nn.Module):
    def __init__(self):
        super().__init__()
        self.nmodel = nn.Sequential(
            nn.Linear(28*28, 128), # 输入层到隐藏层 
            nn.BatchNorm1d(128), # 优化点:批归一化层
            nn.ReLU(), # 激活函数
            nn.Dropout(0.2), # 优化点:Dropout层,防止过拟合
            nn.Linear(128, 10) # 隐藏层到输出层
        )

    def forward(self, x):
        x = nn.Flatten(1)(x) # 将输入展平
        output = self.nmodel(x) #对模型训练
        return output
优化点:轮次、数据打乱、批次
epochs = 10  # 训练轮数加大 一般更优
batch_size = 64 # batch_size  变大 更稳定
# 加载数据 shuffle
train_dataloader = DataLoader(training_data, batch_size=batch_size, shuffle=True)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值