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"))

5 模型的预测

5.1 max函数

t1 =  torch.tensor(np.arange(12).reshape(3, 4))
t1
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]], dtype=torch.int32)
t1.max()
tensor(11, dtype=torch.int32)
t1.max(dim=-1)
torch.return_types.max(
values=tensor([ 3,  7, 11], dtype=torch.int32),
indices=tensor([3, 3, 3]))
t1.max(dim=0)
torch.return_types.max(
values=tensor([ 8,  9, 10, 11], dtype=torch.int32),
indices=tensor([2, 2, 2, 2]))
t1.max(dim=-1)[-1]
tensor([3, 3, 3])

  • 预测部分完整的代码:
def test():
    loss_list = []
    acc_list = []
    test_dataloader = get_dataloader(train=False)
    for idx, (input, target) in enumerate(test_dataloader):
        with torch.no_grad():
            output = model(input)
            cur_loss = F.nll_loss(output, target)
            loss_list.append(cur_loss)
            # 计算准确率
            # output [batch_size,10]  target [batch_size]
            pred = output.max(dim=-1)[-1]   # dim=-1表示输出每行的最大值,[-1]表示输出位置
            cur_acc = pred.eq(target).float().mean()
            acc_list.append(cur_acc)

    print("np.mean(acc_list), np.mean(loss_list)", np.mean(acc_list), np.mean(loss_list))

6 全部代码

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

DATAPATH = "E:\dataset\mnist"  # 路径写到mnist就好了
BATCHSIZE = 64


# 1 获取数据集
def get_dataloader(train=True):
    """返回一个dataloader"""
    transform_fn = Compose([
        ToTensor(),
        Normalize(mean=(0.1307, ), std=(0.3081, ))
    ])
    dataset = MNIST(root=DATAPATH, train=train, transform=transform_fn, download=False)
    data_loader = DataLoader(dataset=dataset, batch_size=BATCHSIZE, 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)

    def forward(self, input):
        x = input.view([input.size(0), 1*28*28])
        x = self.fc1(x)
        x = F.relu(x)
        out = self.fc2(x)
        return out


model = MnistModel()
optimizer = Adam(model.parameters(), lr=0.001)  # 实例化优化器


def train(epoch):
    data_loader = get_dataloader()
    for idx, (input, target) in enumerate(data_loader):
        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())


def test():
    loss_list = []
    acc_list = []
    test_dataloader = get_dataloader(train=False)
    for idx, (input, target) in enumerate(test_dataloader):
        with torch.no_grad():
            output = model(input)
            cur_loss = F.nll_loss(output, target)
            loss_list.append(cur_loss)
            # 计算准确率
            # output [batch_size,10]  target [batch_size]
            pred = output.max(dim=-1)[-1]   # dim=-1表示输出每行的最大值,[-1]表示输出位置
            cur_acc = pred.eq(target).float().mean()
            acc_list.append(cur_acc)

    print("np.mean(acc_list), np.mean(loss_list)", np.mean(acc_list), np.mean(loss_list))


if __name__ =="__main__":
    test()  # 要测什么就调什么函数就好了
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值