机器学习 pytorch搭建一个最简单的手写数字识别网络

本文参考了互联网上的一些资料,基于个人理解。

一、搭建神经网络

先在根目录下创建一个data文件夹,用来放下载的数据集

1.需要用的包

import torch
import torch.nn as nn
from torch import optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms

2.准备训练用的数据

# 定义transform为这两个函数的集合
transform = transforms.Compose([
    transforms.ToTensor(),  # 图像转换为张量
    transforms.Normalize((0.1307,), (0.3081,))  # 标准化图像数据
])

'''下载训练集数据集(包含训练图片和标签)'''
# datasets.MNIST来加载MNIST数据集作为训练数据集。
# root='data':指定数据集存储的根目录,可以根据需要进行更改。
# train=True:表示加载训练数据集,反之则是测试数据集
# download=True:如果数据集在指定路径中不存在,将自动从官方源下载并保存。
# transform=ToTensor():指定数据转换操作,将图像数据转换为PyTorch中的Tensor张量格式。
train_dataset = datasets.MNIST(
    root='data',
    train=True,
    download=True,
    transform=transform,  # 张量
)  # 对于pythorch库能够识别的数据一般是tensor张量

test_dataset = datasets.MNIST(
    root='data',
    train=False,
    download=True,
    transform=transform
)

张量可以理解为不管几维都可以的不管什么类型都可以的数据类型,为了避免类型冲突,统一转成张量处理。

3.对数据做一些处理


# 创建加载器,指定数据集,指定batch的数量为64,shuffle指定是否打乱数据


train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)

4.创建神经网络

# 继承构造神经网络的基类
class SimpleNN(nn.Module):

    # 构造方法
    def __init__(self):

        # 找到SimpleNN的父类,用子类实体创建父类实体,实现用子类实体调用父类方法和参数
        super(SimpleNN, self).__init__()

        # 全连接层
        self.fc1 = nn.Linear(28 * 28, 128)
        self.fc2 = nn.Linear(128, 64)
        self.fc3 = nn.Linear(64, 10)

    # 前向传播,计算函数
    def forward(self, x):

        # 把x展成m*n维,给定了n=28*28, -1代表自行计算n的数值
        x = x.view(-1, 28 * 28)

        # 激活函数
        x = torch.relu(self.fc1(x))
        x = torch.relu(self.fc2(x))
        x = self.fc3(x)
        return x
  • self.fc1 是一个 nn.Linear 类的实例,它在类 SimpleNN 的构造函数中被定义为一个全连接(线性)层。这个层的定义形式是 nn.Linear(in_features, out_features),其中 in_features 是输入特征的数量,out_features 是输出特征的数量。
  • 当你调用 self.fc1(x) 时,实际上是在执行这个全连接层的前向传播操作。x 是这个操作的输入张量,它通过全连接层的权重矩阵进行线性变换,然后加上偏置。如果 x 的形状是 [N, in_features](N 是批量大小),那么输出的形状将会是 [N, out_features]
  • torch.relu 是一个函数,用于应用激活函数 ReLU(Rectified Linear Unit,修正线性单元)。ReLU 函数的公式是 f(x) = max(0, x),它的作用是将所有的负值置为0,正值保持不变。这是深度学习中常用的激活函数,因为它能够在保持非线性的同时,减轻梯度消失的问题。
  • 在这行代码中,torch.relu 被用来对 self.fc1(x) 的输出应用 ReLU 激活函数。这样做的目的是增加网络的非线性能力,因为线性模型的表达能力是有限的,而通过加入非线性激活函数,网络能够学习到更复杂的模式。

5.损失函数和优化器

model = SimpleNN()

# 交叉熵损失,定义损失函数
criterion = nn.CrossEntropyLoss()

# 优化器,包括随机梯度下降、adam、rmsprop等
optimizer = optim.Adam(model.parameters(), lr=0.001)

最原始的优化器是梯度下降算法,一些算法在此基础上作出了改进。

6.模型训练

def train(model, train_loader, criterion, optimizer, epochs):
    for epoch in range(epochs):
        # 每一轮开始时重置损失值
        running_loss = 0.0
        # enumerate 返回可迭代数据的元组,元组内容为id、data
        for i, (images, labels) in enumerate(train_loader):

            optimizer.zero_grad()
            outputs = model(images)
            # 计算损失值
            loss = criterion(outputs, labels)
            # 计算梯度,反向回传,存在grad属性里
            loss.backward()
            
            optimizer.step()
            # 累加当前的batch的损失值到变量中
            running_loss += loss.item()
            if (i + 1) % 100 == 0:
                print(
                    f'Epoch [{epoch + 1}/{epochs}], Step [{i + 1}/{len(train_loader)}], Loss:{running_loss / 100:.4f}')
                running_loss = 0.0

# 训练模型
train(model, train_loader, criterion, optimizer, epochs=5)

三兄弟,顺序不能颠倒

optimizer.zero_grad()   清除上一个batch累计的梯度

loss.backward()            反向回传求w存到参数grad中

optimizer.step()             执行梯度下降算法

7.测试模型

def test(model, test_loader):
    # 切换到评估模式
    model.eval()
    # 记录预测正确的样本数和总样本数
    correct = 0
    total = 0
    # 禁止自动求梯度
    with torch.no_grad():
        for images, labels in test_loader:
            outputs = model(images)
            # predicted用来记录最大输出数据的索引,返回最大值和索引,dim=1按行输出,=0按列输出
            _, predicted = torch.max(outputs.data, 1)
            # 总样本
            total += labels.size(0)
            # 累计正确样本数
            correct += (predicted == labels).sum().item()
    print(f'Accuracy on test set: {100 * correct / total:.2f}%')


# 调用
test(model, test_loader)

二、预测一个看看

1.需要用的包

另开了一个文件

import torch
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt

from model import model

2.再把测试集调出来

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

test_dataset = datasets.MNIST(root='./data', train=False, transform=transform, download=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)

# 没有这句也一样好像
model = model  

3.测试+图形化

其实跟上一个test没啥区别,只是多了个图形化

def predict_images(model, data_loader, num_images=5):
    model.eval()  # 设置为评估模式

    # 把测试加载器转成迭代类型,用next拿数据
    images, labels = next(iter(data_loader))
    images, labels = images[:num_images], labels[:num_images]  # 取前num_images张图片进行预测

    with torch.no_grad():  # 不计算梯度
        outputs = model(images)
        _, predicted = torch.max(outputs, 1)  

    # 显示图片和预测结果
    plt.figure(figsize=(10, num_images * 2))
    for idx in range(num_images):
        plt.subplot(1, num_images, idx + 1)
        plt.imshow(images[idx].numpy().squeeze(), cmap='gray')  # 显示图片
        plt.title(f'Predicted: {predicted[idx].item()}')  # 显示预测的类别
        plt.axis('off')
    plt.show()


# 使用测试集的一个batch进行预测展示
predict_images(model, test_loader, num_images=5)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值