当前位置: 首页 > article >正文

PyTorch使用-张量数值计算

文章目录

  • 张量数值计算
    • 1. 张量基本运算
    • 1.1. 基本运算函数—非 in-place 操作
    • 1.2. 基本运算函数— in-place 操作
    • 1.3. 关键区别
    • 1.4. In-place 操作注意事项
      • 1.4.1. 梯度跟踪:
      • 1.4.2. 设备一致性:
      • 1.4.3. 广播限制:
    • 1.5. 使用建议
  • 2. 阿达玛积
    • 2.1. 阿达玛积定义
    • 2.2. PyTorch 中的阿达玛积
      • 2.2.1. 实现方式
      • 2.2.2. 广播机制下的阿达玛积
    • 2.3. 应用场景
      • 2.3.1. 注意力机制:
      • 2.3.2. 激活函数:
      • 2.3.3. 图像处理:
    • 2.4. 注意事项
      • 2.4.1. 形状一致性:
      • 2.4.2. 梯度计算:
      • 2.4.3数据类型匹配:
    • 2.5. 对比其他乘积
    • 2.6. 代码示例
  • 3. 点积运算
    • 3.1. 点积运算规则
      • 3.1.1矩阵乘法(点积)要求:
    • 3.2. PyTorch 中的点积运算函数
      • 3.2.1. @ 运算符
      • 3.2.2. torch.mm
      • 3.2.3. torch.bmm
      • 3.2.4. torch.matmul
    • 3.3. 形状匹配规则
    • 3.3.1. 基础规则
    • 3.3.2. 非法形状示例
    • 3.4. 函数对比表
    • 3.5. 高阶示例
      • 3.5.1. 混合维度乘法
      • 3.5.2. 广播机制
    • 3.6. 常见错误及解决
      • 3.6.1. 维度不匹配
      • 3.6.2. 误用 torch.bmm
    • 3.7. 总结
  • 4.指定运算设备
    • 4.1. 检查 GPU 可用性
    • 4.2. 将张量移动到 GPU 的方法
      • 4.2.1. 使用 .cuda() 方法
      • 4.2.2. 直接在 GPU 上创建张量
      • 4.2.3. 使用 .to() 方法
    • 4.3. 关键操作对比
    • 4.4. 注意事项
      • 4.4.1. 设备一致性
      • 4.4.2. 内存管理
      • 4.4.3. 梯度跟踪
    • 4.5. 完整代码示例
    • 4.6. 最佳实践

张量数值计算

PyTorch 是一个深度学习框架,张量是其核心数据结构,用于表示多维数组。张量支持丰富的数学运算,如加法、乘法、矩阵运算等,且能在 CPU 和 GPU 上高效计算。GPU 加速可以大大提高大规模数据处理和深度学习模型训练的速度。

1. 张量基本运算

PyTorch 中张量基本运算包括 add、sub、mul、div、neg 及其带下划线的 in-place 版本。

操作函数In-place 版本用途
加法add()add_()元素级相加
减法sub()sub_()元素级相减
乘法mul()mul_()元素级相乘
除法div()div_()元素级相除
取负neg()neg_()元素级取负数

1.1. 基本运算函数—非 in-place 操作

这些操作会 返回新的张量,原始张量保持不变

import torch

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

# 加法
c_add = torch.add(a, b)    # 或直接使用 c_add = a + b

# 减法
c_sub = torch.sub(a, b)    # 或 c_sub = a - b

# 乘法(元素级)
c_mul = torch.mul(a, b)    # 或 c_mul = a * b

# 除法(元素级)
c_div = torch.div(a, b)    # 或 c_div = a / b

# 取负数
c_neg = torch.neg(a)       # 或 c_neg = -a

1.2. 基本运算函数— in-place 操作

带下划线的函数(如 add_)会 直接修改原始张量,不返回新张量:

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

a.add_(b)       # a 变为 [5, 7, 9]
a.sub_(b)       # a 变为 [1, 2, 3](等价于 a = a - b)
a.mul_(2)       # a 变为 [2, 4, 6]
a.div_(2)       # a 变为 [1, 2, 3]
a.neg_()        # a 变为 [-1, -2, -3]

