PyTorch常用函数总结(持续更新)

news/2025/2/26 20:56:17

本文主要记录自己在用 PyTorch复现经典模型 过程中遇到的一些函数及用法,以期对 常见PyTorch函数 更加熟练~

官方Docs:PyTorch documentation — PyTorch 2.6 documentation


目录

数据层面

torch.sign(tensor)

torch.tensor(np.eye(3)[y])

torch.ones() / torch.sum(dim=0)

torch.unsqueeze()升维 & torch.squeeze()降维

torch.mm() / torch.matmul() / torch.mul()

torch.clamp_()

torch.tensor().item()

torch.tensor().view()

torch.gather()

torch.pow()

torch.stack() / torch.cat()

torch.tensor().t()

torch.manual_seed()

torch.empty()

torch.einsum()

torch.randn() / torch.randint()

模型层面

TensorDataset() / Dataset() / DataLoader()

nn.MSELoss() / nn.BCELoss()

optim.Adam() 等优化器

torch.nn.Sigmoid() / torch.nn.Softmax()

nn.ModuleList() / nn.ParameterList()


数据层面

torch.sign(tensor)

sign函数就是符号函数,大于0的输入变为1输出,小于0的输入变为-1输出,0输出为0。如下:

>>> a = torch.tensor([0.7, -1.2, 0., 2.3])
>>> torch.sign(a)
tensor([ 1., -1.,  0.,  1.])

可以在该函数上做一些变种,如单位阶跃函数:

import torch
theta = lambda t: (torch.sign(t) + 1.) / 2.

torch.tensor(np.eye(3)[y])

import numpy as np
 
a=np.eye(3)   # 生成对角线全是1,其余全是0的3维矩阵
print(a)
 
a=np.eye(4,k=1)   # k=1表示全是1的那条对角线往右上走一格(只有3个1了)
print(a)
 
a=np.eye(4,k=-1)   # k=-1表示全是1的那条对角线往左下走一格(只有3个1了)
print(a)
 
a=np.eye(4,k=-3)   # k=-3表示全是1的那条对角线往左下走三格(只有1个1了)
print(a)

结果:

[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]

[[0. 1. 0. 0.]
 [0. 0. 1. 0.]
 [0. 0. 0. 1.]
 [0. 0. 0. 0.]]

[[0. 0. 0. 0.]
 [1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 1. 0.]]

[[0. 0. 0. 0.]
 [0. 0. 0. 0.]
 [0. 0. 0. 0.]
 [1. 0. 0. 0.]]

torch.tensor(np.eye(3)[y]) 为 标签label 转 one-hot向量 的一种写法:

  • np.eye(3)[y] 使用y,即label中的值作为索引,选择单位矩阵中对应的行
  • y的三个元素依次为0、2、2,代表依次选择第0行、第2行、第2行
import torch
import numpy as np

y = torch.tensor([0, 2, 2])
y_onehot = torch.tensor(np.eye(3)[y])
print(y_onehot)

tensor([[1., 0., 0.],
        [0., 0., 1.],
        [0., 0., 1.]], dtype=torch.float64)

torch.ones() / torch.sum(dim=0)

a = torch.ones((2, 3))   # 两行三列、全为1的矩阵
print(a)

tensor([[1., 1., 1.],
        [1., 1., 1.]])

a1 = torch.sum(a)
a2 = torch.sum(a, dim=0)   # 列优先
a3 = torch.sum(a, dim=1)   # 行优先

print(a1)     tensor(6.)
print(a2)     tensor([2., 2., 2.])
print(a3)     tensor([3., 3.])

如果加上keepdim=True,则会保持dim的维度不被squeeze

a2 = torch.sum(a, dim=0, keepdim=True)   # keepdim=True的结果也是二维,即两个[[
a3 = torch.sum(a, dim=1, keepdim=True)
     
print(a2)     tensor([[2., 2., 2.]])
print(a3)     tensor([[3.],
                      [3.]])

torch.unsqueeze()升维 & torch.squeeze()降维

torch.unsqueeze() 函数起升维的作用,参数dim 表示在哪个地方加一个维度

  • 注意dim范围。比如输入input是一维,则dim=0时数据为行方向扩,dim=1时为列方向扩,再大错误
x = torch.tensor([1, 2, 3, 4])   # torch.Size([4])

y = torch.unsqueeze(x, 0)   # 在第0维扩展,第0维大小为1
y, y.shape   # (tensor([[1, 2, 3, 4]]), torch.Size([1, 4]))

y = torch.unsqueeze(x, 1)   # 在第1维扩展,第1维大小为1
y, y.shape
'''
(tensor([[1],
         [2],
         [3],
         [4]]),
 torch.Size([4, 1]))
'''

y = torch.unsqueeze(x, -1)   # 在最后一维扩展,最后一维大小为1
# 结果同在第1维扩展

torch.squeeze() 函数的功能是维度压缩,返回一个tensor(张量),其中 input中维度大小为1的所有维都被删除。举个例子,如果 input 的形状为 (A×1×B×C×1×D),那么返回的tensor形状为 (A×B×C×D)

