文章目录

  • PyTorch基础——张量计算
    • 1 什么是张量计算?
    • 2 基本算术运算
      • 2.1 加法运算
        • 2.1.2 `torch.add`
        • 2.1.3 `a.add(b) 与 a.add_(b)`
          • `a.add(b)` 方法
          • `a.add_(b)` 方法
          • 核心区别
      • 2.2 减法运算
        • 2.2.1 `toch.sub()`
        • 2.2.2 `a.sub(b) `和`a.sub_(b)`
          • `a.sub(b)` 方法
          • `a.sub_(b)` 方法
          • 核心区别
          • 使用建议
      • 2.3 乘法运算
      • 2.4 除法运算
    • 3 矩阵运算
      • 3.1 矩阵乘法
      • 3.2 高维张量的矩阵乘法
      • 3.3 矩阵转置
    • 4 广播机制(Broadcasting)
      • 4.1 广播的基本规则
    • 5 统计运算
      • 5.1 求和运算
      • 5.2 均值运算
      • 5.3 最大值和最小值
      • 5.4 累加运算
    • 6 张量的其他常用运算
      • 6.1 幂运算
        • 6.1.1 通用计算
        • 6.1.2 底数为e的幂运算
      • 6.2 平方根
      • 6.3 指数和对数运算
    • 7 自动求导(Autograd)与张量计算
      • 7.1 基本概念
      • 7.2 自动求导示例
      • 7.3 多变量函数的求导
    • 8 GPU 加速的张量计算
      • 8.1 张量的设备迁移
      • 8.1 张量的设备迁移

PyTorch基础——张量计算

张量是PyTorch中所有操作的基础,类似于多维数组,支持GPU加速和自动求导等高级功能。本篇
博客将专门从基础运算开始,聚焦于张是的计算部分

1 什么是张量计算?

张量计算指的是对张量进行的各种数学操作,包括基本算术运算、矩阵运算、统计运算等。这些操作是构建神经网络和实现机器学习算法的基础。与普通的 Python 数值计算不同,PyTorch 的张量计算可以自动并行化并利用 GPU 加速,大幅提高计算效率。

2 基本算术运算

PyTorch 提供了丰富的算术运算函数,既可以通过运算符直接操作,也可以通过 torch 模块中的函数进行操作。这些运算均为元素级操作(element-wise operation),即对两个张量对应位置的元素分别进行计算。

2.1 加法运算

2.1.2 torch.add

函数形式torch.add(input, other, out=None)

  • 参数解析
    • input:第一个输入张量
    • other:第二个输入张量(或一个标量)
    • out:可选参数,用于指定输出张量

计算原理
加法运算对两个张量的对应元素进行求和。

  • 若为两个张量相加:result[i][j] = input[i][j] + other[i][j]
  • 若为张量与标量相加:result[i][j] = input[i][j] + scalar

手算示例

张量 a: [[1, 2],[3, 4]]
张量 b: [[5, 6],[7, 8]]
a + b 的结果:
[[1+5, 2+6],[3+7, 4+8]] = [[6, 8], [10, 12]]

代码示例

import torch# 创建两个张量
a = torch.tensor([1, 2, 3], dtype=torch.float32)
b = torch.tensor([4, 5, 6], dtype=torch.float32)# 方法1:使用运算符
c = a + b
print("a + b =",c)# 方法2:使用torch.add()函数
print("torch.add(a, b) =", torch.add(a, b))# 与标量相加
print("a + 10 =", a + 10)
print("torch.add(a, 10) =", torch.add(a, 10))

运行结果

a + b = tensor([5., 7., 9.])
torch.add(a, b) = tensor([5., 7., 9.])
a + 10 = tensor([11., 12., 13.])
torch.add(a, 10) = tensor([11., 12., 13.])

结果分析:加法运算会对张量的每个元素执行相应操作,当与标量相加时,标量会自动广播(broadcast)到与张量相同的形状。

2.1.3 a.add(b) 与 a.add_(b)

在 PyTorch 中,a.add(b)a.add_(b) 都是用于实现张量加法的方法,但它们的核心区别在于是否修改原张量。这是 PyTorch 中非常重要的一个设计理念,理解这个区别有助于避免代码中出现意外的数据修改。

a.add(b) 方法
  • 功能:计算 a + b 的结果,但不会修改原张量 a,而是返回一个新的张量来存储计算结果。
  • 特点:属于「非原地操作」(non-inplace operation),原张量的数据保持不变。

代码示例

import torcha = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])# 使用 a.add(b)
result = a.add(b)print("原张量 a:", a)    # 原张量 a 未被修改
print("计算结果 result:", result)

运行结果

原张量 a: tensor([1, 2, 3])
计算结果 result: tensor([5, 6, 9])
a.add_(b) 方法
  • 功能:同样计算 a + b 的结果,但会直接修改原张量 a,将结果存储在 a 中,不会创建新张量。
  • 特点:属于「原地操作」(inplace operation),方法名末尾的下划线 _ 是 PyTorch 中标记原地操作的约定。

