Pytorch中的数据与优化器:Dataset、TensorDataset、DataLoader、optimizer.param_groups

目录

数据 

torch.utils.data.Dataset

1、用法

2、例子

torch.utils.data.TensorDataset

1、用法

2、例子

torch.utils.data.DataLoader

1、用法

2、例子

优化器 optimizer.param_groups

1、用法 

2、例子

参考


数据 

训练模型前一般要先处理数据的输入和预处理,Pytorch分别提供了两个工具(常用):

  • torch.utils.data.Dataset 类
  • torch.utils.data.DataLoader 类 

流程是先把原始数据转变成 torch.utils.data.Dataset 类,随后再把得到的 torch.utils.data.Dataset 类当作一个参数传递给 torch.utils.data.DataLoader 类,得到一个数据加载器,这个数据加载器每次可以返回一个Batch的数据供模型训练使用 


torch.utils.data.Dataset

1、用法

from torch.utils.data import Dataset

如果要自定义读取数据的方法,就需要继承类 torch.utils.data.Dataset ,并将其封装到DataLoader 中。

Dataset 是一个数据集抽象类,它是其他所有数据集类的父类(所有其他数据集类都应继承它),继承时需要重写方法

  • 自定义的类要继承Dataset类
  • __init__ 用于初始化数据集,在这里可以加载数据文件、初始化变量等
  • __len__ 返回自定义数据集的大小
  • __getitem__ 通过索引下标访问数据

2、例子

例1:实现将一组Tensor数据对封装成Tensor数据集,能够通过index得到数据集的数据、通过len得到数据集的大小

from torch.utils.data import Dataset
import torch

class TensorDataset(Dataset):
    # TensorDataset继承Dataset, 重载了__init__, __getitem__, __len__

    def __init__(self, data_tensor, target_tensor):
        self.data_tensor = data_tensor
        self.target_tensor = target_tensor

    def __getitem__(self, index):
        return self.data_tensor[index], self.target_tensor[index]

    def __len__(self):
        return self.data_tensor.size(0)    # size(0)返回当前张量维数的第一维

# 生成数据
data_tensor = torch.randn(4, 3)   # 4行3列,服从正态分布的张量
print(data_tensor)
target_tensor = torch.rand(4)     # 4个元素,服从均匀分布的张量
print(target_tensor)

# 将数据封装成 Dataset (用TensorDataset类)
tensor_dataset = TensorDataset(data_tensor, target_tensor)

# 可使用索引调用数据
print('tensor_data[0]: ', tensor_dataset[0])

# 可返回数据len
print('len os tensor_dataset: ', len(tensor_dataset))

输出结果:

tensor([[ 0.8618,  0.4644, -0.5929],
        [ 0.9566, -0.9067,  1.5781],
        [ 0.3943, -0.7775,  2.0366],
        [-1.2570, -0.3859, -0.3542]])
tensor([0.1363, 0.6545, 0.4345, 0.9928])
tensor_data[0]:  (tensor([ 0.8618,  0.4644, -0.5929]), tensor(0.1363))
len os tensor_dataset:  4

例2:重写 __init__ 实现用 pd.read_csv 读取 csv 文件

from torch.utils.data import Dataset
import pandas as pd

# 继承Dataset,定义自己的数据集类 mydataset
class mydataset(Dataset):
    def __init__(self, csv_file):   # self参数必须,其他参数及其形式随程序需要而不同,比如(self, *inputs)
        self.csv_data = pd.read_csv(csv_file)
    def __len__(self):
        return len(self.csv_data)
    def __getitem__(self, idx):
        return self.csv_data.values[idx]
        
data = mydataset('spambase.csv')
print(data[3])
print(len(data))

输出结果:

