文章目录
PyTorch基础——张量(Tensor)
一、张量基础:概念与核心特性
1.1 张量的数学定义与计算机表示
在数学中,张量是向量空间中的多线性映射,而在PyTorch中,张量是多维数组的泛化表示:
- 0维张量(标量):表示单个数值,维度为0
- 1维张量(向量):表示一组有序数值,维度为1
- 2维张量(矩阵):表示行列结构的数据,维度为2
- n维张量:表示更高维度的数据结构,如3维可表示图像(通道×高度×宽度)
张量的核心属性:
shape
:张量的维度信息,返回一个元组(如(3,4)表示3行4列)dtype
:张量的数据类型,决定了存储精度和范围device
:张量所在的计算设备(CPU/GPU)requires_grad
:是否需要追踪梯度,用于自动求导
1.2 张量的数据类型系统
PyTorch支持丰富的数据类型,主要分为以下几类:
数据类型类别 | 具体类型 | 描述 | 占用字节 |
---|---|---|---|
浮点类型 | torch.float16 |
半精度浮点数,范围±65504 | 2 |
torch.float32 |
单精度浮点数(默认) | 4 | |
torch.float64 |
双精度浮点数 | 8 | |
torch.bfloat16 |
脑浮点格式,适合深度学习 | 2 | |
整数类型 | torch.uint8 |
无符号8位整数(0-255) | 1 |
torch.int8 |
有符号8位整数(-128-127) | 1 | |
torch.int16 |
有符号16位整数 | 2 | |
torch.int32 |
有符号32位整数 | 4 | |
torch.int64 |
有符号64位整数(默认整数类型) | 8 | |
布尔类型 | torch.bool |
布尔值(True/False) | 1 |
复数类型 | torch.complex64 |
复数(实部和虚部为float32) | 8 |
torch.complex128 |
复数(实部和虚部为float64) | 16 |
选择合适数据类型的原则:
- 深度学习模型通常使用
float32
作为默认浮点类型 - 内存有限时可考虑
float16
或bfloat16
(需GPU支持) - 整数类型用于表示索引或分类标签(如
torch.long
) - 布尔类型用于掩码操作(如
torch.bool
)
二、张量的创建方法详解
2.1 使用torch.tensor()
创建张量
标准型:
torch.tensor(data, dtype=None, device=None, requires_grad=False, pin_memory=False)
参数详解:
data
:必需参数,表示输入数据(可以是列表、元组、NumPy数组等)dtype
:可选参数,指定张量的数据类型(如torch.float32
)device
:可选参数,指定张量存储的设备(如"cuda:0"
)requires_grad
:可选参数,是否需要计算梯度(默认为False)pin_memory
:可选参数,是否分配页锁定内存(用于加速GPU数据传输)
代码示例:
import torch
import numpy as np
# 从列表创建张量,指定数据类型和设备
tensor1 = torch.tensor(
[1, 2, 3],
dtype=torch.float32,
device="cuda" if torch.cuda.is_available() else "cpu"
)
print("tensor1:", tensor1)
# 从NumPy数组创建张量,保留梯度
np_array = np.array([[4, 5], [6, 7]])
tensor2 = torch.tensor(np_array, requires_grad=True)
print("\ntensor2:", tensor2)
print("是否需要梯度:", tensor2.requires_grad)
运行效果:
tensor1: tensor([1., 2., 3.], device='cuda:0')
tensor2: tensor([[4, 5],
[6, 7]], dtype=torch.int64, requires_grad=True)
是否需要梯度: True
2.2 使用torch.Tensor()
创建张量(类构造器)
torch.Tensor
是张量类的构造器,与torch.tensor()
有区别:
torch.Tensor()
:是类的构造函数,默认使用torch.float32
数据类型torch.tensor()
:是工厂函数,会根据输入数据自动推断类型
标准型:
torch.Tensor(*size) # 创建指定形状的未初始化张量
torch.Tensor(data) # 从数据创建张量(等价于torch.tensor())
使用场景:
创建未初始化张量(需谨慎使用):
empty_tensor = torch.Tensor(2, 3) # 创建2x3未初始化张量
从已有数据创建张量(与
torch.tensor()
类似):data_tensor = torch.Tensor([1, 2, 3]) # 从列表创建张量
代码示例:
# 使用torch.Tensor()创建张量
tensor1 = torch.Tensor([1, 2, 3]) # 注意:输入为Python列表
print("使用Tensor()创建的张量:", tensor1)
print("数据类型:", tensor1.dtype) # 默认float32
# 创建指定形状的未初始化张量(危险操作)
empty_tensor = torch.Tensor(2, 3) # 创建2x3的未初始化张量
print("\n未初始化的张量:\n", empty_tensor) # 可能包含随机值
运行效果:
使用Tensor()创建的张量: tensor([1., 2., 3.])
数据类型: torch.float32
未初始化的张量:
tensor([[4.5824e-41, 0.0000e+00, 4.5824e-41],
[0.0000e+00, 0.0000e+00, 0.0000e+00]])
核心讲解:
- torch.Tensor()默认使用float32,即使输入是整数列表
- 当传入多个整数参数(如torch.Tensor(2,3))时,会创建指定形状的未初始化张量
- 未初始化张量包含内存中的随机值,直接使用可能导致不可预测的结果
- 推荐使用torch.empty()替代这种危险用法
与torch.tensor()
的关键区别:
torch.Tensor()
默认使用float32
数据类型torch.Tensor(*size)
创建的是未初始化内存,内容是随机的torch.tensor()
总是复制输入数据,而torch.Tensor(data)
可能共享内存(取决于实现)
安全替代方案:
- 用
torch.empty(shape)
替代torch.Tensor(shape)
创建未初始化张量 - 用
torch.tensor(data)
替代torch.Tensor(data)
从已有数据创建张量
2.3 torch.Tensor()
与torch.tensor()
的区别
特性 | torch.tensor() |
torch.Tensor() |
---|---|---|
函数类型 | 工厂函数(推荐使用) | 类构造器 |
数据处理方式 | 复制输入数据 | 可能创建未初始化的内存空间 |
默认数据类型 | 自动推断(整数默认为int64) | 固定为float32 |
安全风险 | 安全(始终复制数据) | 不安全(可能包含随机值) |
推荐场景 | 从已有数据创建张量 | 创建指定形状的空张量(需后续初始化) |
危险示例:
# 使用torch.Tensor()创建未初始化张量(不建议)
dangerous_tensor = torch.Tensor(2, 2) # 创建2x2未初始化张量
print("未初始化张量内容:\n", dangerous_tensor)
运行效果:
未初始化张量内容:
tensor([[4.5824e-41, 0.0000e+00],
[4.5824e-41, 0.0000e+00]])
安全建议:
1. 避免直接使用torch.Tensor(shape)创建张量
2. 推荐使用torch.empty(shape)创建未初始化张量,或使用torch.zeros/ones等函数
3. 只有在明确需要float32类型且输入为None时,才考虑使用torch.Tensor()
三、张量的常用创建函数详解
3.1 创建特定值的张量
函数名 | 标准型 | 功能描述 |
---|---|---|
torch.zeros() |
torch.zeros(size, dtype=None, layout=torch.strided, device=None, requires_grad=False) |
创建全零张量 |
torch.ones() |
torch.ones(size, dtype=None, layout=torch.strided, device=None, requires_grad=False) |
创建全一张量 |
torch.full() |
torch.full(size, fill_value, dtype=None, layout=torch.strided, device=None, requires_grad=False) |
创建填充特定值的张量 |
torch.eye() |
torch.eye(n, m=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) |
创建单位矩阵(对角线为 1,其余为 0) |
torch.arange() |
torch.arange(start=0, end, step=1, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) |
创建等差数列张量 |
torch.linspace() |
torch.linspace(start, end, steps=100, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) |
创建等比数列张量 |
参数说明:
参数 | 说明 |
---|---|
size | 定义张量形状(维度和各维度大小),如(2,3)或[4,5]。 |
dtype | 指定数据类型(默认自动推断),如torch.float32、torch.int64。 |
layout | 内存布局(默认torch.strided),如torch.strided(密集)、torch.sparse_coo(稀疏)。 |
device | 存储设备,如"cpu"、“cuda:0”(GPU)。 |
requires_grad | 是否追踪梯度(用于自动求导),True/False。 |
fill_value(torch.full()) | 填充的具体值,如5、3.14。 |
n(torch.eye()) | 方阵行数(若m未指定则为n×n),如3(3×3 矩阵)。 |
m(torch.eye()) | 可选列数(默认等于n),如4(n×4矩阵)。 |
start(torch.arange()/torch.linspace()) | 序列起始值,如0、1.5。 |
end(torch.arange()/torch.linspace()) | 序列结束值(arange不含,linspace含),如10、5.0。 |
step(torch.arange()) | 相邻元素差值(步长),如2、0.5(非零)。 |
steps(torch.linspace()) | 元素总数(含start和end),如5(生成 5 个元素)。 |
out | 指定输出张量(复用内存),需与结果形状匹配。 |
代码示例:
# torch.zeros()标准型
torch.zeros(size, dtype=None, device=None, requires_grad=False)
# 示例:创建3x4的全零浮点张量
zeros_tensor = torch.zeros((3, 4), dtype=torch.float32)
print("zeros_tensor:\n", zeros_tensor)
# torch.arange()标准型
torch.arange(start=0, end, step=1, dtype=None)
# 示例:创建从0到9的整数张量
arange_tensor = torch.arange(0, 10)
print("\narange_tensor:", arange_tensor)
运行效果:
zeros_tensor:
tensor([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
arange_tensor: tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
3.2 创建随机分布张量
函数名 | 标准型 | 分布类型 | 部分参数说明 |
---|---|---|---|
torch.rand() |
torch.rand(size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) |
均匀分布 [0,1) | size(形状元组) |
torch.randn() |
torch.randn(size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) |
标准正态分布 N (0,1) | size,dtype,device |
torch.randint() |
torch.randint(low=0, high, size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) |
整数均匀分布 | low(下界),high(上界),size(形状),dtype |
torch.normal() |
torch.normal(mean, std, size=None, out=None) |
自定义正态分布 | mean(均值),std(标准差),size(可选,若提供则覆盖 mean/std 形状) |
torch.bernoulli() |
torch.bernoulli(input, generator=None, out=None) |
伯努利分布 | input(概率值张量),generator(随机数生成器) |
代码示例:
# 创建2x3的均匀分布随机张量
uniform_tensor = torch.rand(2, 3)
print("均匀分布随机张量:\n", uniform_tensor)
# 创建均值为2,标准差为0.5的正态分布随机张量
normal_tensor = torch.normal(mean=2.0, std=0.5, size=(2, 2))
print("\n正态分布随机张量:\n", normal_tensor)
# 创建伯努利分布随机张量(二值0/1)
prob_tensor = torch.tensor([0.1, 0.9, 0.5])
bernoulli_tensor = torch.bernoulli(prob_tensor)
print("\n伯努利分布随机张量:", bernoulli_tensor)
运行效果:
均匀分布随机张量:
tensor([[0.7231, 0.3456, 0.6829],
[0.0478, 0.8537, 0.2749]])
正态分布随机张量:
tensor([[2.3425, 1.9127],
[2.0578, 2.3250]])
伯努利分布随机张量: tensor([0., 1., 1.])
四、张量的核心操作详解
4.1 形状操作:reshape、view、squeeze与unsqueeze
函数名 | 标准型 | 功能描述 |
---|---|---|
reshape() |
torch.reshape(input, shape) 或 tensor.reshape(shape) |
改变张量形状,允许非连续内存 |
view() |
tensor.view(*shape) |
改变张量形状,要求内存连续 |
squeeze() |
torch.squeeze(input, dim=None, out=None) 或 tensor.squeeze(dim=None) |
移除所有维度为 1 的维度(如 [1,3,1] 变为 [3]) |
unsqueeze() |
torch.unsqueeze(input, dim) 或 tensor.unsqueeze(dim) |
在指定位置插入维度为 1 的维度(如 [3] 变为 [1,3,1]) |
transpose() |
torch.transpose(input, dim0, dim1) 或 tensor.transpose(dim0, dim1) |
交换两个维度的位置 |
permute() |
tensor.permute(*dims) |
重新排列所有维度的顺序 |
参数说明:
参数 | 说明 |
---|---|
input(torch.reshape()、torch.squeeze()、torch.unsqueeze()、torch.transpose()) | 输入张量(需处理的原始张量),任意维度。 |
shape(torch.reshape()、tensor.reshape()) | 目标形状(元素总数与原张量相同),如(3,4)、-1(自动计算维度)。 |
*shape(tensor.view()) | 目标形状的可变参数(同shape,写法不同),如3,4(3×4 形状)。 |
dim(torch.squeeze()torch.unsqueeze()torch.transpose()) | 操作的维度索引(squeeze移除、unsqueeze插入、transpose交换),如0、1(从 0 开始)。 |
dim0(torch.transpose()) | 需交换的第一个维度,非负整数(小于张量维度数)。 |
dim1(torch.transpose()) | 需交换的第二个维度,非负整数(小于维度数且≠dim0)。 |
*dims(tensor.permute()) | 维度重排顺序(新维度顺序),如2,0,1(原维度 0→1、1→2、2→0)。 |
out | 指定输出张量(复用内存),需与目标形状匹配。 |
关键区别:
reshape()
:更灵活,会在需要时复制数据以确保连续性view()
:更高效,直接使用原内存,但要求内存连续- 如果不确定内存是否连续,优先使用
reshape()
代码示例:
# 创建基础张量
x = torch.arange(12)
print("原始张量:", x)
print("形状:", x.shape) # torch.Size([12])
# 使用reshape()
reshaped = x.reshape(3, 4)
print("\nreshape后的张量:\n", reshaped)
print("形状:", reshaped.shape) # torch.Size([3, 4])
# 使用view()
viewed = x.view(2, 6)
print("\nview后的张量:\n", viewed)
print("形状:", viewed.shape) # torch.Size([2, 6])
# 使用transpose()交换维度
transposed = reshaped.transpose(0, 1) # 交换行和列
print("\ntranspose后的张量:\n", transposed)
print("形状:", transposed.shape) # torch.Size([4, 3])
# 使用permute()重新排列维度
permuted = reshaped.permute(1, 0) # 等价于transpose(0,1)
print("\npermute后的张量:\n", permuted)
print("形状:", permuted.shape) # torch.Size([4, 3])
# 使用squeeze()和unsqueeze()
unsqueezed = x.unsqueeze(0) # 在第0维插入维度
print("\nunsqueeze后的形状:", unsqueezed.shape) # torch.Size([1, 12])
squeezed = unsqueezed.squeeze(0) # 移除第0维
print("squeeze后的形状:", squeezed.shape) # torch.Size([12])
运行效果:
原始张量: tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
形状: torch.Size([12])
reshape后的张量:
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
形状: torch.Size([3, 4])
view后的张量:
tensor([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11]])
形状: torch.Size([2, 6])
transpose后的张量:
tensor([[ 0, 4, 8],
[ 1, 5, 9],
[ 2, 6, 10],
[ 3, 7, 11]])
形状: torch.Size([4, 3])
permute后的张量:
tensor([[ 0, 4, 8],
[ 1, 5, 9],
[ 2, 6, 10],
[ 3, 7, 11]])
形状: torch.Size([4, 3])
unsqueeze后的形状: torch.Size([1, 12])
squeeze后的形状: torch.Size([12])
运行效果说明:
原始张量创建:
torch.arange(12)
生成包含0到11的1维张量,共12个元素,形状为(12)
。这是后续形状操作的基础,所有操作都基于这12个元素的重新排列。reshape操作:
x.reshape(3, 4)
将1维张量重构为3行4列的2维张量。原理是保持元素总数不变(3×4=12),通过改变维度组合实现形状转换。reshape支持非连续内存的张量,此处因原始张量连续,直接完成维度重排。view操作:
x.view(2, 6)
将1维张量转为2行6列的2维张量(2×6=12)。view要求张量内存连续,由于原始张量是连续的,可直接通过改变视图实现,无需复制数据,效率高于reshape(在连续内存场景下)。transpose交换维度:
reshaped.transpose(0, 1)
交换2维张量的0维和1维(行和列),3行4列变为4行3列。transpose仅能交换两个指定维度,适用于简单维度互换场景。permute重排维度:
reshaped.permute(1, 0)
通过指定新维度顺序(原1维→新0维,原0维→新1维),实现与transpose相同的效果。permute支持任意维度的重排,比transpose更灵活,尤其适合高维张量。unsqueeze与squeeze操作:
x.unsqueeze(0)
在第0维插入一个维度,将1维张量(12)
变为2维张量(1, 12)
;squeezed.squeeze(0)
则移除第0维(因该维度大小为1),恢复为(12)
。两者配合实现维度的动态增减,常用于适配不同操作对张量维度的要求。
4.2 数学运算:逐元素运算与矩阵运算
逐元素运算:
- 加法:
+
或torch.add()
- 减法:
-
或torch.sub()
- 乘法:
*
或torch.mul()
- 除法:
/
或torch.div()
- 指数:
torch.pow()
或**
- 对数:
torch.log()
、torch.log2()
、torch.log10()
矩阵运算:
- 矩阵乘法:
torch.matmul()
或@
- 点积(向量内积):
torch.dot()
- 矩阵转置:
torch.t()
或tensor.T
- 矩阵求逆:
torch.inverse()
- 矩阵行列式:
torch.det()
代码示例:
a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[5, 6], [7, 8]])
# 逐元素乘法
elementwise_mul = a * b
print("逐元素乘法:\n", elementwise_mul)
# 矩阵乘法
matrix_mul = torch.matmul(a, b) # 等价于 a @ b
print("\n矩阵乘法:\n", matrix_mul)
# 广播机制示例
c = torch.tensor([10, 20])
broadcast_result = a + c # c自动扩展为[[10,20],[10,20]]
print("\n广播加法:\n", broadcast_result)
# 复杂运算示例
d = torch.tensor([1.0, 2.0, 3.0])
exp_result = torch.exp(d) # 计算e的幂
sqrt_result = torch.sqrt(d) # 计算平方根
print("\n指数运算:", exp_result)
print("平方根运算:", sqrt_result)
运行效果:
逐元素乘法:
tensor([[ 5, 12],
[21, 32]])
矩阵乘法:
tensor([[19, 22],
[43, 50]])
广播加法:
tensor([[11, 22],
[13, 24]])
指数运算: tensor([ 2.7183, 7.3891, 20.0855])
平方根运算: tensor([1.0000, 1.4142, 1.7321])
广播机制规则:
1. 从右向左比较两个张量的维度
2. 如果维度值相等或其中一个为1,则可以广播
3. 广播时会自动扩展维度为1的张量
4. 示例:
- [3,1] 与 [3,3] 可以广播(右维度1 vs 3,左维度3 vs 3)
- [1,4] 与 [3,4] 可以广播(右维度4 vs 4,左维度1 vs 3)
- [2,3] 与 [3,2] 不可广播(右维度3 vs 2不匹配)
五、张量与NumPy的交互详解
5.1 内存共享机制
PyTorch张量与NumPy数组之间的转换有两种模式:
- 内存共享模式:使用
torch.from_numpy()
和tensor.numpy()
,修改一方会影响另一方 - 内存复制模式:使用
torch.tensor()
和tensor.clone().numpy()
,修改互不影响
代码示例:
import numpy as np
import torch
# 创建NumPy数组
np_array = np.array([1, 2, 3])
# 内存共享方式转换为张量
shared_tensor = torch.from_numpy(np_array)
# 内存复制方式转换为张量
copied_tensor = torch.tensor(np_array)
# 修改NumPy数组
np_array[0] = 100
print("共享内存的张量:", shared_tensor) # 输出: tensor([100, 2, 3])
print("复制内存的张量:", copied_tensor) # 输出: tensor([1, 2, 3])
# 修改共享内存的张量
shared_tensor[1] = 200
print("修改后的NumPy数组:", np_array) # 输出: [100 200 3]
5.2 数据类型转换规则
NumPy数据类型 | 自动转换为PyTorch数据类型 |
---|---|
np.float32 |
torch.float32 |
np.float64 |
torch.float64 |
np.int32 |
torch.int32 |
np.int64 |
torch.int64 |
np.bool_ |
torch.bool |
注意事项:
- NumPy默认浮点类型是
float64
,而PyTorch是float32
- 转换时应显式指定数据类型,避免意外的精度损失
- 对于GPU张量,需先调用
.cpu()
方法再转换为NumPy数组
六、设备迁移与性能优化
6.1 设备管理API
函数/方法 | 功能描述 |
---|---|
torch.cuda.is_available() |
检查CUDA是否可用 |
torch.device() |
创建设备对象(如torch.device("cuda:0") ) |
tensor.to(device) |
将张量迁移到指定设备 |
tensor.cuda() |
将张量迁移到GPU(等价于.to("cuda") ) |
tensor.cpu() |
将张量迁移到CPU(等价于.to("cpu") ) |
torch.cuda.device_count() |
获取可用GPU数量 |
代码示例:
# 检查CUDA可用性
print("CUDA可用:", torch.cuda.is_available())
# 创建CPU和GPU张量
cpu_tensor = torch.tensor([1, 2, 3])
if torch.cuda.is_available():
gpu_tensor = cpu_tensor.to("cuda")
print("GPU张量设备:", gpu_tensor.device)
# 在GPU上执行计算
result = gpu_tensor * 2
# 将结果移回CPU并转换为NumPy
numpy_result = result.cpu().numpy()
print("NumPy结果:", numpy_result)
else:
print("CUDA不可用,使用CPU计算")
6.2 性能优化技巧
- 批量操作:利用GPU并行计算能力,优先使用批量操作(如矩阵乘法)
- 内存预分配:避免在训练循环中频繁创建新张量,尽量复用内存
- 减少设备间传输:最小化CPU与GPU之间的数据传输次数
- 混合精度训练:使用
torch.cuda.amp
模块实现混合精度训练(float16+float32) - 使用in-place操作:如
x.add_(1)
替代x = x + 1
(注意:可能影响梯度计算)
七、自动求导机制
7.1 计算图与反向传播
PyTorch的自动求导基于动态计算图(Dynamic Computational Graph):
- 前向传播:构建计算图,记录所有操作
- 反向传播:根据计算图反向计算梯度
- 梯度累积:梯度存储在
.grad
属性中,多次反向传播会累积梯度
关键API:
requires_grad=True
:开启张量的梯度追踪backward()
:执行反向传播grad
:访问计算得到的梯度detach()
:从计算图中分离张量,停止梯度追踪with torch.no_grad()
:上下文管理器,临时关闭梯度计算(用于推理)
代码示例:
# 创建需要求导的张量
x = torch.tensor([2.0], requires_grad=True)
print("x:", x)
# 定义计算过程:y = x² + 3x + 1
y = x**2 + 3*x + 1
print("y:", y) # y会记录计算图信息
# 执行反向传播(计算dy/dx)
y.backward()
# 查看梯度(dy/dx = 2x + 3 = 2*2 + 3 = 7)
print("x的梯度:", x.grad)
# 复杂计算图示例
a = torch.tensor([3.0], requires_grad=True)
b = torch.tensor([4.0], requires_grad=True)
c = a * b # c = a*b
d = 2 * c # d = 2*c
d.backward() # 计算d关于a和b的梯度
print("\na的梯度:", a.grad) # dd/da = 2*b = 2*4 = 8
print("b的梯度:", b.grad) # dd/db = 2*a = 2*3 = 6
7.2 梯度计算注意事项
梯度累积:
- 默认情况下,多次调用
backward()
会累积梯度 - 通常在每个优化步骤后需要调用
optimizer.zero_grad()
清除梯度
- 默认情况下,多次调用
非标量输出的backward():
- 当输出是标量时,
backward()
无需参数 - 当输出是张量时,需要传入与输出形状相同的
gradient
参数
x = torch.tensor([1.0, 2.0], requires_grad=True) y = x * 2 y.backward(torch.tensor([1.0, 1.0])) # 传入梯度权重
- 当输出是标量时,
停止梯度追踪:
- 使用
tensor.detach()
创建不追踪梯度的副本 - 使用
with torch.no_grad()
上下文管理器临时关闭梯度计算
- 使用
requires_grad=True)
c = a * b # c = ab
d = 2 * c # d = 2c
d.backward() # 计算d关于a和b的梯度
print(“\na的梯度:”, a.grad) # dd/da = 2b = 24 = 8
print(“b的梯度:”, b.grad) # dd/db = 2a = 23 = 6
### 7.2 梯度计算注意事项
1. **梯度累积**:
- 默认情况下,多次调用`backward()`会累积梯度
- 通常在每个优化步骤后需要调用`optimizer.zero_grad()`清除梯度
2. **非标量输出的backward()**:
- 当输出是标量时,`backward()`无需参数
- 当输出是张量时,需要传入与输出形状相同的`gradient`参数
```python
x = torch.tensor([1.0, 2.0], requires_grad=True)
y = x * 2
y.backward(torch.tensor([1.0, 1.0])) # 传入梯度权重
- 停止梯度追踪:
- 使用
tensor.detach()
创建不追踪梯度的副本 - 使用
with torch.no_grad()
上下文管理器临时关闭梯度计算
- 使用