代码示例

import torcha = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])# 使用 a.add_(b)
a.add_(b)  # 直接修改原张量 aprint("修改后的张量 a:", a)  # 原张量 a 已被更新

运行结果

修改后的张量 a: tensor([5, 6, 9])
核心区别
方法操作类型对原张量 a 的影响返回值
a.add(b)非原地操作不修改,保持原值新张量(存储 a + b 的结果)
a.add_(b)原地操作直接修改 a,使其等于 a + b修改后的 a(与原张量是同一个对象)

区分:

  1. 内存效率:原地操作(add_)不需要创建新张量,节省内存,适合处理大规模数据。
  2. 计算图影响:在自动求导(Autograd)中,原地操作可能会破坏计算图的完整性,导致梯度计算错误,因此需谨慎使用。
  3. 代码可读性:下划线 _ 明确标记了原地操作,让其他开发者能快速识别代码中存在数据修改的地方。

实际开发中,建议优先使用非原地操作(如 a.add(b)),除非明确需要优化内存使用,再考虑原地操作(如 a.add_(b))。

2.2 减法运算

2.2.1 toch.sub()

函数形式torch.sub(input, other, out=None)

  • 参数解析:与 torch.add() 相同,实现 input - other 的运算

计算原理
减法运算对两个张量的对应元素进行相减。

  • 若为两个张量相减:result[i][j] = input[i][j] - other[i][j]
  • 若为张量与标量相减:result[i][j] = input[i][j] - scalar

手算示例

张量 a: [[1, 2],[3, 4]]
张量 b: [[5, 6],[7, 8]]
a - b 的结果:
[[1-5, 2-6],[3-7, 4-8]] = [[-4, -4], [-4, -4]]

代码示例

# 减法运算
print("a - b =", a - b)
print("torch.sub(a, b) =", torch.sub(a, b))
print("a - 2 =", a - 2)

运行结果

a - b = tensor([-3., -3., -3.])
torch.sub(a, b) = tensor([-3., -3., -3.])
a - 2 = tensor([-1.,  0.,  1.])
2.2.2 a.sub(b) a.sub_(b)

在 PyTorch 中,a.sub(b)a.sub_(b) 都是用于实现张量减法的方法,它们的核心区别与加法操作类似,主要体现在是否修改原张量上。

a.sub(b) 方法
  • 功能:计算 a - b 的结果,但不会修改原张量 a,而是返回一个新的张量来存储计算结果。
  • 特点:属于「非原地操作」(non-inplace operation),原张量的数据保持不变。

代码示例

import torcha = torch.tensor([4, 5, 6])
b = torch.tensor([1, 2, 3])# 使用 a.sub(b)
result = a.sub(b)print("原张量 a:", a)    # 原张量 a 未被修改
print("计算结果 result:", result)

运行结果

原张量 a: tensor([4, 5, 6])
计算结果 result: tensor([3, 3, 3])
a.sub_(b) 方法
  • 功能:同样计算 a - b 的结果,但会直接修改原张量 a,将结果存储在 a 中,不会创建新张量。
  • 特点:属于「原地操作」(inplace operation),方法名末尾的下划线 _ 是 PyTorch 中标记原地操作的约定。

代码示例

import torcha = torch.tensor([4, 5, 6])
b = torch.tensor([1, 2, 3])# 使用 a.sub_(b)
a.sub_(b)  # 直接修改原张量 aprint("修改后的张量 a:", a)  # 原张量 a 已被更新

运行结果

修改后的张量 a: tensor([3, 3, 3])
核心区别
方法操作类型对原张量 a 的影响返回值
a.sub(b)非原地操作不修改,保持原值新张量(存储 a - b 的结果)
a.sub_(b)原地操作直接修改 a,使其等于 a - b修改后的 a(与原张量是同一个对象)
使用建议
  • 非原地操作(a.sub(b))不会改变原始数据,适合需要保留原始张量的场景,且在自动求导中更安全。
  • 原地操作(a.sub_(b))节省内存空间,但会修改原始数据,在使用时需注意后续数据被覆盖的风险,尤其在构建计算图时需谨慎使用。

2.3 乘法运算

函数形式torch.mul(input, other, out=None) 哈达玛积,非矩阵乘法

a.mul(b)a.mul_(b)同2.1-2.2的加减法操作,不作展开讲解。

  • 参数解析:与加法类似,实现元素级乘法(不是矩阵乘法)

计算原理
乘法运算对两个张量的对应元素进行相乘(元素级乘法,element-wise multiplication)。

  • 若为两个张量相乘:result[i][j] = input[i][j] * other[i][j]
  • 若为张量与标量相乘:result[i][j] = input[i][j] * scalar

手算示例