[0.000e+00 0.000e+00 0.000e+00 0.000e+00 6.300e-01 0.000e+00 3.100e-01
 6.300e-01 3.100e-01 6.300e-01 3.100e-01 3.100e-01 3.100e-01 0.000e+00
 0.000e+00 3.100e-01 0.000e+00 0.000e+00 3.180e+00 0.000e+00 3.100e-01
 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00
 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00
 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00
 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00
 1.370e-01 0.000e+00 1.370e-01 0.000e+00 0.000e+00 3.537e+00 4.000e+01
 1.910e+02 1.000e+00]
4601

torch.utils.data.TensorDataset

from torch.utils.data import TensorDataset

1、用法

将多个张量组合成一个数据集,每个张量的第一个维度相同,表示数据的数量。

import torch
from torch.utils.data import TensorDataset

# 创建一个包含数据和标签的TensorDataset
data_tensor = torch.tensor([[1, 2], [3, 4], [5, 6], [7, 8]])
label_tensor = torch.tensor([0, 1, 0, 1])
dataset = TensorDataset(data_tensor, label_tensor)

多个张量的情况:还可以创建包含数据、标签和额外信息(如掩码等)的TensorDataset 

2、例子

训练集,包含输入数据 train_r、输入掩码 train_mask_r、标签 train_labels,将它们组合成一个TensorDataset

import torch
from torch.utils.data import TensorDataset
import numpy as np

train_r = np.random.randn(100, 10)  # 100 个样本,每个样本有 10 个特征

# 0或1
train_mask_r = np.random.randint(0, 2, size=(100, 10))  # 100 个样本的掩码
train_labels = np.random.randint(0, 2, size=100)  # 100 个样本的标签

# 将 NumPy 数组转换为 PyTorch 张量
train_r_tensor = torch.from_numpy(train_r).float()
train_mask_r_tensor = torch.from_numpy(train_mask_r).float()
train_labels_tensor = torch.from_numpy(train_labels).long()

# 创建 TensorDataset
dataset = TensorDataset(train_r_tensor, train_mask_r_tensor, train_labels_tensor)

torch.utils.data.DataLoader

1、用法

from torch.utils.data import DataLoader

数据加载器,结合了数据集和取样器,并且可以提供多个线程处理数据集。

把训练数据分成多个小组(batch)每次抛出一组数据,直至把所有的数据都抛出。可以快速迭代数据 

2、例子

情况1:BATCH_SIZE 刚好整除数据量

  • 共有10条数据,设置 BATCH_SIZE 为 5 进行划分,能划分为 2 组(step 为 0 和 1)。这两组数据互斥 
import torch
import torch.utils.data as Data

"""
    批训练,把数据变成一小批一小批进行训练。
    DataLoader就是用来包装所使用的数据,每次抛出一批数据
"""

BATCH_SIZE = 5       # 批训练的数据个数

x = torch.linspace(1, 10, 10)   # 训练数据
print(x)   # tensor([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10.])
y = torch.linspace(10, 1, 10)   # 标签
print(y)   # tensor([10.,  9.,  8.,  7.,  6.,  5.,  4.,  3.,  2.,  1.])

torch_dataset = Data.TensorDataset(x, y)  # 对给定的tensor数据,将他们包装成dataset

loader = Data.DataLoader(
    # 从数据库中每次抽出batch size个样本
    dataset=torch_dataset,      
    batch_size=BATCH_SIZE,     
    shuffle=True,      # 要不要打乱数据 (打乱比较好)
    num_workers=2,     # 多线程来读数据 (Windows环境设为0,Linux才能支持多线程)
)

def show_batch():
    for epoch in range(3):
        for step, (batch_x, batch_y) in enumerate(loader):
            # training
            print("step:{}, batch_x:{}, batch_y:{}".format(step, batch_x, batch_y))

show_batch()

输出结果:

step:0, batch_x:tensor([10.,  1.,  3.,  7.,  6.]), batch_y:tensor([ 1., 10.,  8.,  4.,  5.])
step:1, batch_x:tensor([8., 5., 4., 9., 2.]), batch_y:tensor([3., 6., 7., 2., 9.])
step:0, batch_x:tensor([ 9.,  3., 10.,  1.,  5.]), batch_y:tensor([ 2.,  8.,  1., 10.,  6.])
step:1, batch_x:tensor([2., 6., 8., 4., 7.]), batch_y:tensor([9., 5., 3., 7., 4.])
step:0, batch_x:tensor([ 2., 10.,  9.,  6.,  1.]), batch_y:tensor([ 9.,  1.,  2.,  5., 10.])
step:1, batch_x:tensor([8., 3., 4., 7., 5.]), batch_y:tensor([3., 8., 7., 4., 6.])

情况2:BATCH_SIZE 不整除数据量,会输出余下所有数据

  • 共有10条数据,设置 BATCH_SIZE 为 4 来进行划分,能划分为 3 组(step 为 0 、1、2),分别有 4、4、2 条数据

将上述代码中的 BATCH_SIZE 改为4,输出结果:

step:0, batch_x:tensor([1., 5., 3., 2.]), batch_y:tensor([10.,  6.,  8.,  9.])
step:1, batch_x:tensor([7., 8., 4., 6.]), batch_y:tensor([4., 3., 7., 5.])
step:2, batch_x:tensor([10.,  9.]), batch_y:tensor([1., 2.])
step:0, batch_x:tensor([ 7., 10.,  5.,  2.]), batch_y:tensor([4., 1., 6., 9.])
step:1, batch_x:tensor([9., 1., 6., 4.]), batch_y:tensor([ 2., 10.,  5.,  7.])
step:2, batch_x:tensor([8., 3.]), batch_y:tensor([3., 8.])
step:0, batch_x:tensor([10.,  3.,  2.,  8.]), batch_y:tensor([1., 8., 9., 3.])
step:1, batch_x:tensor([1., 7., 5., 9.]), batch_y:tensor([10.,  4.,  6.,  2.])
step:2, batch_x:tensor([4., 6.]), batch_y:tensor([7., 5.])

优化器 optimizer.param_groups

1、用法 

optimizer.param_groups:是一个list,长度为1,其中的元素是一个字典

[{'params': [Parameter containing:
tensor([[-0.1548, -0.2069, -0.2007, -0.0577, -0.2824,  0.1292,  0.1056,  0.2825,
          0.1069, -0.0987]], requires_grad=True), Parameter containing:
tensor([-0.0470], requires_grad=True)], 'lr': 0.01, 'momentum': 0, 'dampening': 0, 'weight_decay': 0, 'nesterov': False, 'maximize': False, 'foreach': None, 'differentiable': False}]

optimizer.param_groups[0]:是一个字典,key一般包括params、lr、momentum、weight_decay等参数(不同优化器包含的参数可能略有不同,且可以额外人为添加键值对)

{'params': [Parameter containing:
tensor([[-0.2488,  0.2737, -0.0199, -0.0528, -0.2339, -0.0749, -0.1017,  0.2590,
          0.2526, -0.2583]], requires_grad=True), Parameter containing:
tensor([0.2086], requires_grad=True)], 'lr': 0.01, 'momentum': 0, 'dampening': 0, 'weight_decay': 0, 'nesterov': False, 'maximize': False, 'foreach': None, 'differentiable': False}

人为额外添加键值对的函数为 optimizer.add_param_group()

optimizer.add_param_group({"params":model.fc.parameters(),"lr":0.09})

optimizer.param_groups['params']:Pytorch的优化器中都有一个参数:params,即为网络中需要优化的参数,传入的网络参数必须是可迭代的对象,如model.parameters()

Parameter containing:
tensor([[ 0.0075, -0.1876, -0.0677, -0.1628,  0.2620,  0.2361,  0.2415, -0.3089,
         -0.0936, -0.2149]], requires_grad=True)
Parameter containing:
tensor([-0.0566], requires_grad=True)

如果想取tensor部分的值,可以用 optimizer.param_groups['params'].data:

tensor([[-0.0751, -0.2141, -0.2035,  0.1249, -0.0248,  0.2066,  0.1604, -0.3064,
          0.2822, -0.0026]])
tensor([0.0822])

2、例子