1.3. 关键区别

操作类型示例是否修改原数据返回值适用场景
非 in-placea.add(b)新张量需要保留原始数据时
in-placea.add_(b)修改后的原张量节省内存,但可能破坏梯度计算

1.4. In-place 操作注意事项

1.4.1. 梯度跟踪:

对 requires_grad=True 的张量执行 in-place 操作会破坏梯度计算,可能导致错误:

x = torch.tensor(2.0, requires_grad=True)
y = x**2
x.add_(1)  # 错误!会破坏 x 的梯度跟踪

1.4.2. 设备一致性:

操作张量必须在同一设备上(CPU 或 GPU):

a = a.cuda()
b = b.cpu()
a.add_(b)  # 错误!设备不一致

1.4.3. 广播限制:

In-place 操作不支持广播机制中的维度扩展:

a = torch.ones(3, 1)
b = torch.ones(1, 3)
a.add_(b)  # 错误!形状不匹配且无法广播

1.5. 使用建议

优先使用非 in-place 操作:避免因修改原数据导致的梯度计算错误。
谨慎使用 in-place 操作:
当明确知道操作不会影响梯度时(例如预处理数据)。
在内存受限时(如大模型训练)节省内存。
避免在自动求导中使用:PyTorch 的自动微分机制(Autograd)依赖张量历史,in-place 操作会破坏历史记录。

2. 阿达玛积

在深度学习和线性代数中,阿达玛积(Hadamard Product)是一种重要的元素级运算,以下是其核心概念及 PyTorch 实现详解:

2.1. 阿达玛积定义

数学表示:若矩阵A 和 B形状相同(均为 m×n),则它们的阿达玛积 A⊙B 定义为:


即对应位置元素相乘,结果仍为 m×n的矩阵。
与矩阵乘法的区别:
阿达玛积: 元素级操作,形状严格相同。
矩阵乘法(点积):线性代数操作,要求 A 的列数 = B 的行数,结果形状为(A的行数,B的列数)。

2.2. PyTorch 中的阿达玛积

2.2.1. 实现方式

在 PyTorch 中,阿达玛积可以通过以下方法实现:

import torch

# 创建相同形状的张量
A = torch.tensor([[1, 2], [3, 4]])  # shape: (2, 2)
B = torch.tensor([[5, 6], [7, 8]])  # shape: (2, 2)

# 方法1:使用 * 运算符
C = A * B  # tensor([[5, 12], [21, 32]])

# 方法2:使用 torch.mul()
D = torch.mul(A, B)  # 与 C 结果相同

2.2.2. 广播机制下的阿达玛积

当张量形状不同但满足广播规则时,PyTorch 会自动扩展维度后执行元素相乘:

A = torch.tensor([[1, 2], [3, 4]])  # shape: (2, 2)
B = torch.tensor([10, 20])          # shape: (2,)

# 广播后 B 扩展为 [[10, 20], [10, 20]]
C = A * B  # tensor([[10, 40], [30, 80]])

2.3. 应用场景

2.3.1. 注意力机制:

在 Transformer 中,阿达玛积用于计算注意力权重与值的加权求和。

attention_weights = torch.softmax(scores, dim=-1)  # 形状: (batch, seq_len, seq_len)
weighted_values = attention_weights * values       # 形状: (batch, seq_len, d_model)

2.3.2. 激活函数:

如门控线性单元(GLU)中使用阿达玛积控制信息流:

gate = torch.sigmoid(linear(x))  # 形状: (batch, hidden_dim)
output = gate * x                # 形状: (batch, hidden_dim)

2.3.3. 图像处理:

对图像掩码(如 ROI 区域)进行元素级过滤:

masked_image = image * mask  # mask 为 0-1 的二值张量

2.4. 注意事项

2.4.1. 形状一致性:

非广播情况下,输入张量必须形状一致,否则会报错:

A = torch.rand(2, 3)
B = torch.rand(3, 2)
C = A * B  # 报错:形状不匹配

2.4.2. 梯度计算:

若张量需要梯度(requires_grad=True),避免使用 *_() 的 in-place 操作,可能导致梯度中断:

A = torch.tensor([1.0], requires_grad=True)
B = torch.tensor([2.0])
A.mul_(B)  # 错误!破坏计算图

2.4.3数据类型匹配:

确保张量数据类型一致(如 float32 与 int64 无法直接相乘):

A = torch.tensor([1, 2], dtype=torch.int32)
B = torch.tensor([3.0, 4.0])
C = A * B  # 错误!数据类型不匹配

2.5. 对比其他乘积

操作类型符号输入要求输出形状示例
阿达玛积*同形状或可广播与输入同形状A * B
矩阵乘法@A 列数 = B行数(A行数, B列数)
点积(向量)torch.dot一维向量标量torch.dot(v1, v2)
外积torch.outer一维向量(len(v1), len(v2))torch.outer(v1, v2)

2.6. 代码示例

import torch

# 示例1:严格形状匹配
A = torch.tensor([[1, 2], [3, 4]])
B = torch.tensor([[5, 6], [7, 8]])
hadamard = A * B  # tensor([[ 5, 12], [21, 32]])

# 示例2:广播机制
C = torch.tensor([[1, 2]])  # shape: (1, 2)
D = torch.tensor([[3], [4]])  # shape: (2, 1)
hadamard_broadcast = C * D  # tensor([[3, 6], [4, 8]])

# 示例3:梯度计算
x = torch.tensor([2.0], requires_grad=True)
y = torch.tensor([3.0])
z = x * y  # 非 in-place 操作
z.backward()
print(x.grad)  # 输出: tensor([3.])

3. 点积运算

点积运算要求第一个矩阵 shape: (n, m),第二个矩阵 shape: (m, p), 两个矩阵点积运算 shape 为: (n, p)。

3.1. 点积运算规则

3.1.1矩阵乘法(点积)要求:

输入形状:

第一个矩阵:(n, m)

第二个矩阵:(m, p)

输出形状:

结果矩阵:(n, p)

核心操作:
在这里插入图片描述

3.2. PyTorch 中的点积运算函数

3.2.1. @ 运算符

功能:执行矩阵乘法,等同于 torch.matmul。

灵活性:支持多维张量,自动处理广播。

示例:

A = torch.randn(2, 3)  # shape: (2, 3)
B = torch.randn(3, 4)  # shape: (3, 4)
C = A @ B              # shape: (2, 4)

3.2.2. torch.mm

功能:严格处理 二维矩阵乘法。

限制:输入必须为 2D 张量。

示例:

A = torch.randn(2, 3)   # shape: (2, 3)
B = torch.randn(3, 4)   # shape: (3, 4)
C = torch.mm(A, B)      # shape: (2, 4)

3.2.3. torch.bmm

功能:批量处理 三维张量的矩阵乘法。

输入要求:

输入1:(batch_size, n, m)

输入2:(batch_size, m, p)

输出形状:(batch_size, n, p)

示例:

batch_size = 5
A = torch.randn(batch_size, 2, 3)  # shape: (5, 2, 3)
B = torch.randn(batch_size, 3, 4)  # shape: (5, 3, 4)
C = torch.bmm(A, B)                # shape: (5, 2, 4)

3.2.4. torch.matmul

功能:通用矩阵乘法,支持 多维张量和广播。

输入灵活性:

支持不同维度的张量(如 2D 与 3D)。

最后两维必须满足矩阵乘法规则。

示例:

# 二维输入(等同 torch.mm)
A = torch.randn(2, 3)
B = torch.randn(3, 4)
C = torch.matmul(A, B)  # shape: (2, 4)

# 三维输入(等同 torch.bmm)
A = torch.randn(5, 2, 3)
B = torch.randn(5, 3, 4)
C = torch.matmul(A, B)  # shape: (5, 2, 4)