张量 a: [[1, 2],[3, 4]]
张量 b: [[5, 6],[7, 8]]
a * b 的结果:
[[1×5, 2×6],[3×7, 4×8]] = [[5, 12], [21, 32]]

代码示例

# 乘法运算(元素级)
print("a * b =", a * b)
print("torch.mul(a, b) =", torch.mul(a, b))
print("a * 3 =", a * 3)

运行结果

a * b = tensor([ 4., 10., 18.])
torch.mul(a, b) = tensor([ 4., 10., 18.])
a * 3 = tensor([3., 6., 9.])

结果分析:这里的乘法是哈达玛积元素级乘法(element-wise multiplication),即两个张量对应位置的元素相乘,而不是线性代数中的矩阵乘法。

2.4 除法运算

函数形式torch.div(input, other, out=None)

a.div(b)a.div_(b)同2.1-2.2的加减法操作,不作展开讲解。

  • 参数解析:实现 input / other 的元素级除法运算

计算原理
除法运算对两个张量的对应元素进行相除。

  • 若为两个张量相除:result[i][j] = input[i][j] / other[i][j]
  • 若为张量与标量相除:result[i][j] = input[i][j] / scalar

手算示例

张量 a: [[1, 2],[3, 4]]
张量 b: [[5, 6],[7, 8]]
a / b 的结果:
[[1/5, 2/6],[3/7, 4/8]] = [[0.2, 0.333...], [0.428..., 0.5]]

代码示例

# 除法运算
print("a / b =", a / b)
print("torch.div(a, b) =", torch.div(a, b))
print("b / 2 =", b / 2)

运行结果

a / b = tensor([0.2500, 0.4000, 0.5000])
torch.div(a, b) = tensor([0.2500, 0.4000, 0.5000])
b / 2 = tensor([2., 2.5, 3.])

3 矩阵运算

矩阵运算在深度学习中应用广泛,尤其是在全连接层和卷积层中。PyTorch 提供了多种矩阵运算函数。

3.1 矩阵乘法

二维矩阵乘法运算操作包括:torch.mm()torch.matmul()@,不再有上面说到的类似a.add_()的方法

函数形式torch.matmul(input, other, out=None)

  • 参数解析
    • input:第一个输入张量(可以是1D或更高维)
    • other:第二个输入张量
    • 对于2D张量,执行常规的矩阵乘法
    • 对于1D张量,执行点积运算

计算原理
矩阵乘法遵循线性代数中的矩阵乘法规则。对于形状为 (m, n) 的矩阵 A 和形状为 (n, p) 的矩阵 B,结果矩阵 C 的形状为 (m, p),其中每个元素 C[i][j]A 的第 i 行与 B 的第 j 列的点积:

C[i][j] = A[i][0]×B[0][j] + A[i][1]×B[1][j] + ... + A[i][n-1]×B[n-1][j]

手算示例

矩阵 A: [[1, 2],[3, 4]]
矩阵 B: [[5, 6],[7, 8]]
A × B 的结果:
[[1×5 + 2×7, 1×6 + 2×8],[3×5 + 4×7, 3×6 + 4×8]
] = [[19, 22], [43, 50]]

代码示例

# 创建两个矩阵
mat1 = torch.tensor([[1, 2], [3, 4]])
mat2 = torch.tensor([[5, 6], [7, 8]])print("矩阵1:\n", mat1)
print("矩阵2:\n", mat2)# 方法1: 使用torch.matmul()
product1 = torch.matmul(mat1, mat2)
print("\n使用torch.matmul()的结果:\n", product1)# 方法2: 使用@运算符
product2 = mat1 @ mat2
print("\n使用@运算符的结果:\n", product2)# 方法3: 使用mm()方法(仅适用于2D张量)
product3 = mat1.mm(mat2)
print("\n使用mm()方法的结果:\n", product3)# 1D张量的点积
vec1 = torch.tensor([1, 2, 3])
vec2 = torch.tensor([4, 5, 6])
print("\n向量点积:", torch.matmul(vec1, vec2))

运行结果

矩阵1:tensor([[1, 2],[3, 4]])
矩阵2:tensor([[5, 6],[7, 8]])使用torch.matmul()的结果:tensor([[19, 22],[43, 50]])使用@运算符的结果:tensor([[19, 22],[43, 50]])使用mm()方法的结果:tensor([[19, 22],[43, 50]])向量点积: tensor(32)

结果分析:矩阵乘法遵循线性代数规则,对于矩阵 mat1(形状为 2×2)和 mat2(形状为 2×2),结果是一个 2×2 的矩阵,其中每个元素 (i,j)mat1 的第 i 行与 mat2 的第 j 列的点积。

3.2 高维张量的矩阵乘法

**对于高维(Tensor(dim>2))矩阵乘法运算:**定义其矩阵乘法仅在最后的两个维度上,要求前面的维度必须保持一致,就像矩阵的索引一样并且运算操只有torch.matmul()

对于高维张量(维度 > 2),torch.matmul() 会将最后两个维度视为矩阵维度进行运算:

# 创建3D张量(可以理解为2个2×3的矩阵)
tensor3d = torch.tensor([[[1, 2, 3], [4, 5, 6]],[[7, 8, 9], [10, 11, 12]]
])# 创建另一个3D张量(2个3×2的矩阵)
tensor3d_2 = torch.tensor([[[1, 2], [3, 4], [5, 6]],[[7, 8], [9, 10], [11, 12]]
])print("3D张量1形状:", tensor3d.shape)
print("3D张量2形状:", tensor3d_2.shape)# 高维矩阵乘法
result = torch.matmul(tensor3d, tensor3d_2)
print("\n乘法结果形状:", result.shape)
print("乘法结果:\n", result)

运行结果

3D张量1形状: torch.Size([2, 2, 3])
3D张量2形状: torch.Size([2, 3, 2])乘法结果形状: torch.Size([2, 2, 2])
乘法结果:tensor([[[ 22,  28],[ 49,  64]],[[220, 244],[301, 334]]])

结果分析:对于形状为 (2,2,3)(2,3,2) 的两个3D张量,矩阵乘法会对每个对应的2D矩阵(共2对)进行运算,结果形状为 (2,2,2)

3.3 矩阵转置

函数形式torch.t(input)input.t()

  • 功能:返回张量的转置,仅适用于1D或2D张量

计算原理
矩阵转置将原矩阵的行变为列,列变为行。对于形状为 (m, n) 的矩阵,转置后形状变为 (n, m),其中 result[i][j] = input[j][i]

手算示例

原始矩阵: [[1, 2, 3],[4, 5, 6]]
转置后:    [[1, 4],[2, 5],[3, 6]]

代码示例

mat = torch.tensor([[1, 2, 3], [4, 5, 6]])
print("原始矩阵:\n", mat)
print("原始形状:", mat.shape)# 转置操作
transposed = mat.t()
print("\n转置矩阵:\n", transposed)
print("转置形状:", transposed.shape)

运行结果

原始矩阵:tensor([[1, 2, 3],[4, 5, 6]])
原始形状: torch.Size([2, 3])转置矩阵:tensor([[1, 4],[2, 5],[3, 6]])
转置形状: torch.Size([3, 2])

结果分析:矩阵转置将原矩阵的行变为列,列变为行,形状从 (2,3) 变为 (3,2)

4 广播机制(Broadcasting)

广播是 PyTorch 中一种自动扩展张量形状的机制,使得不同形状的张量可以进行算术运算。这是一个非常重要的概念,能简化代码并提高效率。

4.1 广播的基本规则

  1. 如果两个张量的维度数量不同,维度较少的张量会在前面添加新维度(大小为1)
  2. 如果两个张量在某个维度上的大小不同,但其中一个为1,则会将大小为1的维度扩展为另一个张量的大小
  3. 如果两个张量在某个维度上的大小都大于1且不相等,则无法广播,会抛出错误

代码示例

# 示例1:标量与张量的广播
a = torch.tensor([1, 2, 3])
b = 2
print("a * b =", a * b)# 示例2:不同形状张量的广播
c = torch.tensor([[1], [2], [3]])  # 形状 (3,1)
d = torch.tensor([4, 5, 6])       # 形状 (3,)
print("\nc的形状:", c.shape)
print("d的形状:", d.shape)
print("c + d的结果:\n", c + d)
print("c + d的形状:", (c + d).shape)# 示例3:更复杂的广播
e = torch.ones((2, 3))  # 形状 (2,3)
f = torch.tensor([[1], [2]])  # 形状 (2,1)
print("\ne + f的结果:\n", e + f)

运行结果

a * b = tensor([2, 4, 6])c的形状: torch.Size([3, 1])
d的形状: torch.Size([3])
c + d的结果:tensor([[5, 6, 7],[6, 7, 8],[7, 8, 9]])
c + d的形状: torch.Size([3, 3])e + f的结果:tensor([[2., 2., 2.],[3., 3., 3.]])

结果分析:在示例2中,c 形状为 (3,1)d 形状为 (3,),广播后都变为 (3,3) 形状,然后进行元素级加法。广播机制避免了我们手动扩展张量形状,使代码更简洁。

5 统计运算

PyTorch 提供了丰富的统计函数,用于计算张量的均值、总和、最大值、最小值等统计量。

5.1 求和运算

函数形式torch.sum(input, dim=None, keepdim=False, out=None)

  • 参数解析
    • input:输入张量
    • dim:可选参数,指定求和的维度,不指定则对所有元素求和
    • keepdim:布尔值,是否保持原张量的维度,默认为 False

计算原理
求和运算计算张量在指定维度上所有元素的总和。

  • 对整个张量求和:result = sum(input[i][j] for all i,j)
  • 按行求和(dim=1):result[i] = sum(input[i][j] for all j)
  • 按列求和(dim=0):result[j] = sum(input[i][j] for all i)