torch.squeeze(input, dim=None, out=None) 

当给定dim 时,只在给定的维度上进行压缩操作,注意给定的维度大小必须是1,否则不能进行压缩。举个例子:如果 input 的形状为 (A×1×B),squeeze(input, dim=0)后,返回的tensor不变,因为第0维的大小为A,不是1;squeeze(input, dim=1)后,返回的tensor将被压缩为 (A×B)


torch.mm() / torch.matmul() / torch.mul()

torch.mm() 只适合二维张量的矩阵乘法,如 m*n 和 n*p 输出为 m*p

A = torch.tensor([[1, 2], [3, 4]])
B = torch.tensor([[5, 6], [7, 8]])
result = torch.mm(A, B) 或 result = torch.matmul(A, B) 二维时两者等价

tensor([[19, 22],
        [43, 50]])

若三维或更高维度,可以用 torch.matmul();同时它也支持矩阵与向量的乘法、向量与向量的点积。如例:

# 矩阵与向量乘法
A = torch.tensor([[1, 2], [3, 4]])
v = torch.tensor([1, 1])
result = torch.matmul(A, v)

tensor([3, 7])

# 向量与向量乘法
v1 = torch.tensor([1, 2])
v2 = torch.tensor([3, 4])
result = torch.matmul(v1, v2)  # 1*3 + 2*4 = 11

tensor(11)

torch.mul() 是两个矩阵的元素对位相乘,即哈达玛积。故输入的两个矩阵维度必须一致,返回的仍是同维度的矩阵

# 两个张量乘法
A = torch.tensor([1, 2, 3])
B = torch.tensor([4, 5, 6])
result = torch.mul(A, B)

tensor([4, 10, 18])

# 张量与标量乘法
A = torch.tensor([1, 2, 3])
result = torch.mul(A, 2)

tensor([2, 4, 6])

更多张量乘法见Pytorch常用乘法函数总结:torch.mul()、*、torch.mm()、torch.bmm()、torch.mv()、torch.dot()、@、torch.matmul()-CSDN博客


torch.clamp_()

torch.clamp_(input, min, max, out=None) → Tensor

将输入input张量每个元素的值压缩到区间 [min, max],并直接将结果返回给这个tensor(而不是返回新的tensor)

tensor = torch.tensor([[-1, 2], [3, 10], [15, -5]])
# 使用clamp_限制张量的值在0到5之间
tensor.clamp_(0, 5) 或 torch.clamp_(tensor, 0, 5)

tensor([[0, 2],
        [3, 5],
        [5, 0]])

若为torch.clamp() ,即没有下划线,则返回一个新的tensor

clamped_tensor = torch.clamp(tensor, 0, 5)

# tensor本身不会改变,clamped_tensor将包含限制后的值

pytorch中,一般来说,如果对tensor的一个函数后加了下划线,表明这是一个in-place类型(当在一个tensor上操作了之后,是直接修改了这个tensor,而不是返回一个新的tensor而并不修改旧的tensor)


torch.tensor().item()

.item() 返回的是一个浮点型数据。在求loss或者accuracy时,一般使用 .item()

import torch
x = torch.randn(2, 2)   # 2行2列
print(x)
print(x[1,1])
print(x[1,1].item())

tensor([[ 0.4702,  0.5145],
        [-0.0682, -1.4450]])
tensor(-1.4450)
-1.445029854774475

torch.tensor().view()

用于tensor维度的重构,即返回一个有相同数据、但不同维度的tensor

view函数的操作对象应该是tensor类型。如果不是tensor类型,可以通过 torch.tensor() 来转换

temp = [1,2,3,4,5,6]      # temp的类型为list,非Tensor
temp = torch.tensor(temp) # 将temp由list类型转为Tensor类型。torch.Size([6])

print(temp.view(2,3))     # 将temp的维度改为2*3
print(temp.view(2,3,1))   # 将temp的维度改为2*3*1
print(temp.view(2,3,1,1)) # 更多的维度也没有问题,只要保证维度改变前后的元素个数相同就行,即2*3*1*1=6

​ 

特殊用法:

  • 如果某个参数为-1,表示该维度取决于其他维度,由Pytorch自己计算得到;
  • 如果直接view(-1),表示将tensor转为一维tensor
temp = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(temp)   # torch.Size([2, 3])
print(temp.view(-1))   # 多维张量转为一维张量

tensor([1, 2, 3, 4, 5, 6])

torch.gather()

从原tensor中获取指定dim和指定index的数据。方便从批量tensor中获取指定索引下的数据,该索引是高度自定义且可乱序的

torch.gather(input, dim, index)
  • dim:dim=1 表示按照行号进行索引;dim=0 表示按照列号进行索引
  • index:索引张量,指定要从input的dim维度上提取哪些元素。index的大小应和返回结果相同

