Fork me on GitHub

Pytorch深度学习全流程代码框架——Base Codes for Deep Learning Using Pytorch

# 导入必要的库
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset

# 定义超参数
epochs = 10 # 训练轮数
lr = 0.01 # 学习率
batch_size = 64 # 批量大小

# 定义数据集和数据加载器
class MyDataset(Dataset):
    def __init__(self):
        # 加载数据,预处理数据,划分训练集和测试集等操作
        pass
    
    def __getitem__(self, index):
        # 返回第index个样本的数据和标签
        pass
    
    def __len__(self):
        # 返回数据集的大小
        pass

train_dataset = MyDataset() # 创建训练集对象
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) # 创建训练集数据加载器
test_dataset = MyDataset() # 创建测试集对象
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False) # 创建测试集数据加载器

# 定义模型
class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        # 定义模型的结构,如卷积层,全连接层等
        pass
    
    def forward(self, x):
        # 定义模型的前向传播,即如何根据输入x计算输出
        pass

model = MyModel() # 创建模型对象
model.to(device) # 将模型移动到指定设备,如GPU

# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss() # 定义交叉熵损失函数,适用于多分类问题
optimizer = optim.SGD(model.parameters(), lr=lr) # 定义随机梯度下降优化器

# 训练模型
for epoch in range(epochs):
    model.train() # 将模型设置为训练模式,启用诸如Dropout和BatchNorm等层的功能
    train_loss = 0.0 # 记录训练集的累计损失
    train_acc = 0.0 # 记录训练集的累计准确率
    for i, (inputs, labels) in enumerate(train_loader): # 遍历训练集的每个批次
        inputs = inputs.to(device) # 将输入数据移动到指定设备
        labels = labels.to(device) # 将标签数据移动到指定设备
        
        optimizer.zero_grad() # 将优化器中的梯度清零
        
        outputs = model(inputs) # 将输入数据喂入模型,得到输出
        
        loss = criterion(outputs, labels) # 根据输出和标签计算损失
        
        loss.backward() # 反向传播计算梯度
        
        optimizer.step() # 根据梯度更新参数
        
        train_loss += loss.item() * inputs.size(0) # 累加批次的损失
        
        _, preds = torch.max(outputs, 1) # 根据输出得到预测类别
        
        train_acc += torch.sum(preds == labels).item() # 累加批次的正确预测数
    
    train_loss = train_loss / len(train_dataset) # 计算训练集的平均损失
    
    train_acc = train_acc / len(train_dataset) # 计算训练集的平均准确率
    
    print(f'Epoch {epoch+1}, Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.4f}') # 打印训练结果

# 测试模型
model.eval() # 将模型设置为评估模式,关闭诸如Dropout和BatchNorm等层的功能
test_loss = 0.0 # 记录测试集的累计损失
test_acc = 0.0 # 记录测试集的累计准确率
with torch.no_grad(): # 关闭梯度计算,节省内存,加快速度
    for inputs, labels in test_loader: # 遍历测试集的每个批次
        inputs = inputs.to(device) # 将输入数据移动到指定设备
        labels = labels.to(device) # 将标签数据移动到指定设备
        
        outputs = model(inputs) # 将输入数据喂入模型,得到输出
        
        loss = criterion(outputs, labels) # 根据输出和标签计算损失
        
        test_loss += loss.item() * inputs.size(0) # 累加批次的损失
        
        _, preds = torch.max(outputs, 1) # 根据输出得到预测类别
        
        test_acc += torch.sum(preds == labels).item() # 累加批次的正确预测数
    
    test_loss = test_loss / len(test_dataset) # 计算测试集的平均损失
    
    test_acc = test_acc / len(test_dataset) # 计算测试集的平均准确率
    
    print(f'Test Loss: {test_loss:.4f}, Test Acc: {test_acc:.4f}') # 打印测试结果

# 绘图
import matplotlib.pyplot as plt
plt.plot(train_loss, label='Train Loss') # 绘制训练集损失曲线
plt.plot(valid_loss, label='Valid Loss') # 绘制验证集损失曲线
plt.xlabel('Iterations') # 设置x轴标签
plt.ylabel('Loss') # 设置y轴标签
plt.legend() # 显示图例
plt.show() # 显示图像

plt.plot(train_acc, label='Train Acc') # 绘制训练集准确率曲线
plt.plot(valid_acc, label='Valid Acc') # 绘制验证集准确率曲线
plt.xlabel('Iterations') # 设置x轴标签
plt.ylabel('Accuracy') # 设置y轴标签
plt.legend() # 显示图例
plt.show() # 显示图像

  

DataLoader:

# 定义数据集和数据加载器
class MyDataset(Dataset):
    def __init__(self):
        # 加载数据,预处理数据,划分训练集和测试集等操作
        # 假设数据集路径是'~/dataset'
        # 假设数据集是MNIST手写数字识别,每个样本是28x28的灰度图像,标签是0-9的数字
        # 假设数据集已经分为train.csv和test.csv两个文件,每行是一个样本,第一个元素是标签,后面是784个像素值
        import pandas as pd
        from sklearn.model_selection import train_test_split
        data = pd.read_csv('~/dataset/train.csv') # 读取训练集文件
        X = data.iloc[:, 1:].values # 获取特征矩阵,即像素值
        y = data.iloc[:, 0].values # 获取标签向量,即数字类别
        X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.2, random_state=42) # 划分训练集和验证集
        self.X = X_train / 255.0 # 归一化处理,将像素值映射到[0,1]区间
        self.y = y_train # 获取训练集标签
        self.X_valid = X_valid / 255.0 # 归一化处理,将像素值映射到[0,1]区间
        self.y_valid = y_valid # 获取验证集标签
    
    def __getitem__(self, index):
        # 返回第index个样本的数据和标签
        if self.flag == 'train': # 如果是训练集
            return torch.from_numpy(self.X[index]).view(1, 28, 28), torch.tensor(self.y[index]) # 将numpy数组转换为torch张量,并将图像reshape为1x28x28的形式
        elif self.flag == 'valid': # 如果是验证集
            return torch.from_numpy(self.X_valid[index]).view(1, 28, 28), torch.tensor(self.y_valid[index]) # 将numpy数组转换为torch张量,并将图像reshape为1x28x28的形式
    
    def __len__(self):
        # 返回数据集的大小
        if self.flag == 'train': # 如果是训练集
            return len(self.X) # 返回训练集的大小
        elif self.flag == 'valid': # 如果是验证集
            return len(self.X_valid) # 返回验证集的大小

train_dataset = MyDataset(flag='train') # 创建训练集对象
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) # 创建训练集数据加载器
valid_dataset = MyDataset(flag='valid') # 创建验证集对象
valid_loader = DataLoader(valid_dataset, batch_size=batch_size, shuffle=False) # 创建验证集数据加载器

  

模型保存和加载:

'''一种是保存和加载整个模型,包括模型的结构和参数。这种方法的优点是可以直接使用加载的模型进行预测或继续训练,无需重新定义模型的结构。缺点是保存的文件较大,且可能存在版本兼容性的问题。

保存整个模型的代码如下:'''

torch. Save(model, PATH) # model是要保存的模型对象,PATH是要保存的文件路径
# 加载整个模型的代码如下:

model = torch.load(PATH) # PATH是要加载的文件路径,model是加载后的模型对象

 

'''另一种是保存和加载模型的状态字典(state_dict),即模型的参数张量。这种方法的优点是保存的文件较小,且不依赖于特定的模型结构。缺点是需要先定义好模型的结构,然后再加载状态字典。

保存模型的状态字典的代码如下:'''

torch. Save(model.state_dict(), PATH) # model是要保存的模型对象,PATH是要保存的文件路径
# 加载模型的状态字典的代码如下:

model = TheModelClass(*args, **kwargs) # 先定义好模型的结构,TheModelClass是模型类,*args和**kwargs是初始化参数
model.load_state_dict(torch.load(PATH)) # 加载状态字典,PATH是要加载的文件路径
# 一般来说,推荐使用第二种方法进行模型保存和加载

  

模型可视化:

'''
在pytorch中进行模型可视化的方法有多种,主要可以分为两类:

一类是可视化模型的结构,即展示模型的各个层和参数。这类方法有:

使用tensorboard,利用torch.utils.tensorboard.SummaryWriter.add_graph()方法,将模型和输入数据传入,生成模型的计算图;
使用netron,将模型保存为.pt或.pth文件,然后用netron打开,可以查看模型的层级结构和参数;
使用torchviz,利用torchviz.make_dot()方法,将模型的输出和参数传入,生成一个graphviz对象,可以保存为图片或pdf文件;
使用hiddenlayer,利用hiddenlayer.build_graph()方法,将模型和输入数据传入,生成一个hiddenlayer.Graph对象,可以保存为图片或pdf文件。
一类是可视化模型的训练过程,即展示模型的损失函数、准确率、梯度等指标的变化。这类方法有:

使用tensorboard,利用torch.utils.tensorboard.SummaryWriter.add_scalar()方法,将每个训练步骤或周期的指标值传入,生成标量曲线图;
使用hiddenlayer,利用hiddenlayer.History()和hiddenlayer.Canvas()方法,记录每个训练步骤或周期的指标值,并绘制成折线图;
使用tensorwatch,利用tensorwatch.Watcher()和tensorwatch.StreamViewer()方法,在jupyter notebook中实时监控和可视化模型的训练过程。
'''

  

另一个可参考代码框架(使用datasets模块,transform模块的train和test):

# 导入必要的库
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import models, datasets, transforms