例1:对优化器参数中的二维张量进行转置,计算其元素的平方和 

import torch
import torch.optim as optim

# 假设我们有一个简单的模型
model = torch.nn.Linear(10, 1)

# 创建优化器
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 初始化 temp 变量
temp = 0.0

# 遍历优化器的参数组
for param_group in optimizer.param_groups:
    # 遍历每个参数组中的参数
    for param in param_group['params']:
        print(param.data)
        # 检查参数是否是二维张量
        if param.dim() == 2:
            # 对二维张量进行转置,计算其元素的平方和,并将结果累加到 temp 中
            temp += param.T.pow(2).sum().item()

print(temp)

输出结果:

# w
tensor([[ 0.0840,  0.3101,  0.2821, -0.0384,  0.0747,  0.2369, -0.0436,  0.1418,
          0.3083, -0.0079]])
# b
tensor([0.2341])
# temp
0.36307135224342346

例2:给网络不同模块设置不同学习率,或动态调整学习率 

import torch

class Resnet(torch.nn.Module):
    def __init__(self):
        super(Resnet, self).__init__()
        self.block1 = torch.nn.Sequential(
            torch.nn.Conv2d(1, 10, 5),
            torch.nn.MaxPool2d(2),
            torch.nn.ReLU(True),
            torch.nn.BatchNorm2d(10),
        )
        self.block2 = torch.nn.Sequential(
            torch.nn.Conv2d(10, 20, 5),
            torch.nn.MaxPool2d(2),
            torch.nn.ReLU(True),
            torch.nn.BatchNorm2d(20),
        )
        self.fc = torch.nn.Sequential(
            torch.nn.Flatten(),
            torch.nn.Linear(320, 10)
        )
    def forward(self, x):
        x = self.block1(x)
        x = self.block2(x)
        x = self.fc(x)
        return x
    
model = Resnet()

(1)正常的优化器设置方式:

optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.5)

(2)对网络不同模块设置不同学习率:

params = [{"params":model.block1.parameters()},  # 其采用默认的学习率
          {"params":model.block2.parameters(),"lr":0.08},]
optimizer = torch.optim.SGD(params, lr=0.1,)  # 此处的lr是默认的学习率

'''
optimizer.param_groups[1]在这对应的就是
{"params":model.block2.parameters(),"lr":0.08}
'''

(3)动态调整学习率:

start_lr = [0.1, 0.08, 0.09]  # 不同层的初始学习率