手算示例

张量: [[1, 2, 3],[4, 5, 6]]
所有元素的和: 1+2+3+4+5+6 = 21
按行求和: [1+2+3, 4+5+6] = [6, 15]
按列求和: [1+4, 2+5, 3+6] = [5, 7, 9]

代码示例

tensor = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
print("张量:\n", tensor)# 对所有元素求和
print("\n所有元素的和:", tensor.sum())# 按行求和(dim=1)
row_sum = tensor.sum(dim=1)
print("按行求和:", row_sum)
print("按行求和的形状:", row_sum.shape)# 按列求和(dim=0)并保持维度
col_sum = tensor.sum(dim=0, keepdim=True)
print("\n按列求和(保持维度):\n", col_sum)
print("形状:", col_sum.shape)

运行结果

张量:tensor([[1., 2., 3.],[4., 5., 6.]])所有元素的和: tensor(21.)
按行求和: tensor([ 6., 15.])
按行求和的形状: torch.Size([2])按列求和(保持维度):tensor([[5., 7., 9.]])
形状: torch.Size([1, 3])

结果分析dim=0 表示沿着第一个维度(行方向)求和,得到每列的总和;dim=1 表示沿着第二个维度(列方向)求和,得到每行的总和。keepdim=True 保持了原有的二维结构。

5.2 均值运算

函数形式torch.mean(input, dim=None, keepdim=False, dtype=None, out=None)

  • 参数解析:与 torch.sum() 类似,计算指定维度的均值

计算原理
均值运算计算张量在指定维度上所有元素的平均值,即总和除以元素个数。

  • 整体均值:result = sum(all elements) / number of elements
  • 按行均值:result[i] = sum(row i) / number of elements in row i

代码示例

# 计算均值
print("所有元素的均值:", tensor.mean())
print("按列求均值:", tensor.mean(dim=0))
print("按行求均值:", tensor.mean(dim=1))

运行结果

所有元素的均值: tensor(3.5000)
按列求均值: tensor([2.5000, 3.5000, 4.5000])
按行求均值: tensor([2., 5.])

5.3 最大值和最小值

函数形式torch.max(input, dim=None, keepdim=False, out=None)torch.min(...)

  • 参数解析
    • 不指定 dim 时,返回张量中的最大值/最小值
    • 指定 dim 时,返回一个元组 (values, indices),包含最大值/最小值及其索引

代码示例

# 最大值运算
print("所有元素的最大值:", tensor.max())# 按行求最大值
row_max = tensor.max(dim=1)
print("\n按行求最大值:")
print("最大值:", row_max.values)
print("最大值索引:", row_max.indices)# 最小值运算
print("\n所有元素的最小值:", tensor.min())
print("按列求最小值:", tensor.min(dim=0).values)

运行结果

所有元素的最大值: tensor(6.)按行求最大值:
最大值: tensor([3., 6.])
最大值索引: tensor([2, 2])所有元素的最小值: tensor(1.)
按列求最小值: tensor([1., 2., 3.])

结果分析torch.max(dim=1) 返回每行的最大值及其在该行中的索引位置,对于第一行 [1., 2., 3.],最大值是 3.,位于索引 2 处。

5.4 累加运算

函数形式torch.cumsum(input, dim, out=None)

  • 功能:计算指定维度上的累积和

代码示例

# 累积和
print("按行累积和:\n", tensor.cumsum(dim=1))

运行结果

按行累积和:tensor([[ 1.,  3.,  6.],[ 4.,  9., 15.]])

结果分析:累积和是指每个位置的值等于该位置之前(包括自身)所有元素的和。例如第一行的计算过程是 1, 1+2=3, 3+3=6

6 张量的其他常用运算

6.1 幂运算

6.1.1 通用计算

函数形式torch.pow(input, exponent, out=None)

a.pow(b)a.pow_(b) 逻辑同2.1-2.2的加减法操作,不作展开讲解。

  • 功能:计算张量的指数幂,支持元素级运算

代码示例

a = torch.tensor([1, 2, 3])# 计算a的平方
print("a的平方:", torch.pow(a, 2))
print("a的平方(使用运算符):", a **2)# 计算a的3次方
print("a的3次方:", torch.pow(a, 3))

运行结果

a的平方: tensor([1, 4, 9])
a的平方(使用运算符): tensor([1, 4, 9])
a的3次方: tensor([ 1,  8, 27])
6.1.2 底数为e的幂运算

a.exp(b)a.exp_(b)逻辑同2.1-2.2的加减法操作,不作展开讲解。

代码示例:

import torch# 定义指数张量 x
x = torch.tensor([0, 1, 2], dtype=torch.float32)# 计算 e^x(元素级)
result = torch.exp(x)  # 等价于 x.exp()
print(result)  # 输出:tensor([1.0000, 2.7183, 7.3891])

6.2 平方根

函数形式torch.sqrt(input, out=None)

