Notion Blog
知行合一1 分钟阅读

torch,MNIST实践

import torch
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np

# 定义神经网络
class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # 卷积层Conv2d输入通道数1,输出通道数5,卷积核大小6x6。输入图像大小为(H,W),
				 # 经过conv1输出特征图大小为(H-5,W-5)。
        self.conv1 = torch.nn.Conv2d(1, 5, 6)
        # 第二卷积层Conv2d的参数个第一个参数是输入的通道数量是上一个输出数量5,第二个是输出的通道数量8,第三个是神经核数量5*5
        self.conv2 = torch.nn.Conv2d(5, 8, 5)
        # 池化层 池化核大小为2x2,步长为2。特征图大小变为(H-5)/2,(W-5)/2。每一次卷积层都要处理一次
        self.pool = torch.nn.MaxPool2d(2, 2)
        # 由于上一层有16个channel输出,每个feature map大小为3*3,所以全连接层的输入是8*3*3,
				 # ((原始数据 H-第一次卷积核数量)/2-第二次卷积核数量)/2 在四舍五入 * ((原始数据 W-第一次卷积核数量)/2-第二次卷积核数量)/2 在四舍五入
        self.fc1 = torch.nn.Linear(8*3*3, 120)
        self.fc2 = torch.nn.Linear(120, 84)
        self.fc3 = torch.nn.Linear(84, 10)
        # 最终有10类,所以最后一个全连接层输出数量是10

    def forward(self, x):
        x = self.pool(torch.nn.functional.relu(self.conv1(x)))
        x = self.pool(torch.nn.functional.relu(self.conv2(x)))
        x = x.view(-1, 8*3*3) #第二个参数数据要和上面的fc1 的第一个参数一致
        x = torch.nn.functional.relu(self.fc1(x))
        x = torch.nn.functional.relu(self.fc2(x))
        x = self.fc3(x)
        return x


def Training():
    net = Net()
    # 定义数据预处理
    transform = transforms.Compose(
        [transforms.ToTensor(),
         transforms.Normalize((0.5,), (0.5,))])

    # 加载数据集
    trainset = torchvision.datasets.MNIST(root='./data', train=True,
                                            download=True, transform=transform)
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=1,
                                              shuffle=True,)

    # 定义损失函数和优化器
    criterion = torch.nn.CrossEntropyLoss()
    optimizer = torch.optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

    # 训练网络
    for epoch in range(1):  # 多次循环遍历数据集
        running_loss = 0.0
        for i, data in enumerate(trainloader, 0):
            inputs, labels = data
            # 首先要把梯度清零,不然PyTorch每次计算梯度会累加,不清零的话第二次算的梯度等于第一次加第二次的
            optimizer.zero_grad()
            # 计算前向传播的输出
            outputs = net(inputs)
            # 根据输出计算loss
            loss = criterion(outputs, labels)
            # print(loss,labels)
            # 算完loss之后进行反向梯度传播,这个过程之后梯度会记录在变量中
            loss.backward()
            # 用计算的梯度去做优化
            optimizer.step()
            running_loss += loss.item()
            if i % 2000 == 1999:    # 每 2000 批次打印一次平均损失值
                print('[%d, %5d] loss: %.3f' %
                      (epoch + 1, i + 1, running_loss / 2000))
                running_loss = 0.0
                # show_images(inputs,labels)
            # print(outputs)
            # break
    # 保存模型
    torch.save(net.state_dict(), 'mnist_cnn.pth')
    print('Finished Training')

def show_images(images,labels):
    img = torchvision.utils.make_grid(images)
    img = img.numpy().transpose(1, 2, 0)
    std = [0.5, 0.5, 0.5]
    mean = [0.5, 0.5, 0.5]
    img = img * std + mean
    print(labels)
    plt.imshow(img)
    plt.show()

def test_load(path):
    img = Image.open(path)
    img = img.convert('L')  # 转为灰度图
    img = img.resize((28, 28))  # 改为28x28
    img = np.array(img)
    img = (img / 255 - 0.5) / 0.5  # 标准化数据值在-1到1
    img = img[np.newaxis, np.newaxis, :, :]  # 增加batch和channel维度
    img = torch.Tensor(img)
    return img

#训练和测试一体
def custom_training(img_path,result=None):
    model = Net()
    model.load_state_dict(torch.load('mnist_cnn.pth'))
    # 切换到预测模式
    model.eval()
    criterion = torch.nn.CrossEntropyLoss()
    optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
    img = test_load(img_path)
    outputs = model(img)
    _, predicted = torch.max(outputs.data, 1)
    if result != None:
        labels = torch.tensor([result],dtype=torch.int64)
        # 根据输出计算loss
        l = 1
        while l !=0:
            optimizer.zero_grad()
            # 计算前向传播的输出
            outputs = model(img)
            flattened_tensor = outputs.view(-1)
            # 找到最大值的索引
            max_value_index = torch.argmax(flattened_tensor)
            if max_value_index == result:
                break
            loss = criterion(outputs, labels)
            # 算完loss之后进行反向梯度传播,这个过程之后梯度会记录在变量中
            loss.backward()
            # 用计算的梯度去做优化
            optimizer.step()
            l=loss
					#保存模型
        torch.save(model.state_dict(), 'mnist_cnn.pth')
        print('Finished Training',optimizer)
    else:
        print(outputs)
        print(predicted)


Training()
# test_model()
# test_custom_model('test_3.png')
# custom_training('test9.png'

有关使用上的问题,欢迎您在底部评论区留言,一起交流~

读者评论

评论会同步写入该文在 Notion 中的页面底部(与正文同页,便于管理)。

0/1500

暂无评论,欢迎抢沙发。