Pytorch深度学习——实现手写数字识别 06(未完)

1 思路和流程分析

  1. 准备数据,Dataloader
  2. 构建模型,使用torch构造一个深层的神经网络
  3. 模型的训练
  4. 模型的保存,后序持续使用
  5. 模型的评估,使用测试集,观察模型的好坏。

2 准备训练集和测试集

由05课已经知道,调用MNIST返回的结果中 图形数据是一个Image对象,需要对其进行处理。

为了进行数据的处理,学习torchvision.transforms的方法。

2.1 torchvision.transforms.ToTensor()

[H, W, C]转换最后的结果应该是[C, H, W] 的torch.floatTensor

import torchvision
import numpy as np
import torch
from torchvision import transforms

dataset = torchvision.datasets.MNIST(root='E:\study_self\LearnPytorch\dataset\mnist', train=True, download=False, transform=None)

data = np.random.randint(0, 225, size=12)
img = data.reshape(2, 2, 3)
print(img)  # np.array

img_tensor = torch.tensor(img)
img1 = img_tensor.transpose(0, 2)

img2 = transforms.ToTensor()(img)

img3 = img_tensor.permute(2, 0, 1)

img4 = img.permute(2, 0, 1)  # 报错,permute属性是torch.tensor


print("img1, img2", img1, img2)

注意:
(1)transposepermute 是 torch.tensor 的属性,注意不要用到 np.array 上。
(2) torchvision.transform 中的 ToTensor() 可以直接实例化,传入img 就可以自动生成 [C, H, W] 格式的数据了。

2.2 torchvision.transforms.Normalize(mean, std)

(1)mean: 均值指的是每个通道的均值
(2)std:方差指的是每个通道的方差

Normalized_image = (image - mean) / std
# 每个图片的值 - 均值,除以标准差
  • MNIST数据集是广泛使用的数据集,所以标准差和均值都是可以查出的,一般使用 0.137 和0.3081

2.3 torchvision.transforms.Compose(transforms)

  • 作用:将多个transform组合起来使用。
transforms.Compose([
    transforms.ToTensor(),  # 先转化为Tensor
    transforms.Normalize(mean=, std=)  # 在进行正则化
])

2.4 写Dataset 和 DataLoader

dataset = torchvision.datasets.MNIST(
    '../../dataset/mnist', train=True, download=False,
    transform=torchvision.transforms.Compose([
        torchvision.transforms.ToTensor(),
        torchvision.transforms.Normalize((0.130, ), (0.3081, ))
    ])
)

train_dataloader = torch.utils.data.DataLoader(dataset, batch_size=64, shuffle=True)

2.5 数据处理部分的代码

import torchvision
import numpy as np
import torch


from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from torchvision.transforms import Compose, ToTensor, Normalize

# 1.准备数据集

transform_fn = Compose([
    ToTensor(),
    Normalize(mean=(0.130,), std=(0.3081,))
])

# 注意,下面的root写mnist的路径
# 如果自己电脑上没有下载mnist,就给出一个位置
# 然后 download=True
dataset = MNIST(
    root='E:\study_self\LearnPytorch\dataset\mnist',
    train=True, download=False,
    transform=transform_fn
)


data_loader = DataLoader(dataset, batch_size=2, shuffle=True)


for i in enumerate(data_loader):
    print(i)

3 构建模型

class MnistModel(nn.Model):
    def __init__(self):
        super(MnistModel, self).__init__()
        self.fc1 = nn.Linear(1*28*28, 28)
        self.fc2 = nn.Linear(28, 10)  # 最后输出的是10个类别

    def forward(self, input):
        """

        :param input: [batch_size, 1, 28, 28]
        :return:
        """

        # 1.修改形状
        x = input.view([input.size(0), 1*28*28])  # 也可以写-1, 1*28*28
        # 2.进行全连接的操作
        x = self.fc1(x)
        # 3.进行激活函数的处理,形状是不会变化的
        x = F.relu(x)
        # 4.输出层
        out = self.f2(x)
        return out

【注意】 tensorflow是静态的,torch是动态的,所以可以写input.size(0)

3.1 损失函数

  • 二分类用sigmoid
  • 多分类用sofxmax
criterion = nn.CrossEntropyLoss()
loss = criterion(output, target)
import torchvision
import numpy as np
import torch
from torch import nn
from torch.optim import Adam

from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from torchvision.transforms import Compose, ToTensor, Normalize
import torch.nn.functional as F


BATCH_SIZE = 64
DATA_PATH = 'E:\study_self\LearnPytorch\dataset\mnist'


# 1.准备数据集
def get_dataloader(train=True):
    transform_fn = Compose([
        ToTensor(),
        Normalize(mean=(0.130,), std=(0.3081,))
    ])
    dataset = MNIST(
        root=DATA_PATH,
        train=train, download=False,
        transform=transform_fn
    )
    data_loader = DataLoader(dataset, batch_size=BATCH_SIZE, shuffle=True)
    return data_loader


# 2. 构建模型
class MnistModel(nn.Module):
    def __init__(self):
        super(MnistModel, self).__init__()
        self.fc1 = nn.Linear(1*28*28, 28)
        self.fc2 = nn.Linear(28, 10)  # 最后输出的是10个类别

    def forward(self, input):
        """
        :param input: [batch_size, 1, 28, 28]
        :return:
        """
        # 1.修改形状
        x = input.view([input.size(0), 1*28*28])  # 也可以写-1, 1*28*28  batch_size*1*28 *28
        # 2.进行全连接的操作
        x = self.fc1(x)
        # 3.进行激活函数的处理,形状是不会变化的
        x = F.relu(x)
        # 4.输出层
        out = self.fc2(x)
        return out

# criterion = nn.CrossEntropyLoss()
# loss = criterion(input, target)

model = MnistModel()
optimizer = Adam(model.parameters(), lr=0.001)

def train(epoch):
    """
    实现训练的过程
    :param epoch: 所有的样本都跑一遍,就是一个epoch
    :return:
    """
    data_loader = get_dataloader()
    for idx, (input, target) in enumerate(data_loader):
        # print("input.size", input.shape)  # torch.Size([64, 1, 28, 28])
        optimizer.zero_grad()
        output = model(input)  # 调用模型,得到预测值
        loss = F.nll_loss(output, target)  # 得到损失
        loss.backward()  # 反向传播
        optimizer.step()  # 梯度更新
        if idx%100==0:
            print(epoch, idx, loss.item())


if __name__ =="__main__":
    for i in range(3):
        train(i)

4 模型的保存与加载

4.1 保存

  • 保存模型所有的参数。
    # 模型的保存
    if idx%100==0:
        torch.save(model.state_dict(), "./model_save/model.pkl")
        torch.save(optimizer.state_dict(), "./model_save/optimizer.pkl")

4.2 加载

if os.path.exists("./model_save/model.pkl"):  # 判断路径是否存在
    # 模型的加载
    model.load_state_dict(torch.load("./model_save/model.pkl"))
    # 优化器的加载
    optimizer.load_state_dict(torch.load("./model_save/optimizer.pkl"))

猜你喜欢

转载自blog.csdn.net/weixin_42521185/article/details/127088925
今日推荐