例1:在0维上gather(按照列号

import torch

x = torch.tensor([[10, 20, 30], 
                  [40, 50, 60], 
                  [70, 80, 90]])

index = torch.tensor([[0, 2, 1], 
                      [1, 0, 2], 
                      [2, 1, 0]])

result = torch.gather(x, dim=0, index=index)
print(result)

tensor([[10, 80, 60],
        [40, 20, 90],
        [70, 50, 30]])

例2:在1维上gather(按照行号

x = torch.tensor([[10, 20, 30], 
                  [40, 50, 60], 
                  [70, 80, 90]])

index = torch.tensor([[2, 1, 0], 
                      [0, 2, 1], 
                      [1, 0, 2]])

result = torch.gather(x, dim=1, index=index)
print(result)

tensor([[30, 20, 10],
        [40, 60, 50],
        [80, 70, 90]])

例3:实际应用,获取分类任务中真实类别的预测概率

import torch
import torch.nn.functional as F

logits = torch.tensor([[2.0, 1.0, 0.1], 
                       [0.5, 2.1, 1.3]])

labels = torch.tensor([[0], [1]])  # 真实类别索引

# 计算 softmax 使其成为概率
probs = F.softmax(logits, dim=1)   # dim=0 列优先,dim=1 行优先

tensor([[0.6590, 0.2424, 0.0986],
        [0.1863, 0.5141, 0.2996]])

# 使用 gather 提取 labels即真实标签 对应的概率
selected_probs = torch.gather(probs, dim=1, index=labels)

tensor([[0.6590],
        [0.5141]])

PyTorch中torch.gather()函数-CSDN博客

torch.gather()函数-CSDN博客


torch.pow()

对输入tensor的分量求幂次运算

a = torch.tensor(3)
b = torch.pow(a,2)  # tensor(9) 即3^2=9
 
c = torch.randn(4)   # tensor([0.0923, 0.7006, -0.2963, 0.6543]) 
# 对其中的每个分量求平方
d = torch.pow(c,2)   # tensor([0.0085, 0.4909, 0.0878, 0.4282])

PyTorch 笔记(05)— Tensor 基本运算(torch.abs、torch.add、torch.clamp、torch.div、torch.mul、torch.pow等)-CSDN博客


torch.stack() / torch.cat()

torch.stack() 将多个形状相同的张量沿着一个新维度进行堆叠,即合并成一个更高维度的张量

torch.stack(tensors, dim=0)
  • tensors:一个包含多个张量的序列(例如,列表或元组)。所有张量必须具有相同的形状
  • dim:要插入新维度的位置,默认为0
  • 返回值:在指定的维度dim上增加了一个新的维度,原始张量的形状在其他维度上保持不变

例1:沿第0维堆叠

import torch

# 创建三个形状相同的张量
x1 = torch.tensor([1, 2])
x2 = torch.tensor([3, 4])
x3 = torch.tensor([5, 6])

# 沿着第0维堆叠
result = torch.stack([x1, x2, x3], dim=0)

print(result)
tensor([[1, 2],
        [3, 4],
        [5, 6]])

print(result.shape)  # 输出: torch.Size([3, 2])

例2:沿第1维堆叠

import torch

# 创建三个形状相同的张量,形状为(2,)
x1 = torch.tensor([1, 2])
x2 = torch.tensor([3, 4])
x3 = torch.tensor([5, 6])

result = torch.stack([x1, x2, x3], dim=1)

print(result)
tensor([[1, 3, 5],
        [2, 4, 6]])

print(result.shape)  # 输出: torch.Size([2, 3])

torch.stack() 会在指定维度上增加一个新的维度,而 torch.cat() 是沿着现有维度连接多个张量,张量的形状不会增加新的维度

torch.cat(tensors, dim=0)
  • tensors:一个包含多个张量的序列(例如,列表或元组)。这些张量的形状必须在除了指定维度dim之外相同
  • dim:要沿着其连接的维度,默认为0,表示沿着行拼接
  • 返回值:在指定的维度上将输入的多个张量拼接起来

例1:沿第0维拼接

import torch

# 创建两个形状相同的张量
x1 = torch.tensor([[1, 2], [3, 4]])
x2 = torch.tensor([[5, 6], [7, 8]])

# 沿着第0维度拼接
result = torch.cat([x1, x2], dim=0)

print(result)
tensor([[1, 2],
        [3, 4],
        [5, 6],
        [7, 8]])

print(result.shape)   # 输出: torch.Size([4, 2])

例2:沿第1维拼接

import torch

# 创建两个形状相同的张量
x1 = torch.tensor([[1, 2], [3, 4]])
x2 = torch.tensor([[5, 6], [7, 8]])

result = torch.cat([x1, x2], dim=1)

print(result)
tensor([[1, 2, 5, 6],
        [3, 4, 7, 8]])

print(result.shape)  # 输出: torch.Size([2, 4])

例3:拼接不同维度的张量(这些张量的形状必须在除了指定维度dim之外相同

# 创建两个形状不同的张量
x1 = torch.tensor([[1, 2], [3, 4]])   # (2, 2)
x2 = torch.tensor([[5, 6]])   # (1, 2)

# 沿着第0维度拼接
result = torch.cat([x1, x2], dim=0)

print(result)
tensor([[1, 2],
        [3, 4],
        [5, 6]])

print(result.shape)  # 输出: torch.Size([3, 2])

例4:拼接张量和标量

# 创建张量和标量
x1 = torch.tensor([1, 2, 3])
scalar = torch.tensor([4])

# 沿着第 0 维度拼接
result = torch.cat([x1, scalar], dim=0)

print(result)
tensor([1, 2, 3, 4])

torch.tensor().t()

将tensor进行转置

import torch
a = torch.tensor([[1,2],[3,4]])

a
tensor([[1, 2],
        [3, 4]])

a.t()
tensor([[1, 3],
        [2, 4]])

Pytorch里.t()的作用-CSDN博客


torch.manual_seed()

用于设置随机数生成器种子,确保每次运行时生成相同的随机数序列。通常,用于确保实验的可复现性,特别是在训练深度学习模型时,需要确保每次训练模型的初始化权重和数据的随机划分一致

torch.manual_seed(seed)   # seed为一个整数。一般设置为 42

torch.manual_seed() 只会影响在CPU上的随机数生成。如果使用了GPU,还需要设置GPU上的随机数种子

# 设置GPU上的随机数种子
torch.cuda.manual_seed(seed)
torch.cuda.manual_seed_all(seed)  # 如果使用多个GPU

注:如果代码中还使用了numpy,也可以设置numpy的随机种子,使得整个实验过程是可复现的

np.random.seed(seed)

参考:pytorch如何确保 可重复性/每次训练结果相同(固定了随机种子,为什么还不行)? - Cheer-ego的回答 - 知乎


torch.empty()

创建一个具有指定形状、但内容未定义,即未经初始化(不会被初始化为零或者任何其他值)的张量。由于不进行任何初始化工作,它比 torch.zeros() 或 torch.randn() 等初始化函数更快

# *表示必选,其余参数都为可选
torch.empty(*size, dtype=None, layout=torch.strided, device=None, requires_grad=False)
  • size:张量的形状,可以是整数或元组。如 (2, 3) 表示一个2×3的张量
  • dtype:张量的数据类型,默认为torch.float32
  • layout:张量的布局,默认为torch.strided,通常不需要改
  • device:张量存储的设备,默认CPU,通过 torch.device('cuda') 可以将张量创建在GPU上
# 创建一个2x2的未初始化张量,并放到GPU上
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
tensor_gpu = torch.empty(2, 2, device=device)
  • requires_grad:默认为False。如果设置为True,则张量将追踪其所有操作,支持自动求导(用于神经网络训练)

应用场景:

  • 模型权重初始化
tensor = torch.empty(3, 3)  # 创建一个未初始化的张量
torch.nn.init.normal_(tensor, mean=0.0, std=1.0)  # 使用正态分布初始化
  • 高效内存分配:知道张量的形状,但暂时不关心其内容时,可以使用 torch.empty() 创建一个张量,并稍后填充或更新它的内容
# 多任务学习的一个例子
task1_dim, task2_dim = 3, 2
y_train_task1 = torch.empty(num_samples, task1_dim)
y_train_task1[:, 0] = torch.randint(0, 2, (num_samples,)).float()   # 是否停留
y_train_task1[:, 1] = torch.randn(num_samples)   # 停留时长
y_train_task1[:, 2] = torch.randint(0, 2, (num_samples,)).float()   # 是否点击

y_train_task2 = torch.empty(num_samples, task2_dim)
y_train_task2[:, 0] = torch.randn(num_samples)   # 点击后播放时长
y_train_task2[:, 1] = torch.randint(0, 2, (num_samples,)).float()   # 播放后是否点赞

torch.einsum()

爱因斯坦求和约定

  • 提供了一种灵活且高效的方式来执行各种线性代数操作(如矩阵乘法、矩阵转置、向量点积、外积)、广播操作、求和或聚合操作(如矩阵迹)等
  • 通过符号表示操作中的维度来描述操作,而不需要显式地使用循环或中间张量
torch.einsum(equation, *operands)
  • equation:一个字符串,指定了操作的维度及求和的规则(通过字母表示张量的维度,维度之间用逗号分隔)
  • operands:需要操作的张量,可以是多个张量

矩阵乘法:(m, n) 与 (n, p) -> (m, p)

torch.einsum('ij,jk->ik', A, B)

向量点积:对应元素相乘并求和,即dot product

torch.einsum('i,i->', a, b)

向量外积(outer product):假设向量a 和 向量b 的维度分别是 (m) 和 (n),通过将 向量a 中的每个元素和 向量b 中的每个元素相乘,生成一个 (m, n)维度 的矩阵

torch.einsum('i,j->ij', a, b)

矩阵转置:

torch.einsum('ij->ji', A)

广播:torch.einsum('ij,j->ij', A, B) 表示将A的每一列与B对应的元素相乘,从而实现广播

A = torch.tensor([[1, 2, 3, 4],
                  [1, 1, 1, 1],
                  [4, 3, 2, 1]])   # torch.Size([3, 4])
B = torch.tensor([2, 2, 2, 2])     # torch.Size([4])
 
# 广播
result = torch.einsum('ij,j->ij', A, B)

print(result)
tensor([[2, 4, 6, 8],
        [2, 2, 2, 2],
        [8, 6, 4, 2]])   # torch.Size([3, 4])

矩阵迹(trace):矩阵对角线元素的和

torch.einsum('ii->', A)

torch.randn() / torch.randint()

torch.randn() 用于生成服从标准正态分布(均值为0,标准差为1)的随机浮点数

# *表示必选,其余参数都为可选
torch.randn(*size, dtype=None, device=None, requires_grad=False)
  • size:生成张量的形状,可以是一个整数或一个整数元组
  • dtype:张量的数据类型,默认为torch.float32
  • device:默认为CPU。如果需要创建GPU上的张量,可以使用 torch.device('cuda') 或指定 device='cuda'
  • requires_grad:是否需要计算梯度,默认False

常见用途:初始化神经网络权重、生成噪声、随机生成生态分布数据

torch.randint() 用于生成指定范围内的整数随机数,并可以指定张量的形状。返回一个包含随机整数的张量,生成的整数值是离散的,形状由size指定,生成的数值位于 [low, high) 之间

# *表示必选,其余参数都为可选
torch.randint(*low, *high, *size, dtype=None, device=None, requires_grad=False)
  • low:生成的随机数的下限(包含)
  • high:生成的随机数的上限(不包含)
  • dtype:默认为torch.int64
  • 其它参数同上

常见用途:随机生成整数类型的标签(如分类标签)或索引、生成数据集的随机批次索引

两者对比:


模型层面

TensorDataset() / Dataset() / DataLoader()

from torch.utils.data import TensorDataset, Dataset, DataLoader

TensorDataset 通常用于将特征张量和标签张量组合在一起,封装成一个数据集对象,便于传递给模型训练

# *tensors可以是任意数量的张量,但必须保证第一个维度都相同
torch.utils.data.TensorDataset(*tensors)
  • 每个张量的第一个维度(代表样本数量)应该是相同的,因为这些张量会按行组合起来,每一行代表一个样本
  • 返回一个可迭代的数据集对象,可以通过DataLoader将其包装成一个数据加载器,以便按批次加载数据

应用: 

dataset = TensorDataset(features, labels)

# 如果数据集包含多个特征和多个标签
dataset = TensorDataset(features1, features2, labels1, labels2)   # 将两个特征张量和两个标签张量组合在一起,每个批次中返回四个元素

Dataset 是用于表示数据集的基类,可以通过继承 torch.utils.data.Dataset 类来定义自己的数据集类(自定义如何加载数据、如何处理数据)。需要实现两个方法:

  • __len__():返回数据集的大小,即数据集中样本的数量
  • __getitem__(index):根据索引返回数据集中一个样本,通常是特征和标签。可以在这里进行数据的预处理,如数据增强、归一化、标准化等
import torch
from torch.utils.data import Dataset, DataLoader

class MyDataset(Dataset):
    def __init__(self, features, labels):
        self.features = features
        self.labels = labels

    def __len__(self):
        return len(self.features)  # 数据集的大小

    def __getitem__(self, idx):
        # 根据索引返回一个数据样本,包括特征和标签
        x = self.features[idx]
        y = self.labels[idx]
        return x, y

# 创建自定义数据集实例
dataset = MyDataset(features, labels)

DataLoader 用于批量加载数据,通常与 TensorDataset 或自定义的数据集类一起使用。提供了批量加载(将数据按批次加载到内存中进行训练。batch_size)、数据打乱(帮助提高模型训练的泛化能力。shuffle)、并行加载(使用多线程并行加载数据,提高数据加载速度。num_workers)、自动迭代(类似于迭代一个list)等功能

torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None,
                            batch_sampler=None, num_workers=0, collate_fn=None,
                            pin_memory=False, drop_last=False, timeout=0,
                            worker_init_fn=None)
  • dataset: 传入的数据集对象。它可以是 TensorDatasetDataset 的子类或自定义的数据集类,必须实现 __len____getitem__ 方法。

  • batch_size (int, default=1): 每个批次包含的样本数量。

  • shuffle (bool, default=False): 是否在每个epoch结束后打乱数据。设置为 True 会对数据进行随机打乱,这在训练过程中通常是必需的。

  • sampler (torch.utils.data.Sampler, optional): 通常用于定制数据抽取方式。可以选择不使用 shuffle,而使用自定义的 sampler

  • batch_sampler (torch.utils.data.BatchSampler, optional): 类似于 sampler,但返回批次样本。

  • num_workers (int, default=0): 用于加载数据的子进程数量。设置为大于0时,DataLoader 将在多个进程中并行加载数据(通常会提升加载速度)。一般来说,num_workers 设置为系统 CPU 核心数的 1-2 倍比较合适。

  • collate_fn (callable, optional): 用于将一个批次内的数据组合成一个小批量。可以根据需要自定义,如填充、拼接等。

  • pin_memory (bool, default=False): 如果设置为 TrueDataLoader 会将数据加载到内存中并进行内存页锁定,这在使用GPU加速时可能提高性能。

  • drop_last (bool, default=False): 如果设置为 True,在数据集大小不能被 batch_size 整除时,会丢弃最后一个不满批次的数据。

  • timeout (int, default=0): 如果设置为正值,则表示加载数据时最大超时时间(秒)。一般不常用,除非遇到数据加载卡顿的情况。

  • worker_init_fn (callable, optional): 如果使用多进程加载数据,可以传入一个函数,用于在每个子进程初始化时执行自定义操作(例如设置随机种子)。

例1:基本使用 

import torch
from torch.utils.data import TensorDataset, DataLoader

# 特征张量和标签张量
features = torch.randn(10, 5)  # 10个样本,每个样本有 5个特征
labels = torch.randint(0, 2, (10,))  # 10个标签,0或1

# 创建TensorDataset
dataset = TensorDataset(features, labels)

# 使用 DataLoader创建批量加载器
dataloader = DataLoader(dataset, batch_size=3, shuffle=True)

# 迭代 DataLoader,按批次加载数据
for data in dataloader:
    inputs, targets = data
    print(inputs.shape, targets.shape)

torch.Size([3, 5]) torch.Size([3])
torch.Size([3, 5]) torch.Size([3])
torch.Size([3, 5]) torch.Size([3])
torch.Size([1, 5]) torch.Size([1])

例2:自定义collate_fn函数

  • 用于定义如何将一个批次内的数据组合成一个小批量
  • 如下例,collate_fn 将批次数据按最大长度进行填充,使得每个输入张量的长度相同。适用于处理变长序列数据(如文本、时间序列等)
# 自定义处理批次数据(例如填充到相同的长度)
def collate_fn(batch):
    # 将一个包含多个元组的列表(或可迭代对象)解包为两个独立的列表(或元组)
    inputs, targets = zip(*batch)
 
    max_len = max([len(x) for x in inputs])
    # 假设想要按最大长度填充数据
    padded_inputs = [torch.cat([x, torch.zeros(max_len - len(x))]) for x in inputs]
    return torch.stack(padded_inputs), torch.tensor(targets)

# 创建 DataLoader,使用自定义的 collate_fn
dataloader = DataLoader(dataset, batch_size=3, collate_fn=collate_fn)

# 迭代 DataLoader
for data in dataloader:
    inputs, targets = data
    print(inputs)
    print(targets)

参考 Pytorch的数据读取机制:Dataset类 & DataLoader类以及collate_fn参数 


nn.MSELoss() / nn.BCELoss()

import torch.nn as nn

nn.MSELoss() 是用于计算均方误差(Mean Squared Error,MSE)的损失函数,常用于回归问题。相较于 nn.L1Loss(),MSELoss更加敏感于离群点(Outliers),因为它使用了平方项,离群点的影响被放大;而 L1Loss() 使用的是绝对值,对离群点的影响较小。

  • 参数:reduction(可选,默认是 'mean' ) 
    • mean:返回所有样本的损失均值
    • sum:返回所有样本的损失总和
    • none:返回一个张量,包含每个样本的损失值
  • 训练神经网络时,如果使用MSELoss,输出层通常是线性激活,即没有激活函数,或使用ReLU / Tanh 等

import torch
import torch.nn as nn

# 假设我们有一些预测值和真实值
y_true = torch.tensor([1.0, 2.0, 3.0])
y_pred = torch.tensor([1.5, 2.5, 3.5])

# 定义 MSELoss
mse_loss = nn.MSELoss()

# 计算 MSE损失
loss = mse_loss(y_pred, y_true)
print(f'MSE Loss: {loss.item()}')   # MSE Loss: 0.25

nn.BCELoss() 是用于二分类问题的二进制交叉熵损失函数(Binary Cross Entropy Loss),要求预测值是一个概率值(介于0~1),通常需要使用Sigmoid函数;标签必须是二分类标签(0或1)

  • 参数:reduction(可选,默认是 'mean' ),用法同上,可以选择返回均值、总和或每个样本的损失
  • 如果模型输出的不是概率值(即通过Sigmoid进行归一化的值),而是原始的未归一化分数(logits),可以使用 nn.BCEWithLogitsLoss() 。该损失函数会自动对logits进行Sigmoid操作,而无需显式地在模型输出中应用Sigmoid


optim.Adam() 等优化器

import torch.optim as optim
optimizer = optim.Adam(model.parameters(), lr=0.001)

Pytorch提供了多种优化器:

  • optim.SGD:使用梯度下降的随机版本更新参数。缺点是易陷入局部最小值,且收敛速度较慢
    • lr:学习率(需要手动调整)
    • momentum:动量,用来加速收敛,减少震荡,避免陷入局部最小值
    • weight_decay:L2正则化系数
  • optim.Adagrad:根据每个参数的历史梯度自适应调整学习率
    • 对于稀疏梯度有很好的表现
    • 对于长期训练可能导致学习率下降太快(变为0,停止训练),从而无法收敛
  • optim.RMSprop:是一种自适应学习率的优化器,在序列数据如RNN中表现优异
    • lr:学习率
    • alpha:衰减因子,控制过去梯度的影响
    • weight_decay:L2正则化系数
  • optim.Adam:是SGD的一个改进版本,结合了 Momentum 和 RMSprop 的优点,能自动调整每个参数的学习率,故通常不需要过多的超参数调整
    • 对于稀疏梯度表现较好;比普通的SGD更稳定,不容易陷入局部最小值
    • 某些情况下比SGD更容易过拟合,尤其是当训练集较小时
  • optim.Adadelta:是Adagrad的改进版本,旨在解决Adagrad在训练时学习率下降过快的问题
  • optim.NAdam:是Adam和Nesterov动量的结合。由于Nesterov加速的优势,可能加速收敛;但计算开销相对较大,训练时间较长
  • optim.FTRL:适用于稀疏特征的优化,常用于大规模机器学习问题
  • optim.LBFGS:是一种基于二阶优化方法的算法,适用于较小的数据集和模型,常用于精细调优阶段,收敛速度较快,能得到更精确的最优解
  • optim.SparseAdam:是Adam的稀疏版本,通常用于处理具有稀疏梯度的模型(如嵌入层)
  • optim.ASGD:基于SGD的变种,结合了平均化策略来减少震荡。比传统SGD更稳定,但适用于特定类型的任务,故不常用

不同优化器对比参考 七种反向传播优化器总结及Python实现(SGD、SGDM、Adagrad、RMSProp、Adam、NAG、AdaDelta)


torch.nn.Sigmoid() / torch.nn.Softmax()

torch.nn.Sigmoid() 将输入值映射到一个 0~1 之间的输出(会对张量的每个元素应用Sigmoid函数),常用于二分类问题中的输出层,尤其是需要输出概率值的情况

  • 除了 nn.Sigmoid() 模块,还可以直接使用 torch.sigmoid() 函数

如二分类模型最后一层通常是一个Sigmoid激活函数,将模型输出映射到0~1之间,表示某一类的概率(如输出0.8表示模型认为该样本属于正类的概率为80%):

# 模型的输出层定义
output_layer = nn.Linear(in_features, 1)  # 输出一个标量
output = nn.Sigmoid(output_layer(x))

问题:在输入值较大或较小时(即接近0或接近1),梯度会变得非常小,几乎为0,这可能导致训练时出现梯度消失。因此Sigmoid不适合用在隐藏层,而通常用于输出层 

  • vs ReLU:ReLU输出范围是 (0, +∞),常用于隐藏层的激活函数,相对于Sigmoid能更有效地避免梯度消失问题
  • vs Tanh:Tanh输出范围是 (-1, 1),与Sigmoid相比,Tanh在训练时通常表现得更好,因为它的输出对称性使得模型的学习更加稳定

torch.nn.Softmax() 将输入的多个值转换为一个概率分布,输出的概率值和为1,通常用于多分类任务的输出层

  • 参数dim:决定沿哪个维度应用softmax
    • dim=0:通常是batch维度,适用于对每个样本的类别进行归一化
    • dim=1:通常是样本维度,是大多数多分类任务的标准做法
  • 参数dtype:指定返回张量的数据类型,通常是浮点数类型
  • 等价写法:torch.softmax(x, dim=1) 函数
  • 若输入得分非常大或非常小,可能导致数值上的不稳定。因此,通常会对输入进行缩放处理(例如减去每行的最大值)。上面两种softmax写法都已经自动进行了数值稳定性处理,不需要再手动处理

例1:以二维输入为例

import torch.nn as nn

input = torch.tensor([[1., 2, 3],
                      [4, 5, 6]])   # input必须为float类型

m1 = nn.Softmax(dim=0)
output1 = m1(input)

m2 = nn.Softmax(dim=1)   # dim=1表示在每一行(即每个样本)上应用Softmax
output2 = m2(input)

# dim=-1就是按最后一维,这个例子里等价于dim=1

  • 二维tensor参考:【Pytorch】torch.nn. Softmax()_torch.softmax-CSDN博客
  • 多维tensor可以参考:Pytorch nn.Softmax(dim=?) - 知乎

例2:在训练多分类模型时,常常使用 torch.nn.CrossEntropyLoss,它会自动应用softmax(不需要在模型的输出层显式使用softmax,而是可以直接输出未经softmax归一化的原始得分,即logits

# 定义 CrossEntropyLoss
criterion = nn.CrossEntropyLoss()

# y_pred是未经Softmax处理的logits,y_true是标签(整数索引)
y_pred = torch.tensor([[1.0, 2.0, 3.0], [1.0, 2.0, 3.0]])
y_true = torch.tensor([2, 1])

# 计算损失
loss = criterion(y_pred, y_true)
print(f'CrossEntropyLoss: {loss.item()}')

nn.ModuleList() / nn.ParameterList()

nn.ModuleList() 是一个用于保存 nn.Module对象的容器,是一个有序的容器,可以按顺序存储多个子模块(如多个卷积层、全连接层等)。在Pytorch中,它能够保证其中的每个模块都被正确地注册到模型中,且可以通过 .parameters() 自动获取模型中的所有参数

  • 所有的子模块会被自动地添加到模型的参数列表中
  • 在模型的forward函数中可以动态地通过索引调用各个子模块
import torch
import torch.nn as nn

class ExampleModel(nn.Module):
    def __init__(self):
        super(ExampleModel, self).__init__()
        self.layers = nn.ModuleList([nn.Conv2d(1, 32, 3), nn.Conv2d(32, 64, 3)])

    def forward(self, x):
        for layer in self.layers:
            x = layer(x)
        return x

nn.ParameterList() 是专门用于存储 nn.Parameter 对象(nn.Parameter是torch.Tensor的一个子类,用于存储模型中的参数,如权重和偏置)的容器。用于管理模型中手动创建的、通常需要进行梯度更新的参数

  • 适用于存储多个独立的参数,如自定义的权重、偏置等
  • 不会自动注册任何模块,仅仅用于管理参数,这些参数可以直接参与优化过程
import torch
import torch.nn as nn

class ExampleModel(nn.Module):
    def __init__(self):
        super(ExampleModel, self).__init__()
        self.weights = nn.ParameterList([nn.Parameter(torch.randn(3, 3)) for _ in range(5)])

    def forward(self, x):
        for weight in self.weights:
            x = torch.matmul(x, weight)
        return x

总结:

  • nn.ModuleList() 用于存储 nn.Module 子模块,主要作用是组织网络层级,确保模块的自动注册
  • nn.ParameterList() 用于存储 nn.Parameter,主要用于管理模型的参数(例如权重和偏置),而不是层或子模块

http://www.niftyadmin.cn/n/5869164.html

相关文章

文心一言AI创意画

介绍 文心一言是百度推出的新一代知识增强大语言模型,属于文心大模型家族的新成员。‌它能够与人对话互动、回答问题、协助创作,高效便捷地帮助人们获取信息、知识和灵感。‌ 特点 文心一言基于数万亿数据和数千亿知识进行融合学习,采用预训…

【大语言模型】【整合版】DeepSeek 模型提示词学习笔记(散装的可以看我之前的学习笔记,这里只是归纳与总结了一下思路,内容和之前发的差不多)

以下是个人笔记的正文内容: 原文在FlowUs知识库上,如下截图。里面内容和这里一样,知识排版好看一点 一、什么是 DeepSeek 1. DeepSeek 简介 DeepSeek 是一家专注于通用人工智能(AGI)的中国科技公司,主攻大模型研发与…

Android Audio实战——音频相关基础概念(附)

Android Audio 开发其实就是媒体源数字化的过程,通过将声波波形信号通过 ADC 转换成计算机支持的二进制的过程叫做音频采样 (Audio Sampling)。采样 (Sampling) 的核心是把连续的模拟信号转换成离散的数字信号。 一、声音的属性 1、响度 (Loudness) 响度是指人类可以感知到的…

IDEA配置Github上传项目

1. 创建项目仓库 2. 设置独立账户 可配置ssh key 可配置令牌,这里选择令牌,Personal access tokens 生成个人访问令牌: 登录到 GitHub,前往 Settings > Developer settings > Personal access tokens,生成一个…

FastAPI高级特性(二):错误处理、中间件与应用生命周期

前言 FastAPI 不仅以其高性能和易用性著称,还内置了丰富的高级特性,使得开发者可以快速组织和封装各种功能。在本篇博客中,我们将深入探讨 FastAPI 的一些高级特性,包括错误处理、中间件和应用生命周期管理。通过这些特性,开发者可以在应用的不同阶段和层面上挂载自定义逻…

机器视觉--线扫相机触发

绪论 在当今蓬勃发展的机器视觉领域,线扫相机堪称关键角色,它凭借高分辨率的扫描成像能力,广泛应用于工业检测、物流识别、印刷质量检测等众多核心场景。线扫相机的触发方式作为成像环节的核心要素,直接决定了图像采集的精准度与…

看视频学习方法总结

以下是提高教学视频吸收率的系统性方法,结合认知科学原理和实际学习场景,帮助您最大化学习效果: 一、观看前的黄金准备阶段 60秒快速扫描法 用1分钟快速浏览视频目录、章节标题和简介,建立知识框架。荷兰伊拉斯姆斯大学实验表明&…

手撕FocalLoss

文章目录 前言1、FocalLoss1.1.公式定义 2、代码总结 前言 为了加深对Focal Loss理解,本文提供了一个简单的手写Demo。 1、FocalLoss 介绍FocalLoss的文章已经很多了,这里简单提一下: 1.1.公式定义 Focal Loss 的公式如下: FL (…