Pytorch训练代码框架

前言

网上关于Pytorch的基础训练代码框架有很多,但一直想创建一个自己的。于是从头写了一遍,包含了seed指定,网络搭建,DataSet和DataLoader,loss和优化器的定义和使用,模型的保存和载入。

代码

import numpy as np
import os
import argparse
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, Dataset

parser = argparse.ArgumentParser(description="输入参数")
parser.add_argument('-batch_size', type=int, default=16, help="BatchSize")
parser.add_argument('-epochs', type=int, default=20, help="Epoch Num")
parser.add_argument('-train', type=str, default='True', help="Train or Eval")
parser.add_argument('-cuda_id', type=int, default='0', help="CUDA序号")

parser.add_argument('-model_save_path', type=str,
                    default='./model', help="model保存路径")
parser.add_argument('-pretrain_model_path', type=str,
                    default='./model/c19.pth', help="预训练模型路径")

args = parser.parse_args()


class PredictNet(nn.Module):
    def __init__(self):
        super().__init__()

        self.conv1 = nn.Sequential(
            nn.Conv2d(in_channels=1, out_channels=16, kernel_size=3, stride=1),
            nn.BatchNorm2d(num_features=16),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Dropout2d(),
        )

        self.conv2 = nn.Sequential(
            nn.Conv2d(in_channels=16, out_channels=64, kernel_size=3, stride=1),
            nn.BatchNorm2d(num_features=64),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Dropout2d(),
        )

        self.conv3 = nn.Sequential(
            nn.Conv2d(in_channels=64, out_channels=32, kernel_size=3, stride=1),
            nn.BatchNorm2d(num_features=32),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Dropout2d(),
        )

        self.linear = nn.Sequential(
            nn.Linear(in_features=4 * 4 * 32, out_features=100),
            nn.ReLU(inplace=True),
            nn.Linear(in_features=100, out_features=50),
            nn.ReLU(inplace=True),
        )

        self.linear_x = nn.Linear(50, 1)
        self.linear_y = nn.Linear(50, 1)
        self.linear_sigma = nn.Linear(50, 1)

    def forward(self, x):
        BatchSize, _, _, _ = x.shape
        conv1_out = self.conv1(x)
        conv2_out = self.conv2(conv1_out)
        conv3_out = self.conv3(conv2_out)
        linear = self.linear(conv3_out.reshape(BatchSize, -1))

        return [self.linear_x(linear),
                self.linear_y(linear),
                self.linear_sigma(linear)]


class Data(Dataset):
    def __init__(self, image_size=50, data_size=10000):
        # 创建数据
        if args.cuda_id != -1:
            device = 'cuda:{}'.format(args.cuda_id)
        else:
            device = 'cpu'

        self.data_size = data_size
        self.x = torch.randint(low=0, high=image_size, size=[data_size, 1, 1],
                               device=device, dtype=torch.float)
        self.y = torch.randint(low=0, high=image_size, size=[data_size, 1, 1],
                               device=device, dtype=torch.float)
        self.sigma = torch.randint(low=30, high=100, size=[data_size, 1, 1],
                                   device=device, dtype=torch.float)

        x_grid, y_grid = torch.meshgrid(
            [torch.linspace(0, image_size, image_size, device=device),
             torch.linspace(0, image_size, image_size, device=device)],
        )

        x_grid = x_grid.unsqueeze(0).repeat_interleave(repeats=data_size, dim=0)
        y_grid = y_grid.unsqueeze(0).repeat_interleave(repeats=data_size, dim=0)

        self.gauss_map = 100 / (2 * np.pi * self.sigma) * torch.exp(
            ((x_grid - self.x) ** 2 + (y_grid - self.y) ** 2) / (2 * self.sigma ** 2)
        )

    def __getitem__(self, index):
        gauss_map = self.gauss_map[index, :, :]

        x = self.x[index, 0, 0]
        y = self.y[index, 0, 0]
        sigma = self.sigma[index, 0, 0]

        return gauss_map.unsqueeze(0), [x, y, sigma]

    def __len__(self):
        return self.data_size


def train():
    pred_net = PredictNet().cuda()

    criterion = torch.nn.MSELoss()
    optim = torch.optim.Adam(pred_net.parameters(), lr=1e-4)
    scheduler = torch.optim.lr_scheduler.StepLR(optim,1,0.9)

    dataset = Data()
    dataloader = DataLoader(dataset, batch_size=args.batch_size, shuffle=True)

    for epoch in range(args.epochs):
        print("Epoch:{epoch}, lr:{lr}".format(epoch=epoch, lr=optim.param_groups[0]['lr']))
        for gauss_map, [x, y, sigma] in dataloader:
            x_pred, y_pred, sigma_pred = pred_net(gauss_map)
            loss = criterion(x_pred, x) + criterion(y_pred, y) + criterion(sigma_pred, sigma)

            optim.zero_grad()
            loss.backward()
            optim.step()
        scheduler.step()

        # save model
        if not os.path.exists(args.model_save_path):
            os.makedirs(args.model_save_path)
        save_name = os.path.join(args.model_save_path, "c{}.pth".format(epoch))
        torch.save(pred_net.state_dict(), save_name)

        # val
        loss_val = torch.zeros([100]).cuda()
        for index, (gauss_map, [x, y, sigma]) in enumerate(dataloader):

            if index == 100:
                break

            x_pred, y_pred, sigma_pred = pred_net(gauss_map)
            loss = criterion(x_pred, x) + criterion(y_pred, y) + criterion(sigma_pred, sigma)
            loss_val[index] = loss

        print("Epoch:{epoch}, loss:{loss}".format(epoch=epoch, loss=loss_val.mean()))