a.sqrt_(b)逻辑同2.1-2.2的加减法操作,不作展开讲解。

  • 功能:计算张量每个元素的平方根

代码示例

b = torch.tensor([4.0, 9.0, 16.0])
print("b的平方根:", torch.sqrt(b))

运行结果

b的平方根: tensor([2., 3., 4.])

6.3 指数和对数运算

函数形式torch.exp(input, out=None)torch.log(input, out=None)

  • 功能:分别计算自然指数和自然对数
  • 底数为2: torch.log2(a)
  • 底数为e: torch.log(a)torch.log_(a)
  • 底数为10: torch.log10(a)

代码示例

import numpy as npc = torch.tensor([1.0, 2.0, 3.0])# 指数运算 e^x
print("e^c:", torch.exp(c))# 对数运算 ln(x)
d = torch.tensor([1.0, np.e, np.e**2])
print("ln(d):", torch.log(d))

运行结果

e^c: tensor([ 2.7183,  7.3891, 20.0855])
ln(d): tensor([0.0000, 1.0000, 2.0000])

7 自动求导(Autograd)与张量计算

PyTorch 的自动求导机制是实现神经网络反向传播的核心,它能自动计算张量运算的梯度。

7.1 基本概念

  • 计算图:PyTorch 会记录所有对张量的操作,构建一个计算图
  • 反向传播:通过计算图从输出反向传播到输入,计算梯度
  • requires_grad:张量的一个属性,设为 True 时会追踪该张量的所有操作

7.2 自动求导示例

# 创建需要计算梯度的张量
x = torch.tensor(2.0, requires_grad=True)
print("x =", x)
print("x是否需要计算梯度:", x.requires_grad)# 定义一个函数 y = x^2 + 3x + 1
y = x**2 + 3*x + 1
print("\ny =", y)
print("y的梯度函数:", y.grad_fn)  # 显示y是如何从x计算得到的# 计算y对x的导数
y.backward()# 查看导数结果(dy/dx = 2x + 3)
print("\ndy/dx 在x=2处的值:", x.grad)  # 理论值应为 2*2 + 3 = 7

运行结果

x = tensor(2., requires_grad=True)
x是否需要计算梯度: Truey = tensor(11., grad_fn=<AddBackward0>)
y的梯度函数: <AddBackward0 object at 0x7f8a2c3d3d30>dy/dx 在x=2处的值: tensor(7.)

结果分析:当我们设置 requires_grad=True 时,PyTorch 会追踪该张量的所有操作。调用 y.backward() 会触发反向传播,计算 y 对所有需要梯度的张量(这里是 x)的导数,并将结果存储在张量的 .grad 属性中。

7.3 多变量函数的求导

# 创建两个需要计算梯度的张量
x = torch.tensor(1.0, requires_grad=True)
y = torch.tensor(2.0, requires_grad=True)# 定义函数 z = x^2 + 2xy + y^3
z = x**2 + 2*x*y + y**3
print("z =", z)# 计算偏导数
z.backward()# 查看结果(dz/dx = 2x + 2y, dz/dy = 2x + 3y^2)
print("\ndz/dx 在(1, 2)处的值:", x.grad)  # 理论值: 2*1 + 2*2 = 6
print("dz/dy 在(1, 2)处的值:", y.grad)  # 理论值: 2*1 + 3*2^2 = 14

运行结果

z = tensor(13., grad_fn=<AddBackward0>)dz/dx 在(1, 2)处的值: tensor(6.)
dz/dy 在(1, 2)处的值: tensor(14.)

8 GPU 加速的张量计算

PyTorch 最大的优势之一是能够利用 GPU 进行加速计算,对于大规模张量运算,GPU 可以显著提高计算速度。

8.1 张量的设备迁移

函数形式torch.to(device)tensor.cuda() / tensor.cpu()

  • 功能:将张量从 CPU 迁移到 GPU 或从 GPU 迁移到 CPU

代码示例

# 检查是否有可用的GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("使用的设备:", device)# 创建一个大张量
large_tensor = torch.randn(1000, 1000)
print("原始张量设备:", large_tensor.device)# 将张量迁移到GPU(如果可用)
large_tensor_gpu = large_tensor.to(device)
print("迁移后张量设备:", large_tensor_gpu.device)# 在GPU上进行计算
result_gpu = torch.matmul(large_tensor_gpu, large_tensor_gpu)
print("GPU计算结果设备:", result_gpu.device)# 将结果迁移回CPU
result_cpu = result_gpu.to("cpu")
print("CPU上的结果设备:", result_cpu.device)

运行结果(如果有GPU):

使用的设备: cuda
原始张量设备: cpu
迁移后张量设备: cuda:0
GPU计算结果设备: cuda:0
CPU上的结果设备: cpu

结果分析:通过 to(device) 方法可以将张量在 CPU 和 GPU 之间迁移。所有计算会在张量所在的设备上进行,因此对于需要频繁操作的张量,最好将它们放在同一个设备上,避免频繁的设备间数据传输。