def adjust_learning_rate(optimizer, epoch, start_lr):
    for index, param_group in enumerate(optimizer.param_groups):
        lr = start_lr[index] * (0.9 ** (epoch // 1))    # 每1个eporch学习率改变为上一个eporch的 0.9倍
        param_group['lr'] = lr
  • 0.9 ** (epoch // 1):这是一个幂运算,用于计算当前 epoch 对应的学习率衰减系数
  • 这个公式的作用是每经过一个 epoch,学习率将乘以0.9

例3:如果只是想优化一个网络,就把一整个网络看做一个param_groups,参数params赋值为model.parameters()

import torch
import torch.nn as nn
 
# 定义网络
class Test(nn.Module):
    def __init__(self):
        super(Test, self).__init__()

        self.conv = nn.Sequential(
            nn.Conv2d(3, 8, 3),
            nn.ReLU(),
        )

        self.fc = nn.Sequential(
            nn.Linear(288, 5)
        )
 
    def forward(self, x):
        x = self.conv(x)
        x = torch.flatten(x, 1)
        x = self.fc(x)
        return x
 
# 实例化网络
model = Test()
 
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
 
print("只有一个网络时optimizer.param_groups(list类型)的长度:{}".format(len(optimizer.param_groups)))

输出结果:

只有一个网络时optimizer.param_groups(list类型)的长度:1

例4:如果是同时优化多个网络的参数

(1)可以将多个网络的参数合并,当成一个网络的参数来优化

# 此时有两个网络需要优化
model_1 = Test()
model_2 = Test()
 
optimizer = torch.optim.Adam([*model_1.parameters(), *model_2.parameters()], lr=0.01)
 
print("两个网络时optimizer.param_groups(list类型)的长度:{}".format(len(optimizer.param_groups)))

输出结果:

两个网络时optimizer.param_groups(list类型)的长度:1

(2)多个网络分开优化,且可以使用不同的学习率(每个param_groups中可以单独定义学习率,如果没有指定,默认采取后面的学习率)

# 此时有两个网络需要优化
model_1 = Test()
model_2 = Test()
 
optimizer = torch.optim.Adam([{'params':model_1.parameters()},{'params':model_2.parameters(), 'lr': 0.2}], lr=0.01)
 
print("优化器里有多少个param_groups: ", len(optimizer.param_groups))
print("网络1的学习率为: ", optimizer.param_groups[0]['lr'])
print("网络2的学习率为: ", optimizer.param_groups[1]['lr'])

输出结果:

优化器里有多少个param_groups:  2
网络1的学习率为:  0.01
网络2的学习率为:  0.2

参考

【PyTorch】torch.utils.data.Dataset 介绍与实战-CSDN博客

【PyTorch】torch.utils.data.DataLoader 简单介绍与使用-CSDN博客

optimizer.param_groups含义分析_param groups-CSDN博客

【人工智能概论】 optimizer.param_groups简介_optimizer params-CSDN博客

  • 10
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是基于PyTorch的LSTM训练寻找最优参数代码,保存最优参数代码以及打印优化学习率的示例: ```python import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader, TensorDataset # 定义数据集 x = torch.randn(100, 10, 5) y = torch.randint(0, 2, (100,)) # 定义模型 class LSTMModel(nn.Module): def __init__(self, input_size, hidden_size, num_layers, num_classes): super(LSTMModel, self).__init__() self.hidden_size = hidden_size self.num_layers = num_layers self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True) self.fc = nn.Linear(hidden_size, num_classes) def forward(self, x): h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device) c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device) out, _ = self.lstm(x, (h0, c0)) out = self.fc(out[:, -1, :]) return out # 定义超参数 input_size = 5 hidden_size = 16 num_layers = 2 num_classes = 2 batch_size = 32 learning_rate = 0.01 num_epochs = 10 # 定义数据加载器 dataset = TensorDataset(x, y) dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True) # 定义模型、损失函数和优化器 model = LSTMModel(input_size, hidden_size, num_layers, num_classes) criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=learning_rate) # 训练模型 best_acc = 0.0 for epoch in range(num_epochs): for i, (inputs, targets) in enumerate(dataloader): inputs = inputs.to(torch.float32) targets = targets.to(torch.long) # 前向传播 outputs = model(inputs) loss = criterion(outputs, targets) # 反向传播和优化 optimizer.zero_grad() loss.backward() optimizer.step() # 评估模型 with torch.no_grad(): total = 0 correct = 0 for inputs, targets in dataloader: inputs = inputs.to(torch.float32) targets = targets.to(torch.long) outputs = model(inputs) _, predicted = torch.max(outputs.data, 1) total += targets.size(0) correct += (predicted == targets).sum().item() acc = 100 * correct / total print('Epoch [{}/{}], Accuracy: {:.2f}%'.format(epoch+1, num_epochs, acc)) # 保存最优参数 if acc > best_acc: best_acc = acc torch.save(model.state_dict(), 'best_model.pth') # 打印优化学习率 print('Optimizer learning rate:', optimizer.param_groups[0]['lr']) ``` 在上面的示例,我们首先定义了一个数据集,然后定义了一个LSTM模型,接着定义了超参数、数据加载器、损失函数和优化器。在训练过程,我们每个epoch都循环数据集,并进行前向传播、损失计算、反向传播和优化。在每个epoch之后,我们评估模型的准确率,并保存最优参数。最后,我们打印出优化器的学习率。 请注意,这只是一个示例,实际情况下您可能需要根据您的具体需求进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cheeryang_ego

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值