# 广播机制(不同维度)
A = torch.randn(2, 5, 3)  # shape: (2, 5, 3)
B = torch.randn(3, 4)     # shape: (3, 4)
C = torch.matmul(A, B)    # shape: (2, 5, 4)(自动广播 B 到 (2, 3, 4))

3.3. 形状匹配规则

3.3.1. 基础规则

最后两维必须满足矩阵乘法:

前一个张量的列数 = 后一个张量的行数。

合法示例:

A: (3, 4), B: (4, 5) → Output: (3, 5)    # 标准乘法
A: (5, 3, 4), B: (4, 2) → Output: (5, 3, 2)  # 广播 B 到 (5, 4, 2)

3.3.2. 非法形状示例

错误原因:最后两维不匹配。

A = torch.randn(2, 3)
B = torch.randn(4, 5)
C = torch.mm(A, B)  # 报错:3 != 4

3.4. 函数对比表

函数输入维度广播支持典型场景
@/torch.matmul任意维度(需满足最后两维规则)通用多维张量乘法,支持广播
torch.mm严格 2D简单二维矩阵乘法
torch.bmm严格 3D批量处理固定批次的矩阵乘法

3.5. 高阶示例

3.5.1. 混合维度乘法

# 输入1: 4D 张量 (2, 5, 3, 4)
# 输入2: 3D 张量 (4, 6)
A = torch.randn(2, 5, 3, 4)
B = torch.randn(4, 6)
C = torch.matmul(A, B)  # 输出形状: (2, 5, 3, 6)

3.5.2. 广播机制

# 输入1: (3, 1, 4) 
# 输入2: (5, 4, 2)
A = torch.randn(3, 1, 4)
B = torch.randn(5, 4, 2)
C = torch.matmul(A, B)  # 输出形状: (3, 5, 1, 2)

3.6. 常见错误及解决

3.6.1. 维度不匹配

A = torch.randn(2, 3)
B = torch.randn(4, 5)
try:
    C = torch.mm(A, B)  # 报错:3 != 4
except RuntimeError as e:
    print("错误:", e)

3.6.2. 误用 torch.bmm

A = torch.randn(2, 3, 4)  # shape: (2, 3, 4)
B = torch.randn(3, 4, 5)  # shape: (3, 4, 5)
try:
    C = torch.bmm(A, B)  # 报错:批次维度 2 != 3
except RuntimeError as e:
    print("错误:", e)

3.7. 总结

优先使用 @ 或 torch.matmul:灵活支持多维张量和广播。

明确场景选择函数:简单 2D 乘法 → torch.mm;固定批次 3D 乘法 → torch.bmm

形状检查:始终确保最后两维满足矩阵乘法规则。

4.指定运算设备

在 PyTorch 中,指定运算设备(CPU 或 GPU)是优化计算效率的关键步骤。以下是 将张量移动至 GPU 的三种方法,以及相关注意事项的详细说明:

4.1. 检查 GPU 可用性

在操作设备前,需确保当前环境支持 GPU:

import torch

# 检查 CUDA 是否可用
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"当前设备: {device}")

# 输出示例(若有 GPU): 
# 当前设备: cuda:0

4.2. 将张量移动到 GPU 的方法

4.2.1. 使用 .cuda() 方法

功能:将 CPU 张量复制到 GPU(默认选择第一个 GPU)。

示例:

tensor_cpu = torch.tensor([1, 2, 3])
tensor_gpu = tensor_cpu.cuda()          # 移动到默认 GPU(索引 0)
tensor_gpu_1 = tensor_cpu.cuda(device=1) # 移动到指定 GPU(索引 1)

注意:若未安装 CUDA 驱动,调用 .cuda() 会报错。

4.2.2. 直接在 GPU 上创建张量

方法:通过 device 参数指定设备。

示例:

# 直接创建在 GPU 上
tensor_gpu = torch.tensor([1, 2, 3], device="cuda")

# 使用工厂函数(如 zeros, randn)指定设备
ones_gpu = torch.ones(3, 3, device="cuda")

4.2.3. 使用 .to() 方法

功能:灵活转移设备,支持同时指定数据类型。