一是能够利用 GPU 进行加速计算,对于大规模张量运算,GPU 可以显著提高计算速度。

8.1 张量的设备迁移

函数形式torch.to(device)tensor.cuda() / tensor.cpu()

  • 功能:将张量从 CPU 迁移到 GPU 或从 GPU 迁移到 CPU

代码示例

# 检查是否有可用的GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("使用的设备:", device)# 创建一个大张量
large_tensor = torch.randn(1000, 1000)
print("原始张量设备:", large_tensor.device)# 将张量迁移到GPU(如果可用)
large_tensor_gpu = large_tensor.to(device)
print("迁移后张量设备:", large_tensor_gpu.device)# 在GPU上进行计算
result_gpu = torch.matmul(large_tensor_gpu, large_tensor_gpu)
print("GPU计算结果设备:", result_gpu.device)# 将结果迁移回CPU
result_cpu = result_gpu.to("cpu")
print("CPU上的结果设备:", result_cpu.device)

运行结果(如果有GPU):

使用的设备: cuda
原始张量设备: cpu
迁移后张量设备: cuda:0
GPU计算结果设备: cuda:0
CPU上的结果设备: cpu

结果分析:通过 to(device) 方法可以将张量在 CPU 和 GPU 之间迁移。所有计算会在张量所在的设备上进行,因此对于需要频繁操作的张量,最好将它们放在同一个设备上,避免频繁的设备间数据传输。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/91614.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/91614.shtml
英文地址,请注明出处:http://en.pswp.cn/web/91614.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云原生联调利器:Telepresence实战

Telepresence在云原生联调中的应用&#xff1a;本地服务直连K8s集群实战在云原生开发中&#xff0c;调试和测试服务常常需要本地环境与远程Kubernetes&#xff08;K8s&#xff09;集群无缝集成。Telepresence是一个开源工具&#xff0c;它允许开发者将本地服务“注入”到K8s集群…

浏览器【详解】requestIdleCallback(浏览器空闲时执行)

简介requestIdleCallback 是浏览器的一个 API&#xff0c;用于在浏览器空闲时间执行低优先级任务&#xff0c;避免阻塞主线程&#xff0c;提升页面性能和响应速度。 当浏览器完成了关键任务&#xff08;如渲染、布局、用户交互处理&#xff09;且暂时没有更高优先级的工作时&am…

STP技术

一、环路的危害1.现象链路指示灯快速闪烁MAC表震荡&#xff1a;交换机频繁修改MAC地址表 → 转发失效。2.环路危害造成的影响链路堵塞主机操作系统响应迟缓二层交换机管理缓慢冲击网关设备的CPU三、STP的作用1.STP基本原理STP即生成树协议&#xff0c;它通过阻断冗余链路来消除…

RAGFLOW~knowledge graph

start 为了增强多跳问答&#xff0c;RAGFlow在数据提取和索引之间增加了一个知识图谱构建步骤&#xff0c;如下面所示。这一步骤会从您指定的分块方法生成的现有块中创建额外的块。 从v0.16.0版本开始&#xff0c;RAGFlow支持在知识库上构建知识图谱&#xff0c;允许你在知识库…

机器学习【二】KNN

KNN算法是一种基于实例的惰性学习算法&#xff0c;其核心思想是通过"多数投票"机制进行分类决策。算法流程包括数据准备&#xff08;需归一化处理&#xff09;、距离计算&#xff08;常用欧氏距离&#xff09;、选择K值&#xff08;通过交叉验证确定&#xff09;和决…

preloader

patch调试串口115200--- a/platform/ac8257/default.makb/platform/ac8257/default.mak-40,7 40,7 CFG_USB_DOWNLOAD :1CFG_FUNCTION_PICACHU_SUPPORT :1CFG_PMT_SUPPORT :0CFG_UART_COMMON :1 -CFG_LOG_BAUDRATE :921600 CFG_LOG_BAUDRATE :115200CFG_EVB_UART_CLOCK :260000…

Linux基础(三)——Bash基础

1、Bash基础1.1 Bash简介从前边操作系统的组成介绍中&#xff0c;我们可以知道操作系统为上层用户提供的与内核进行交互的接口称为shell&#xff0c;其在系统中的位置如下图所示&#xff0c;shell作为内核和用户之间的中介&#xff0c;接收用户发送的指令&#xff0c;将其解析为…

Python 元编程实战:动态属性与数据结构转换技巧

在处理复杂嵌套的 JSON 数据源时&#xff0c;我们常面临访问不便、结构不灵活、字段关联性差等问题。本文将以 O’Reilly 为 OSCON 2014 提供的 JSON 数据源为例&#xff0c;系统讲解如何通过 动态属性转换、对象封装、数据库映射与特性&#xff08;property&#xff09;机制&a…

Android-侧边导航栏的使用

