pytorch规范化训练过程(Mnist分类任务)

前言

之前的一个暑假跟着师兄做了一些任务,开学了发现自己成了一名代码搬运工。就比如dataloader封装环节,我自己还是写不出,所以借着pytorch综合实践上机课的机会,想重新学一学pytorch。
文章是参照pytorch官网的教程WHAT IS TORCH.NN REALLY?,将最后的mnist分类任务过程做了整合。

正文

第一步:下载mnist数据集

from pathlib import Path
import requests
import pickle
import gzip
DATA_PATH = Path("data")
PATH = DATA_PATH / "mnist"
PATH.mkdir(parents = True, exist_ok = True)  # 联级创建

URL = "http://deeplearning.net/data/mnist/"
FILENAME = "mnist.pkl.gz"

if not (PATH/ FILENAME).exists():
    content = requests.get(URL + FILENAME).content
    (PATH / FILENAME).open("wb").write(content)
with gzip.open((PATH / FILENAME).as_posix(),"rb" ) as f:
    ((x_train,y_train),(x_valid,y_valid),_) = pickle.load(f, encoding = "latin-1")

第二步:封装成dataloader

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import TensorDataset, DataLoader
from torch import optim
###############
#numpy.array->torch.tensor->tensordataset->dataloader
###############
x_train, y_train, x_valid, y_valid = map(torch.tensor, (x_train, y_train, x_valid, y_valid))
train_ds = TensorDataset(x_train, y_train)
valid_ds = TensorDataset(x_valid, y_valid)
train_dl = DataLoader(train_ds, bs,shuffle = True)
valid_dl = DataLoader(valid_ds, bs*2)
###############
#在dataloader中加入预处理
###############
class WrappedDataLoader:
    def __init__(self,dl):
        self.dl  = dl
#         self.func = func
    
    def preprocess(self,x,y):
         return x.view(-1,1,28,28),y
    
    def __len__(self):
        return len(self.dl)
    
    def __iter__(self):
        batches = iter(self.dl)
        for b in batches:
            yield (self.preprocess(*b))

train_dl, valid_dl = get_data(train_ds, valid_ds, bs = 64)
train_dl = WrappedDataLoader(train_dl)
valid_dl = WrappedDataLoader(valid_dl)

第三步:定义模型与损失函数

###############
# 模型类
###############
class Cnn_model(nn.Module):
    
    def __init__(self):
        super(Cnn_model,self).__init__()
        
#         self.sequence = nn.Sequential(
        self.sequence = nn.Sequential(
        nn.Conv2d(1, 16, kernel_size=3, stride=2, padding=1),
        nn.ReLU(),
        nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1),
        nn.ReLU(),
        nn.Conv2d(16, 10, kernel_size=3, stride=2, padding=1),
        nn.ReLU(),
        nn.AdaptiveAvgPool2d(1), 
        )
    
    def forward(self,xb):
        xb  = self.sequence(xb)
        xb = xb.view(xb.size(0),-1)
        return xb
###############
# 返回模型,和optim
###############
def get_model():
    model = Cnn_model()
    optimizer = optim.SGD(model.parameters(),lr = 1e-2)
    return model, optimizer
model, optimizer = get_model()
loss_func = F.cross_entropy  # loss_func

第四步:定义fit过程

###############
# 结果的计算/loss的计算/是否要反向传播
###############
def loss_batch(model,loss_func,xb,yb, optimizer= None):
    y_pred = model(xb)
    loss = loss_func(y_pred, yb)
    if optimizer != None:
        loss.backward()
        optimizer.step()
        optimizer.zero_grad()
    
    return loss, len(xb) # len(xb)用于计算valid中loss平均值
###############
# fit 
###############
def fit(epochs, model, loss_func, opt, train_dl, valid_dl):
    for epoch in range(epochs):
        model.train()
        for xb, yb in train_dl:
            loss_batch(model, loss_func, xb, yb, opt)
        model.eval()
        with torch.no_grad():
            losses, nums = zip(
                *[loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl]
            )
        val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)
        print(epoch, val_loss)

最后只需要:

fit(epochs=10, model=model, loss_func=loss_func, opt=optimizer, train_dl=train_dl, valid_dl=valid_dl)

就可以跑出结果:
在这里插入图片描述

总结

大致用到的技巧:

  • pathlib\requests\pickle\gzip库
  • Tensordataset\dataloader,以及自定义dataloader类(需要定义:init\len\iter)
  • nn.Sequential与nn.AdaptiveAvgPool2d(参数取决于你需要输出的维度)
  • 定义get_model 函数,返回model和optim,loss_fn额外定义
  • 定义fit函数,简化训练过程
  • 将结果计算、loss计算、优化写入loss_batch类中,并通过opt参数使得train与valid过程都可以使用

下一篇:
Text Segmentation as a Supervised Learning Task模型复现

好的,我可以为您提供相关的代码和骤。 首先,您需要导入必要的库和数据集: ```python import torch import torch.nn as nn import torch.optim as optim import torchvision.datasets as dsets import torchvision.transforms as transforms # 加载 MNIST 数据集 train_dataset = dsets.MNIST(root='./data',train=True,transform=transforms.ToTensor(),download=True) test_dataset = dsets.MNIST(root='./data',train=False,transform=transforms.ToTensor(),download=True) # 设置超参数 batch_size = 100 learning_rate = 0.01 num_epochs = 10 ``` 接下来,您需要定义一个 RNN 模型。在这个示例中,我们将使用一个简单的单层 RNN,该模型接受 MNIST 图像序列并输出一个分类标签。 ```python class RNN(nn.Module): def __init__(self, input_size, hidden_size, output_size): super(RNN, self).__init__() self.hidden_size = hidden_size self.rnn = nn.RNN(input_size, hidden_size, batch_first=True) self.fc = nn.Linear(hidden_size, output_size) def forward(self, x): # 初始化隐藏状态 h0 = torch.zeros(1, x.size(0), self.hidden_size) # 前向传播 RNN out, _ = self.rnn(x, h0) # 取 RNN 的输出的最后一个时间 out = self.fc(out[:, -1, :]) return out ``` 接下来,您需要将数据加载到批次中,并将其输入到 RNN 模型中进行训练。 ```python train_loader = torch.utils.data.DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=True) test_loader = torch.utils.data.DataLoader(dataset=test_dataset,batch_size=batch_size,shuffle=False) model = RNN(28, 128, 10) # 输入大小为 28(序列长度),输出大小为 10(类别数) criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=learning_rate) for epoch in range(num_epochs): for i, (images, labels) in enumerate(train_loader): images = images.view(-1, 28, 28) # 将图像序列转换为 28x28 的矩阵 optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() if (i+1) % 100 == 0: print ('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'.format(epoch+1, num_epochs, i+1, len(train_dataset)//batch_size, loss.item())) ``` 最后,您可以使用测试数据集评估模型的性能: ```python with torch.no_grad(): correct = 0 total = 0 for images, labels in test_loader: images = images.view(-1, 28, 28) outputs = model(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print('Test Accuracy of the model on the 10000 test images: {} %'.format(100 * correct / total)) ``` 希望这可以帮助您开始使用 PyTorch 实现 RNN 并在 MNIST 上进行分类
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值