def eval():
    pred_net = PredictNet().cuda()
    pred_net.load_state_dict(torch.load(args.pretrain_model_path))

    dataset = Data()
    dataloader = DataLoader(dataset, batch_size=args.batch_size, shuffle=True)
    criterion = torch.nn.MSELoss()

    loss_val = torch.zeros([100]).cuda()
    for index, (gauss_map, [x, y, sigma]) in enumerate(dataloader):
        if index == 100:
            break
        x_pred, y_pred, sigma_pred = pred_net(gauss_map)
        loss = criterion(x_pred, x) + criterion(y_pred, y) + criterion(sigma_pred, sigma)
        loss_val[index] = loss

    print("Model:{model}, loss:{loss}".format(model=args.pretrain_model_path,
                                              loss=loss_val.mean()))


def set_seed(seed=123):
    # random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)


if __name__ == '__main__':
    set_seed()
    os.environ["CUDA_VISIBLE_DEVICES"] = str(args.cuda_id)

    if args.train == "True":
        train()
    else:
        eval()

代码功能:
生成一个2D的高斯图,其中峰值位置(x,y)和方差sigma是随机的。输入这个2D高斯图,利用卷积神经网络预测这三个量。

后记

  1. 尽管已经用了很久的pytorch,但是单独写这个不到200行的代码还是用了一天时间。毕竟以前只是在现成的代码上修改。
  2. 数据增强部分没有包含,以后用的时候再说吧。
  3. 测试的时候遇到了输出为NaN的问题,是计算结果过大或过小导致。在调整sigma的取值下限后,问题解决。
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
一个基本的PyTorch分类代码框架通常包括以下几个部分: 1. 数据加载器:使用PyTorch的DataLoader加载训练、验证和测试数据集,并进行预处理和数据增强。 2. 模型定义:定义你的神经网络模型,包括网络结构、层数、激活函数等。 3. 损失函数:选择适当的损失函数,例如交叉熵损失函数、均方误差损失函数等。 4. 优化器:选择适当的优化器,例如Adam、SGD等,并设置相关的超参数。 5. 训练循环:对模型进行训练,包括前向传播、反向传播、参数更新等。 6. 验证/测试循环:对训练好的模型进行验证或测试,以评估模型的性能。 7. 可视化:使用Tensorboard等工具对模型的训练过程和性能进行可视化。 一个完整的PyTorch分类代码框架可以参考如下示例代码: ```python import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader from torchvision.datasets import MNIST from torchvision.transforms import ToTensor from tqdm import tqdm # 数据加载器 train_dataset = MNIST(root='./data', train=True, download=True, transform=ToTensor()) train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True) test_dataset = MNIST(root='./data', train=False, download=True, transform=ToTensor()) test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False) # 模型定义 class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(1, 32, kernel_size=3) self.conv2 = nn.Conv2d(32, 64, kernel_size=3) self.fc1 = nn.Linear(64*5*5, 128) self.fc2 = nn.Linear(128, 10) def forward(self, x): x = nn.functional.relu(self.conv1(x)) x = nn.functional.relu(self.conv2(x)) x = x.view(-1, 64*5*5) x = nn.functional.relu(self.fc1(x)) x = self.fc2(x) return x # 损失函数和优化器 criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(net.parameters(), lr=0.001) # 训练循环 net = Net() device = 'cuda' if torch.cuda.is_available() else 'cpu' net.to(device) epochs = 10 for epoch in range(epochs): running_loss = 0.0 for i, data in enumerate(train_loader, 0): inputs, labels = data inputs, labels = inputs.to(device), labels.to(device) optimizer.zero_grad() outputs = net(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() print(f'Epoch {epoch+1}, loss: {running_loss/len(train_loader)}') # 验证/测试循环 correct = 0 total = 0 with torch.no_grad(): for data in test_loader: inputs, labels = data inputs, labels = inputs.to(device), labels.to(device) outputs = net(inputs) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print(f'Accuracy on test set: {100*correct/total}%') ``` 这段代码实现了一个简单的卷积神经网络对MNIST手写数字进行分类。其中,数据加载器使用了PyTorch自带的MNIST数据集,模型定义包括了两层卷积层和两层全连接层,损失函数使用了交叉熵损失函数,优化器使用了Adam优化器,训练循环使用了GPU进行加速,并使用了tqdm库对训练过程进行可视化,验证/测试循环计算了模型在测试集上的准确率。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值