\(Pytorch\)
导入库
import torch
张量\((Tensor)\)
张量是\(Pytorch\)中的核心数据结构,用于存储和操作多维数组。
张量特征
一个张量有以下特征:
\(1.\)维度\((Dimensionality)\)
张量的维度是数据的多维数组结构,零维是一个数字,一维张量就是一维数组,二维张量是一个矩阵,三维张量可以看成是多个矩阵叠成的立方体,四维张量可以看成是立方体向量,五维张量是立方体矩阵。
\(2.\)形状\((Shape)\)
张量的形状是每个维度上的大小,例如形状\((3,4)\)的张量就说明它有三行四列。
\(3.\)数据类型\((Dtype)\)
支持多种数据类型,整数型\((torch.int8,torch.int32)\),浮点型\((torch.float32,torch.float64)\),布尔型\((torch.bool)\)。
dtype = torch.float #张量的数据类型为float
张量的创建
torch.tensor(data) #torch.tensor([[1,2],[3,4]])
a = torch.zeros(2,3) #2X3的全零张量
b = torch.ones(2,3,4) #2X3X4的全一张量
c = torch.randn(2,3) #2X3的随机数张量,创建一个服从正态分布的随机数张量
torch.rand(size) #创建一个服从均匀分布的随机数张量,在[0,1]
torch.arrange(start,end,step) #torch.arrange(0,10,2) 创建一个一维张量,类似python的range
torch.eye(size) #创建一个单位矩阵,主对角线为1,其余为0 torch.eye(3)
#从numpy数组创建张量
import numpy as np
numpy_array = np.array([[1,2],[3,4]])
tensor_from_array = torch.from_numpy(numpy_array)
#在指定设备上创建张量,GPU加速
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
d = torch.randn(2,3,device = device)
张量的属性
\(.shape\):获取张量的形状。\(tensor.shape\)
\(.size():\)获取张量的形状。\(tensor.size()\)
\(.dtype:\)张量的数据类型。\(tensor.dtype\)
\(.device:\)张量所在的设备\((cpu/gpu)\)。\(tensor.device\)
\(.dim():\)张量的维度。\(tensor.dim()\)
\(.requires\_grad:\)是否启用梯度计算。\(tensor.requires\_grad\)
\(.numel():\)张量的元素个数。\(tensor.numel()\)
\(.is\_cuda:\)检查张量是否在\(GPU\)上。\(tensor.is\_cuda\)
\(.T:\)张量的转置(适用于二维张量)。\(tensor.T\)
\(.item():\)获取单元素张量的值。\(tensor.item()\)
\(.is\_contiguous():\)检查张量是否连续存储。\(tensor.is\_contiguous()\)
张量常用操作
基础操作:
#张量相加
a = torch.randn(2,3)
b = torch.randn(2,3)
c = a + b
#张量逐元素相乘
c = a * b
#张量转置
c = a.T
#矩阵相乘 torch.matmul(x,y)
z = torch.matmul(x,y)
#向量点积,仅适用于一维张量 torch.dot(x,y)
z = torch.dot(x,y)
#求和 torch.sum(x)
z = torch.sum(x)
#求平均值 torch.mean(x)
z = torch.mean(x)
#求最大值 torch.max(x)
z = torch.max(x)
#求最小值 torch.min(x)
z = torch.min(x)
#返回最大值的索引(指定维度) torch.argmax(x,dim)
z = torch.argmax(x,dim=1)
#计算softmax(指定维度) torch.softmax(x,dim)
z = torch.softmax(x,dim=1)
形状操作:
#改变张量的形状,但不改变数据 x.reshape(shape)
z = x.reshape(2,3)
#转置矩阵 x.t()
z = x.t()
#在指定维度增加一个维度 x.unsqueeze(dim)
z = x.unsqueeze(0)
#在指定维度减少一个维度 x.squeeze(dim)
z = x.squeeze(0)
#按指定维度连接多个张量 torch.cat((x,y),dim)
z = torch.cat((x,y),dim=0)
梯度与自动微分
创建一个需要梯度的张量时,\(pytorch\)可以自动计算它的梯度。
#创建一个需要梯度的张量
tensor_requires_grad = torch.randn(2, 3, requires_grad=True)
#进行一些操作
tensor_result = tensor_requires_grad * 2
#计算梯度
tensor_result.backward(torch.ones_like(tensor_result))
tensor_requires_grad_grad = tensor_requires_grad.grad
自动求导\((Autograd)\)
自动求导用处有两个方面:一是在训练神经网络时计算梯度,二是用于反向传播算法的实现。
\(pytorch\)可以自动求导,\(torch.tensor\)的对象有一个\(requires\_grad\)的属性,用于指示这个张量是否需要求梯度。
当创建了一个\(requires\_grad=True\)的张量时,\(pytorch\)会自动跟踪对它的操作,以便在后面求梯度。
张量求平均值,用到\(torch.mean()\)函数。
#求张量的平均值
print(a.mean())
#还可以按不同维度规约
b = a.mean(dim=0)
#注意按维度规约相当与按维度压缩,dim=0时,意味着按行方向压缩(即垂直方向),将压缩掉行的维度,保留列的维度。
#同理,dim=1时表示按列方向压缩,将压缩掉列的维度,保留行的维度。
c = a.mean(dim=1,keepdim=True)
#keepdim=True表示保留原始维度
#torch.mean()有三个参数,依次是张量,压缩维度,是否保留原始维度
print(torch.mean(a,1,True))
反向传播\((backward)\)
梯度计算
在\(pytorch\)中,只有浮点类型的数才有梯度。
一旦定义了计算图,就可以用反向传播\(.backward()\)的方法求梯度。反向传播流程是,前向传播计算得到函数损失值,反向传播调用\(loss.backward()\)后会依据链式法则自动回溯求导,计算所有\(requires\_grad=True\)参数的梯度,梯度存储在参数的\(.grad\)属性中,优化器按照参数的\(.grad\)属性更新参数。
x = torch.tensor([1.0], requires_grad=True)
y = x**2 + 3*x # 计算图自动构建
y.backward() # 计算梯度
print(x.grad) # dy/dx = 2x + 3 → 5.0
梯度计算规则
对于标量,直接调用。
loss = model(output, target)
loss.backward() # 直接调用
对于非标量,则需要指定梯度权重。
# 需要指定梯度权重
output = model(input)
output.backward(gradient=torch.ones_like(output))
注意事项
\(pytorch\)中梯度是累积的而不是覆盖的,不清零梯度会一直累积导致梯度爆炸,因此需要注意每次\(batch\)前清空梯度,用\(.zero\_grad()\)。
\(loss.backward(retain\_grph=True)\)表示保留计算图。
不需要计算\(tensor\)梯度时,可以用\(torch.no\_grad()\)或者\(requires\_grad=False\)。
神经网络\((nn.Module)\)
神经网络是模仿人脑神经元连接结构的计算模型,由多层结点(神经元)组成,用于学习数据之间的复杂关系。神经网络通过调整神经元之间的连接权重来优化预测结果,这一过程包括前向传播,损失计算,反向传播,优化器优化(参数更新)。
神经网络在\(pytorch\)中通过\(torch.nn\)模块实现,\(torch.nn\)模块提供了各种网络层,损失函数,优化器。
\(pytorch\)中有无\(()\)的区别
函数或方法:不带括号是引用函数对象本身,带括号是调用函数并执行。
类:不带括号是引用类本身,带括号是创建类的实例。
\(pytorch\)层定义:不带括号是定义层对象,而带括号会导致语法错误(不能在赋值左边用括号)。
\(pytorch\)层使用:不带括号是返回层对象而非计算结果,是错误使用。带括号是返回计算结果。
定义\(nn.Module\)类
\(pytorch\)提供了一个很方便创建神经网络的接口,即\(torch.nn.Module\)。
我们可以继承\(nn.Module\)类并定义自己的网络层。
\(nn.Module\)是所有神经网络模块的基类,需要定义两部分:
\(\_\_init\_\_():\)定义网络层。
\(forward():\)定义数据的前向传播过程。
以下展示了一个简单的全连接神经网络:
import torch
import torch.nn as nn
class simpleNN(nn.Module):#定义网络层def __init__(self):super(simpleNN,self).__init__()#定义一个输入层到隐藏层的全连接层self.fc1 = nn.Linear(2,2) #输入2个特征,输出2个特征#定义一个隐藏层到输出层的全连接层self.fc2 = nn.Linear(2,1) #输入2个特征,输出1个预测值#定义前向传播def forward(self,x):x = torch.relu(self.fc1(x)) #对隐藏层的输入特征使用relu激活函数x = self.fc2(x) #输出层return x
model = simpleNN()
print(model)
\(pytorch\)提供了很多常用的神经网络层:
全连接层(线性层):
\(nn.Linear(in\_features,out\_features,bias=True):\)全连接层,输入\(in\_features\)个特征,输出\(out\_features\)个特征。
卷积层:
\(nn.Conv1d:\)\(1d\)卷积层,用于处理时序数据。
\(nn.Conv2d:\)\(2d\)卷积层,用于图像处理。
\(nn.Conv3d:\)\(3d\)卷积层,用于视频,体积数据。
上述卷积层的参数都有:\(in\_channels,out\_channels,kernel\_size\),输入通道数,输出通道数(卷积核数量),卷积核大小。
循环神经网络层:
\(nn.RNN:\)基础循环神经网络层。
\(nn.LSTM(input\_size, hidden\_size, num\_layers):\)长短期记忆网络层。
\(nn.GRU:\)门控循环单元。
归一化层:
\(nn.BatchNorm1d/2d/3d(num\_features):\)输出归一化,减少内部协变量偏移,允许更大的学习率。
\(nn.LayerNorm:\)层归一化,常用于\(Transformer\)。
\(nn.InstanceNorm2d:\)实例归一化,风格迁移。
\(nn.GroupNorm:\)组归一化,用于小批量场景。
池化层
\(nn.MaxPool1d/2d/3d(kernel\_size):\)最大池化层,提取最显著特征,用于降维。
\(nn.AcgPool1d/2d/3d(kernel\_size):\)平均池化层。
正则化层
\(nn.Dropout:\)提高泛化能力,防止过拟合。
嵌入层
\(nn.Embedding(num\_embeddings,embedding\_dim):\)用于处理离散特征。
\(Transformer\)层
\(nn.Transformer:\)完整的\(Transformer\)模型。
\(nn.TransformerEncoder/Decoder\)
\(nn.MultiheadAttention:\)多头注意力机制。
特殊功能层
\(nn.Upsample:\)上采样。
\(nn.ConvTranspose1d/2d/3d:\)转置卷积。
\(nn.CosineSimilarity:\)余弦相似度。
\(nn.PairwiseDistance:\)成对距离。
容器层
\(nn.Sequential:\)顺序容器。
\(nn.ModuleList:\)层列表(动态网络)。
\(nn.ModuleDict:\)层字典(按名称访问)。
激活函数
\(nn.ReLU():\)\(ReLU\)激活函数,常用于隐藏层。
\(nn.Sigmoid():\)输出\(0-1\),用于二分类。
\(nn.Tanh():\)输出\(-1-1\)。
\(nn.Softmax(dim):\)\(Softmax\)激活函数,常用于输出层,处理多分类问题输出概率。
\(nn.GELU():\)常用于\(Transformer\)。
损失函数
\(nn.CrossEntropyLoss:\)多分类交叉熵。
\(nn.MSELoss:\)均方误差,回归问题常用,计算输出与目标值的平方差。
\(nn.BCELoss:\)二分类交叉熵。
\(nn.L1Loss:\)\(L1\)损失。
\(nn.HuberLoss:\)平滑\(L1\)损失。
\(nn.CosineEmbeddingLoss:\)余弦嵌入损失。
\(nn.BCEWithLogitsLoss:\)常用于二分类问题,结合了\(sigmoid\)激活函数和二分类交叉熵。
优化器\((Optimizer)\)
所有优化器都位于\(torch.optim\)模块中。
import torch.optim as optim
基本梯度下降法\(SGD(Stochastic\ Gradient\ Descent)\)
optim.SGD(params, lr, momentum=0, dampening=0, weight_decay=0, nesterov=False)
自适应学习率优化器
\(Adam(Adaptive\ Moment\ Estimation)\)
最常用的优化器,结合了动量和自适应学习率。
optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False)
\(RMSprop\)
适合处理非平衡目标,常用于循环神经网络。
optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e-08, weight_decay=0, momentum=0, centered=False)
\(Adagrad\)
自适应为每个参数分配学习率,并且适用于稀疏数据。
optim.Adagrad(params, lr=0.01, lr_decay=0, weight_decay=0, initial_accumulator_value=0)
改进型优化器
\(AdamW\)
\(Adam\)的改进版本,更正确地实现权重衰减。通常能获得更好的泛化性能。
optim.AdamW(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0.01, amsgrad=False)
\(NAdam\)
结合了\(Nesterov\)动量和\(Adam\)。
optim.NAdam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, momentum_decay=0.004)
\(RAdam(Rectified\ Adam)\)
修正了\(Adam\)在训练初期的方差问题。
optim.RAdam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)
优化器使用流程
\(1.\)创建优化器实例
import torch.optim as optim# 定义模型
model = MyModel()# 创建优化器 - 以Adam为例
optimizer = optim.Adam(model.parameters(), # 要优化的参数lr=0.001, # 学习率weight_decay=1e-5 # L2正则化(权重衰减)
)
\(2.\)在训练循环中使用
优化器关键方法
\(zero\_grad():\)清空所有参数的梯度,防止梯度积累。
\(step():\)执行单次参数更新。
\(state\_dict():\)返回优化器状态(可保存/加载)。
\(load\_state\_dict():\)加载优化器状态。
\(add\_param\_group():\)添加参数组。
学习率调度器
\(pytorch\)提供了\(torch.optim.lr\_scheduler\)用于动态调整学习率。一般优化器只能固定学习率,而学习率调度器可以动态调整学习率。
from torch.optim.lr_scheduler import StepLR, ReduceLROnPlateau
# 创建优化器
optimizer = optim.Adam(model.parameters(), lr=0.01)
# 创建调度器
scheduler1 = StepLR(optimizer, step_size=30, gamma=0.1) # 每30个epoch学习率×0.1
scheduler2 = ReduceLROnPlateau(optimizer, 'min', patience=5) # 当指标停止改善时降低LR
for epoch in range(100):# 训练...val_loss = validate(model)# 更新学习率scheduler1.step()scheduler2.step(val_loss) # 基于验证损失的调度器
测试与评估
计算训练集的损失:测试模型在未学习过的数据上的损失。
计算准确率\((Accuracy):\)对于分类问题,计算正确预测的比例。
# 假设你有测试集 X_test 和 Y_test
model.eval() # 设置模型为评估模式
with torch.no_grad(): # 在评估过程中禁用梯度计算output = model(X_test)loss = criterion(output, Y_test)print(f'Test Loss: {loss.item():.4f}')