LeNet复现-Pytorch版本

本文介绍了一个基于PyTorch实现的手写数字识别LeNet模型,包括模型定义、训练过程及单张图片预测方法。通过MNIST数据集进行训练,并详细展示了训练流程与评估指标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

模型

from torch import nn


class Lenet(nn.Module):  # 继承Moudle,后面没有括号
    def __init__(self, in_dim, n_class):
        super().__init__()

        self.conv1 = nn.Sequential(
            nn.Conv2d(in_channels=in_dim, out_channels=20, kernel_size=5, stride=1, padding=2),  # (20, 28, 28)
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2)  # (20, 14, 14) 池化不会改变通道数
        )

        self.conv2 = nn.Sequential(
            nn.Conv2d(in_channels=20, out_channels=50, kernel_size=5, stride=1, padding=2),  # (50, 14, 14)
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2)  # (50, 7, 7)
        )

        # fully_connected 两层
        self.fc = nn.Sequential(
            nn.Linear(in_features=2450, out_features=500),  # (50 * 7 * 7, 500) 降维
            nn.ReLU(),
            nn.Linear(in_features=500, out_features=n_class)  # (500, 10)
        )

    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        # flatten之后送入全连接
        x = x.view(x.size(0), -1)
        output = self.fc(x)  # 不需要softmax,因为CrossEntropyLoss做了softmax的处理

        return output

训练

import torch
from torch import nn
from LeNet import Lenet
from torch.utils.data import DataLoader
from torchvision import datasets, transforms


def get_datasets():
    train_dataset = datasets.MNIST(
        root='./data/mnist',
        train=True,
        transform=transforms.ToTensor(),
        download=True,
    )
    test_dataset = datasets.MNIST(
        root='./data/mnist',
        train=False,
        transform=transforms.ToTensor()
    )
    train_loader = DataLoader(
        dataset=train_dataset,
        batch_size=batch_size,
        shuffle=True
    )
    test_loader = DataLoader(
        dataset=test_dataset,
        batch_size=batch_size,
        shuffle=False
    )

    return train_loader, test_loader


def evaluate_accuracy(data_iter, model):
    total = 0
    correct = 0
    with torch.no_grad():
        for images, labels in data_iter:
            model.eval()
            images = images.to(device)
            labels = labels.to(device)
            outputs = model(images)
            _, predicts = torch.max(outputs.data, 1)
            total += labels.size(0)
            correct += (predicts == labels).cpu().sum()

    return 100 * correct / total


def train(learning_rate, num_epochs, train_loader, test_loader, model):
    # 设置随机种子,确保结果可重复
    torch.manual_seed(1)
    # Adam optimizer
    optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
    criterion = nn.CrossEntropyLoss()

    for epoch in range(num_epochs):
        print('current epoch = %d' % epoch)
        train_accuracy_total = 0
        train_correct = 0
        train_loss_sum = 0
        for i, (images, labels) in enumerate(train_loader):
            train_accuracy_total = 0
            train_correct = 0
            train_loss_sum = 0
            model.train()
            images = images.to(device)
            labels = labels.to(device)
            # forward
            outputs = model(images)
            # calculate current iteration's loss
            loss = criterion(outputs, labels)
            # reset grad graph
            optimizer.zero_grad()
            # backward -
            loss.backward()
            # update parameters
            optimizer.step()
            train_loss_sum += loss.item()
            _, predicts = torch.max(outputs.data, dim=1)  # dim=1 表示按照行求最大值,和其索引
            train_accuracy_total += labels.size(0)
            train_correct += (predicts == labels).cpu().sum().item()
        test_acc = evaluate_accuracy(test_loader, model)
        print('epoch %d, loss %.4f, train accuracy %.3f,'
              ' test accuracy %.3f' %
              (epoch, train_loss_sum / batch_size, train_correct / train_accuracy_total, test_acc))
    torch.save(model, 'lenet.pth')
    print('finish training')


def main():
    model = Lenet(1, 10)  # 单通道灰度图像,数字图像10分类问题,实例化模型
    model.to(device)  # 放到gpu上
    learning_rate = 1e-3  # 学习率
    num_epochs = 10  # epoch num
    # 获取数据集
    train_loader, test_loader = get_datasets()
    # train
    train(learning_rate=learning_rate, num_epochs=num_epochs, train_loader=train_loader, test_loader=test_loader,
          model=model)


if __name__ == '__main__':
    # global variables
    batch_size = 64
    device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
    main()

单张预测:

import torch
from LeNet import Lenet
from PIL import Image
from torchvision import datasets, transforms


def main():
    # 使用gpu训练的话,模型的参数类型是torch.cuda.FloatTensor所以需要to device
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

    # 这里还有一个中括号
    transform = transforms.Compose([
        transforms.Resize((28, 28)),
        transforms.ToTensor()
    ])

    test_img = Image.open('number.jpeg')
    test_img = test_img.convert('L')
    print(test_img.size)  # [1115, 1115]
    test_img = transform(test_img)
    test_img = torch.unsqueeze(test_img, dim=0)
    print(test_img.size())  # [1, 1, 28, 28]
    model = torch.load('./lenet.pth')
    model.eval()

    with torch.no_grad():

        test_img = test_img.to(device)  # 使用Gpu训练得到的模型参数是
        print('test_img data type', test_img.dtype)
        output = model(test_img)
        print(output.dtype)
        _, predict = torch.max(output, dim=1)
        print(type(predict))
        print(predict)  # cuda tensor
        print(predict.cpu())  # tensor
        print('预测为数字 ', predict.item())


if __name__ == '__main__':
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Klaus1205

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值