PyTorch基础——张量计算

文章目录

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

代码示例

python 复制代码
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),原张量的数据保持不变。

代码示例

python 复制代码
import torch

a = 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 中标记原地操作的约定。

代码示例

python 复制代码
import torch

a = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])

# 使用 a.add_(b)
a.add_(b)  # 直接修改原张量 a

print("修改后的张量 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]]

代码示例

python 复制代码
# 减法运算
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),原张量的数据保持不变。

代码示例

python 复制代码
import torch

a = 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 中标记原地操作的约定。

代码示例

python 复制代码
import torch

a = torch.tensor([4, 5, 6])
b = torch.tensor([1, 2, 3])

# 使用 a.sub_(b)
a.sub_(b)  # 直接修改原张量 a

print("修改后的张量 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]]

代码示例

python 复制代码
# 乘法运算(元素级)
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]]

代码示例

python 复制代码
# 除法运算
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]]

代码示例

python 复制代码
# 创建两个矩阵
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() 会将最后两个维度视为矩阵维度进行运算:

python 复制代码
# 创建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]]

代码示例

python 复制代码
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且不相等,则无法广播,会抛出错误

代码示例

python 复制代码
# 示例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]

代码示例

python 复制代码
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

代码示例

python 复制代码
# 计算均值
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),包含最大值/最小值及其索引

代码示例

python 复制代码
# 最大值运算
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)

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

代码示例

python 复制代码
# 累积和
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的加减法操作,不作展开讲解。

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

代码示例

python 复制代码
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的加减法操作,不作展开讲解。

代码示例:

python 复制代码
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的加减法操作,不作展开讲解。

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

代码示例

python 复制代码
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)

代码示例

python 复制代码
import numpy as np

c = 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 自动求导示例

python 复制代码
# 创建需要计算梯度的张量
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是否需要计算梯度: True

y = 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 多变量函数的求导

python 复制代码
# 创建两个需要计算梯度的张量
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

代码示例

python 复制代码
# 检查是否有可用的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

代码示例

python 复制代码
# 检查是否有可用的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 之间迁移。所有计算会在张量所在的设备上进行,因此对于需要频繁操作的张量,最好将它们放在同一个设备上,避免频繁的设备间数据传输。

相关推荐
风象南7 分钟前
Claude Code这个隐藏技能,让我告别PPT焦虑
人工智能·后端
曲幽30 分钟前
FastAPI压力测试实战:Locust模拟真实用户并发及优化建议
python·fastapi·web·locust·asyncio·test·uvicorn·workers
Mintopia1 小时前
OpenClaw 对软件行业产生的影响
人工智能
陈广亮1 小时前
构建具有长期记忆的 AI Agent:从设计模式到生产实践
人工智能
会写代码的柯基犬2 小时前
DeepSeek vs Kimi vs Qwen —— AI 生成俄罗斯方块代码效果横评
人工智能·llm
Mintopia2 小时前
OpenClaw 是什么?为什么节后热度如此之高?
人工智能
爱可生开源社区2 小时前
DBA 的未来?八位行业先锋的年度圆桌讨论
人工智能·dba
叁两5 小时前
用opencode打造全自动公众号写作流水线,AI 代笔太香了!
前端·人工智能·agent
敏编程5 小时前
一天一个Python库:jsonschema - JSON 数据验证利器
python