PyTorch是一个基于Python语言的深度学习框架,它将数据封住成张量(Tensor)来进行处理,PyTorch提供了灵活且高效的工具,用于构建、训练和部署机器学习和深度学习模型,广泛运用于计算机视觉、自然语言处理、强化学习等领域。
Tensor是PyTorch中最基本的数据结构,可以理解为多维的数组(或元素是同一种类型的多维矩阵),可以运行在GPU上,从而实现高速并行运算。如:
0维张量:一个数字(标量),1维张量:一个数组(向量),2维张量:一个矩阵(矩阵),3维张量:一个数据体,比如彩色的图片3x244x244(通道宽高),4维张量:一个数据批次,如:一个批次的图片32x3x244x244(批次大小通道宽*高)。
PyTorch特点: 类似于NumPy的张量计算,自动微分系统,深度学习库,动态计算图,GPU加速(CUDA支持),支持多应用场景,跨平台支持……
通道:是张量中非常核心的一个概念,可以理解为数据中承载不同信息的层次和维度。
安装pytorch:
pip install torch
安装numpy:
pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple
张量的基本创建方式:
·torch.tensor 根据指定数据创建张量
·torch.Tensor 根据形状创建张量,其也可用来创建指定数据的张量
·torch.IntTensor、torch.FloatTensor、torch.DoubleTensor 创建指定类型的张量
创建线性张量和随机张量:
·torch.arrange() 和 torch.linspace() 创建线性张量
·torch.random.initial_seed() 和 torch.random.manual_seed() 随机种子设置
·torch.rand/randn() 创建随机浮点类型张量
·torch.randint(low,high,size=()) 创建随机整数类型张量
创建0、1、指定值张量:
·torch.ones 和 torch.ones_like 创建全1张量
·torch.zeros 和 torch.zeors_like 创建全0张量
·torch.full 和 torch.full_like 创建全为指定值张量
张量元素类型转换:
1.data.type(torch.DoubleTensor)
2.data.half/double/float/short/int/long()
创建三维张量:
张量与NumPy数组的相互转换(NumPy 负责数据处理,PyTorch 张量负责模型训练。数据要进模型 → 转张量。结果要处理、画图、保存 → 转回 NumPy。张量可以去 GPU numpy 只能在 CPU所以要来回转换):
张量转换为NumPy数组:
使用Tensor.numpy函数可以将张量转换为ndarray,但是共享内存,可以使用copy函数避免共享。
NumPy数组转化为张量:
张量的基本运算:
加减乘除取符号:
add、sub、mul、div、neg
add_、sub_、mul_、div_、neg_(带下划线的版本会修改原数据)
张量点乘(*,A.mul(B))、张亮的矩阵乘法(@,torch.matmul(A,B))
打印张量维度
print(tensor_3d_ones.size(0))
张量计算函数(sum……):
张量的索引操作:
张量的形状操作:
张量的形状修改:
张量的拼接操作:
自动微分模块(作用:算梯度->调参):
反向传播(loss.backward(),前向铺路,反向全求,loss(标量张量)是起点,沿路全都求一遍(对向量张量求导))/计算梯度:,意思是从这个错误程度往回走,分析错误来源,并计算出参数应该怎么改(调整的方向和大小,也就是梯度),调整建议(梯度)被存到w.grad和b.grad中(使用的是一个叫链式法则的数学规则,可以理解为对参数的责任分配,如某个错误多少是b的因素造成的,多少是w的因素造成的),在下次反向传播前,必须执行optimizer.zeor_grad进行梯度清零(把w.grad和b.grad)中的旧值清空。
pytorch不支持向量张量对向量张量的求导,只支持标量张量对向量张量的求导。x如果是张量,y必须是标量(一个值)才可以进行求导。
单步训练流程先由正向传播,根据初始参数和损失函数计算得到损失张量,然后根据损失张量计算得到一个标量,用这个标量对参数求梯度,然后用学习率和梯度更新参数。
import torch
if __name__ == '__main__':
# 1- 初始化权重参数
"""
-requires_grad=True: 标记该张量需要计算梯度(用于反向传播求导),是pytorch自动微分的核心开关
-dtype=torch.float32: 必须使用浮点类型,因为梯度计算(如w1 = w0-lr*grad)会产生小数,整数无法存储梯度信息
-此处w是二维特征的权重,初始值为【20,30】,表示两个特征的初始权重分别为20和30,这里可以理解为w这个向量里装着w1,w2两个独立的参数
"""
w = torch.tensor([20,30],requires_grad=True,dtype=torch.float32)
print(f"初始权重w:{w},形状:{w.shape}")
# 2- 定义损失函数(自定义损失:loss = 2*w^2)
"""
损失函数公式推导:
-对于单个权重w_i,损失函数为loss_i = 2 * w_i^2
-w是包含两个权重的向量[w1,w2],整体损失张量为[2*w1^2,2*w2^2]
-计算的loss张量为[800.,1800.]
"""
loss = 2*w**2 # 对w中的每个元素分别计算2*平方
print(f"损失张量loss:{loss},形状:{loss.shape}")
# 3- 反向传播(计算梯度)
"""
sum()将损失张量[800.,1800.]转为标量 2600(800+1800)
梯度计算(链式法则):
总损失L = loss1+loss2 = 2*w1**2+2*w2**2
对w1的梯度:L对w1求导:4*w1
对w2的梯度:L对w2求导: 4*w2
代入初始值,得到w.grad应为[80.,120.]
"""
loss.sum().backward()
print(f"权重w的梯度(L对w的导数):{w.grad}")
#4- 更新权重(梯度下降法:W_new=W_old-lr*grad)
"""
-学习率lr=0.01(控制更新步长,避免更新幅度过大或过小)
"""
lr = 0.01
w.data = w.data - lr*w.grad # 原地更新参数值(梯度下降更新权重)
print("修改后的权重值是: ",w.data)
多轮迭代: 单次梯度更新只能让x向最优方向迈一小步(受学习率lr限制),多次迭代才能逐渐接近最优值。通过循环实现多轮更新。
import torch
#这段代码里,w是不断变小的,loss是不断变小的,所以w的变化速度是递减的
if __name__ == '__main__':
# 1- 初始化权重参数
"""
-requires_grad=True: 标记该张量需要计算梯度(用于反向传播求导),是pytorch自动微分的核心开关
-dtype=torch.float32: 必须使用浮点类型,因为梯度计算(如w1 = w0-lr*grad)会产生小数,整数无法存储梯度信息
-此处w是二维特征的权重,初始值为【20,30】,表示两个特征的初始权重分别为20和30,这里可以理解为w这个向量里装着w1,w2两个独立的参数
"""
w = torch.tensor([20,30],requires_grad=True,dtype=torch.float32)
print(f"初始权重w:{w},形状:{w.shape}")
epochs = 100
for epoch in range(epochs):
#pytorch 的梯度会累积(即每次backward()会把新梯度加到旧梯度上),如果不清零,本轮梯度会叠加之前所有轮次的梯度,导致计算错误。
#因此每次迭代前必须用zero_()重置梯度。
if w.grad is not None:
w.grad.zero_()
# 2- 定义损失函数(自定义损失:loss = 2*w^2)
"""
损失函数公式推导:
-对于单个权重w_i,损失函数为loss_i = 2 * w_i^2
-w是包含两个权重的向量[w1,w2],整体损失张量为[2*w1^2,2*w2^2]
-计算的loss张量为[800.,1800.]
"""
loss = 2 * w ** 2 # 对w中的每个元素分别计算2*平方
#print(f"损失张量loss:{loss},形状:{loss.shape}")
# 3- 反向传播(计算梯度)
"""
sum()将损失张量[800.,1800.]转为标量 2600(800+1800)
梯度计算(链式法则):
总损失L = loss1+loss2 = 2*w1**2+2*w2**2
对w1的梯度:L对w1求导:4*w1
对w2的梯度:L对w2求导: 4*w2
代入初始值,得到w.grad应为[80.,120.]
"""
loss.sum().backward()
#print(f"权重w的梯度(L对w的导数):{w.grad}")
# 4- 更新权重(梯度下降法:W_new=W_old-lr*grad)
"""
-学习率lr=0.01(控制更新步长,避免更新幅度过大或过小)
"""
lr = 0.01
w.data = w.data - lr * w.grad # 原地更新参数值(梯度下降更新权重)
#print("修改后的权重值是: ", w.data)