在学习之前&#xff0c;我们先得知道侧边导航栏是什么&#xff1f;它是一个 可以让内容从屏幕边缘滑出的布局容器&#xff0c;由安卓官方提供&#xff0c;用于创建侧边菜单&#xff0c;通常搭配 NavigationView 使用&#xff1b;添加依赖&#xff1a;在app下的build.gradle中添…

lesson30:Python迭代三剑客:可迭代对象、迭代器与生成器深度解析

目录 一、可迭代对象&#xff1a;迭代的起点 可迭代对象的本质特征 可迭代对象的工作原理 自定义可迭代对象 二、迭代器&#xff1a;状态化的迭代工具 迭代器协议与核心方法 迭代器的状态管理 内置迭代器的应用 三、生成器&#xff1a;简洁高效的迭代器 生成器函数&a…

实时语音流分段识别技术解析:基于WebRTC VAD的智能分割策略

引言 在现代语音识别应用中&#xff0c;实时处理音频流是一项关键技术挑战。不同于传统的文件式语音识别&#xff0c;流式处理需要面对音频数据的不确定性、网络延迟以及实时性要求等问题。本文将深入解析一个基于WebRTC VAD&#xff08;Voice Activity Detection&#xff09;…

word中rtf格式介绍

RTF&#xff08;Rich Text Format&#xff0c;富文本格式&#xff09;是一种由微软开发的跨平台文档文件格式&#xff0c;用于在不同应用程序和操作系统之间交换格式化文本。以下是对RTF格式的简要说明&#xff1a; RTF格式特点 跨平台兼容性&#xff1a;RTF文件可以在多种文字…

Springboot 配置 doris 连接

Springboot 配置 doris 连接 一. 使用 druid 连接池 因为 Doris 的前端&#xff08;FE&#xff09;兼容了 MySQL 协议&#xff0c;可以像连 MySQL 一样连 Doris。这是 Doris 的一个核心设计特性&#xff0c;目的是方便接入、简化生态兼容。 首先需要引入 pom 依赖:<dependen…

Linux 系统启动与 GRUB2 核心操作指南

Linux 系统启动与 GRUB2 核心操作指南 Linux 系统的启动过程是一个环环相扣的链条&#xff0c;从硬件自检到用户登录&#xff0c;每一步都依赖关键组件的协作。其中&#xff0c;GRUB2 引导器和systemd 进程是核心枢纽&#xff0c;而运行级别则决定了系统的启动状态。以下是系统…

供应链分销代发源码:一站式打通供应商供货、平台定价、经销商批发及零售环节

在当前复杂的市场环境中&#xff0c;供应链管理成为企业发展的关键。尤其对于电商平台来说&#xff0c;高效、精准的供应链管理不仅能提升运营效率&#xff0c;还能增强市场竞争力。为了应对日益复杂的供应链挑战&#xff0c;核货宝供应链分销代发系统应运而生&#xff0c;旨在…

机器学习、深度学习与数据挖掘:核心技术差异、应用场景与工程实践指南

技术原理与核心概念数据挖掘作为知识发现的关键技术&#xff0c;其核心在于通过算法自动探索数据中的潜在模式。关联规则挖掘可以发现项目之间的有趣关联&#xff0c;如经典的"啤酒与尿布"案例&#xff1b;聚类分析能够将相似对象自动分组&#xff0c;常用于客户细分…

《C++初阶之STL》【stack/queue/priority_queue容器适配器:详解 + 实现】(附加:deque容器介绍)

【stack/queue/priority_queue容器适配器&#xff1a;详解 实现】目录前言&#xff1a;------------标准接口介绍------------一、栈&#xff1a;stack标准模板库中的stack容器适配器是什么样的呢&#xff1f;1. 栈的基本操作std::stack::topstd::stack::pushstd::stack::pop2…

Thymeleaf 模板引擎原理

Thymeleaf 的模板文件&#xff0c;本质上是标准的 HTML 文件&#xff0c;只是“加了标记&#xff08; th&#xff1a;&#xff09;的属性”&#xff0c;让模板引擎在服务端渲染时能 识别并处理 这些属性&#xff0c;从而完成数据&#xff08;model&#xff09; 的填充。<!DO…

5、生产Redis高并发分布式锁实战

一、核心问题与解决方案 问题本质 #mermaid-svg-W1SnVWZe1AotTtDy {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-W1SnVWZe1AotTtDy .error-icon{fill:#552222;}#mermaid-svg-W1SnVWZe1AotTtDy .error-text{fill:#5…

CS231n-2017 Lecture8深度学习框架笔记

深度学习硬件&#xff1a;CPU:CPU有数个核心&#xff0c;每个核心可以独立工作&#xff0c;同时进行多个线程&#xff0c;内存与系统共享GPU&#xff1a;GPU有上千个核心&#xff0c;但每个核心运行速度很慢&#xff0c;适合并行做类似的工作&#xff0c;不能独立工作&#xff…