示例:

tensor_cpu = torch.randn(2, 2)

# 移动到 GPU
tensor_gpu = tensor_cpu.to(device="cuda")

# 同时转换数据类型和设备
tensor_gpu_float16 = tensor_cpu.to(device="cuda", dtype=torch.float16)

4.3. 关键操作对比

方法语法优点 缺点
.cuda()tensor.cuda(device=idx)简单直接,适合单 GPU 需手动指定设备索引
直接创建device=“cuda”避免数据复制,效率高 需提前规划设备分配
.to()tensor.to(device)支持设备+类型转换,代码通用性强 语法稍复杂

4.4. 注意事项

4.4.1. 设备一致性

所有参与运算的张量必须在同一设备上:

a = torch.tensor([1], device="cuda")
b = torch.tensor([2], device="cpu")
c = a + b  # 报错:不同设备的张量无法运算

4.4.2. 内存管理

显存释放:GPU 显存不会自动释放,需手动清理或使用上下文管理器:

with torch.cuda.device(0):  # 在指定 GPU 上操作
    tensor = torch.randn(3, 3, device="cuda")
# 退出上下文后显存可能被释放(依赖垃圾回收)

4.4.3. 梯度跟踪

保持计算图连续性:移动带梯度的张量时,使用 .to() 而非 .cuda() 以保留梯度历史:

x = torch.tensor(2.0, requires_grad=True)
x_gpu = x.to("cuda")  # 保留梯度跟踪
y = x_gpu**2
y.backward()

4.5. 完整代码示例

import torch

# 检查 CUDA 可用性
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"当前设备: {device}")

# 方法1:使用 .cuda()
tensor_cpu = torch.ones(2, 2)
tensor_gpu = tensor_cpu.cuda()  # 移动到默认 GPU

# 方法2:直接在 GPU 创建
tensor_gpu_direct = torch.randn(3, 3, device="cuda")

# 方法3:使用 .to()
tensor_gpu_to = tensor_cpu.to(device="cuda", dtype=torch.float16)

# 验证设备
print(tensor_gpu.device)          # 输出: cuda:0
print(tensor_gpu_direct.device)   # 输出: cuda:0
print(tensor_gpu_to.device)       # 输出: cuda:0

# 错误示例:设备不一致
try:
    a = torch.tensor([1], device="cuda")
    b = torch.tensor([2], device="cpu")
    c = a + b
except RuntimeError as e:
    print("错误信息:", e)

4.6. 最佳实践

统一设备管理:

# 全局定义设备
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 模型与数据统一迁移
model = MyModel().to(device)
data = data.to(device)

避免频繁设备切换:减少 CPU-GPU 数据传输开销。
多 GPU 训练:使用 torch.nn.DataParalleltorch.distributed 进行分布式训练。


http://www.kler.cn/a/588534.html

相关文章:

  • 每日Attention学习27——Patch-based Graph Reasoning
  • 【从零开始学习计算机科学】软件工程(六)软件质量
  • Docker基础知识介绍
  • 【Python+HTTP接口】POST请求不同请求头构造
  • 【ASMbits--常用算术运算指令】
  • 深入解析 FID:深度学习生成模型评价指标
  • pyQT学习笔记——Qt常用组件与绘图类的使用指南
  • 【商城实战(36)】UniApp性能飞升秘籍:从渲染到编译的深度优化
  • 使用memmove优化插入排序
  • 软件架构设计习题及复习
  • 计算机网络——NAT
  • 【Linux】Socket 编程 TCP
  • 《Python深度学习》第四讲:计算机视觉中的深度学习
  • 在Simulink中将Excel数据导入可变负载模块的方法介绍
  • 工程化与框架系列(30)--前端日志系统实现
  • cursor全栈网页开发最合适的技术架构和开发语言
  • JVM系统变量的妙用
  • 树莓派 连接 PlutoSDR 教程
  • Typedef 与enum的使用
  • 【人工智能基础2】人工神经网络、卷积神经网络基础、循环神经网络、长短时记忆网络