# 定义超参数
num_classes = 10 # 数据集类别数
batch_size = 64 # 批量大小
num_epochs = 10 # 训练轮数
lr = 0.01 # 学习率

# 定义数据集和数据加载器
transform = transforms.Compose([ # 定义数据预处理操作
    transforms.Resize(256), # 调整图像大小为256x256
    transforms.CenterCrop(224), # 中心裁剪为224x224
    transforms.ToTensor(), # 转换为张量
    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) # 归一化
])

train_dataset = datasets.ImageFolder(root='data/train', transform=transform) # 创建训练集对象
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True) # 创建训练集数据加载器

test_dataset = datasets.ImageFolder(root='data/test', transform=transform) # 创建测试集对象
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=False) # 创建测试集数据加载器

# 定义模型
model = models.resnet18(pretrained=True) # 加载预训练好的resnet18模型
model.fc = nn.Linear(model.fc.in_features, num_classes) # 修改最后一层为全连接层,输出维度为num_classes

# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss() # 定义交叉熵损失函数,适用于多分类问题
optimizer = optim.SGD(model.parameters(), lr=lr, momentum=0.9) # 定义随机梯度下降优化器

# 训练模型
for epoch in range(num_epochs):
    model.train() # 将模型设置为训练模式,启用诸如Dropout和BatchNorm等层的功能
    train_loss = 0.0 # 记录训练集的累计损失
    train_acc = 0.0 # 记录训练集的累计准确率
    for i, (inputs, labels) in enumerate(train_loader): # 遍历训练集的每个批次
        optimizer.zero_grad() # 将优化器中的梯度清零
        
        outputs = model(inputs) # 将输入数据喂入模型,得到输出
        
        loss = criterion(outputs, labels) # 根据输出和标签计算损失
        
        loss.backward() # 反向传播计算梯度
        
        optimizer.step() # 根据梯度更新参数
        
        train_loss += loss.item() * inputs.size(0) # 累加批次的损失
        
        _, preds = torch.max(outputs, 1) # 根据输出得到预

        train_acc += torch.sum(preds == labels).item() # 累加批次的正确预测数
        
        if (i + 1) % 10 == 0: # 每10个批次打印一次训练结果
            print(f'Epoch {epoch + 1}, Batch {i + 1}, Loss: {loss.item():.4f}, Acc: {torch.sum(preds == labels).item() / inputs.size(0):.4f}')
    
    train_loss = train_loss / len(train_dataset) # 计算训练集的平均损失
    
    train_acc = train_acc / len(train_dataset) # 计算训练集的平均准确率
    
    print(f'Epoch {epoch + 1}, Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.4f}') # 打印训练结果
    
    model.eval() # 将模型设置为评估模式,关闭诸如Dropout和BatchNorm等层的功能
    test_loss = 0.0 # 记录测试集的累计损失
    test_acc = 0.0 # 记录测试集的累计准确率
    with torch.no_grad(): # 关闭梯度计算,节省内存,加快速度
        for inputs, labels in test_loader: # 遍历测试集的每个批次
            outputs = model(inputs) # 将输入数据喂入模型,得到输出
            
            loss = criterion(outputs, labels) # 根据输出和标签计算损失
            
            test_loss += loss.item() * inputs.size(0) # 累加批次的损失
            
            _, preds = torch.max(outputs, 1) # 根据输出得到预测类别
            
            test_acc += torch.sum(preds == labels).item() # 累加批次的正确预测数
        
        test_loss = test_loss / len(test_dataset) # 计算测试集的平均损失
        
        test_acc = test_acc / len(test_dataset) # 计算测试集的平均准确率
        
        print(f'Epoch {epoch + 1}, Test Loss: {test_loss:.4f}, Test Acc: {test_acc:.4f}') # 打印测试结果

 超参的配置文件导入和运行选项的解析:

*.cfg文件如下:

[settings]
name = Alice
age = 25
color = blue

  

引入这个cfg文件的过程如下:

import configparser

config = configparser.ConfigParser()
config.read('settings.cfg')
name = config['settings']['name']
age = config['settings']['age']
color = config['settings']['color']
print(name, age, color)

 

argparse的用法如下:

import argparse

parser = argparse.ArgumentParser(description='A simple calculator.')
parser.add_argument('x', type=float, help='the first number')
parser.add_argument('y', type=float, help='the second number')
parser.add_argument('operation', choices=['+', '-', '*', '/'], help='the operation')
args = parser.parse_args()

if args.operation == '+':
    result = args.x + args.y
elif args.operation == '-':
    result = args.x - args.y
elif args.operation == '*':
    result = args.x * args.y
elif args.operation == '/':
    result = args.x / args.y

print(result)

  

 

posted @ 2023-04-13 15:56  stardsd  阅读(572)  评论(0编辑  收藏  举报