Tensor的常用计算方法(torch示例说明)
Tensor(张量)是多维数组的泛化概念,在深度学习和科学计算中被广泛使用。以下是Tensor的常用计算方法,涵盖基础操作和高级应用。
一、基础创建与属性
1. 创建Tensor
import torch# 从Python列表创建
tensor_from_list = torch.tensor([[1, 2], [3, 4]])# 特殊初始化
zeros_tensor = torch.zeros(2, 3) # 2x3的全0张量
ones_tensor = torch.ones(2, 3) # 2x3的全1张量
rand_tensor = torch.rand(2, 3) # 2x3的随机张量(0-1均匀分布)
randn_tensor = torch.randn(2, 3) # 2x3的标准正态分布张量tensor = torch.randint(1, 20, (2, 3)) # 1-20的2x3 int类型数字# 类似已有张量
new_tensor = torch.zeros_like(rand_tensor) # 形状和类型与rand_tensor相同的全0张量
2. Tensor属性
x = torch.rand(2, 3, 4)
print(x.shape) # 形状: torch.Size([2, 3, 4])
print(x.dtype) # 数据类型: torch.float32
print(x.device) # 存储设备: cpu/cuda
print(x.requires_grad) # 是否计算梯度
二、基本数学运算
1. 元素级运算
a = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])# 加法
c = a + b # 等价于 torch.add(a, b)
c = torch.add(a, b, out=torch.empty(3)) # 指定输出tensor# 其他运算
d = a - b # 减法
e = a * b # 逐元素乘法(Hadamard积)
f = a / b # 逐元素除法
g = a ** 2 # 平方
h = torch.sqrt(a) # 平方根
2. 广播机制
x = torch.ones(2, 3)
y = torch.tensor([1, 2, 3])
z = x + y # y被广播为[[1,2,3], [1,2,3]]
3. 矩阵乘法
-
一维向量乘法 点积(内 外积)
import torch# 创建两个一维向量
v1 = torch.tensor([1, 2, 3])
v2 = torch.tensor([4, 5, 6])# 点积计算
dot_product = torch.dot(v1, v2)
print(f"向量点积结果:\n{dot_product}\n")
"""
向量点积结果:
tensor(32)
解释:1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32
"""# 外积计算
outer_product = torch.outer(v1, v2)
print(f"向量外积结果:\n{outer_product}\n")
"""
向量外积结果:
tensor([[ 4, 5, 6],[ 8, 10, 12],[12, 15, 18]])
解释:结果矩阵的每个元素是v1[i] * v2[j]
"""
-
二维矩阵乘法
# 创建两个2x3和3x2的矩阵
mat1 = torch.tensor([[1, 2, 3], [4, 5, 6]]) # 2x3
mat2 = torch.tensor([[7, 8], [9, 10], [11, 12]]) # 3x2# 矩阵乘法
matrix_product = torch.mm(mat1, mat2)
print(f"二维矩阵乘法结果:\n{matrix_product}\n")
"""
二维矩阵乘法结果:
tensor([[ 58, 64],[139, 154]])
解释:
[1*7 + 2*9 + 3*11, 1*8 + 2*10 + 3*12] = [58, 64]
[4*7 + 5*9 + 6*11, 4*8 + 5*10 + 6*12] = [139, 154]
"""# 逐元素乘法(Hadamard积)
# 创建两个相同形状的矩阵
mat_a = torch.tensor([[1, 2], [3, 4]])
mat_b = torch.tensor([[5, 6], [7, 8]])# 逐元素乘法
elementwise_product = mat_a * mat_b
print(f"逐元素乘法结果:\n{elementwise_product}\n")
"""
逐元素乘法结果:
tensor([[ 5, 12],[21, 32]])
解释:对应位置相乘
"""
-
三维矩阵乘法
# 创建两个3D张量 (batch_size=2, 2x3和3x2)
batch1 = torch.tensor([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]) # 2x2x3
batch2 = torch.tensor([[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]]]) # 2x3x2# 批量矩阵乘法
batch_product = torch.bmm(batch1, batch2)
print(f"三维批量矩阵乘法结果:\n{batch_product}\n")
"""
三维批量矩阵乘法结果:
tensor([[[ 22, 28],[ 49, 64]],[[214, 244],[277, 316]]])
解释:
第一个batch:
[[1*1 + 2*3 + 3*5, 1*2 + 2*4 + 3*6], = [22, 28][4*1 + 5*3 + 6*5, 4*2 + 5*4 + 6*6]] [49, 64]第二个batch:
[[7*7 + 8*9 + 9*11, 7*8 + 8*10 + 9*12], = [214, 244][10*7 + 11*9 + 12*11, 10*8 + 11*10 + 12*12]] [277, 316]
"""#广播矩阵乘法
# 3D张量与2D矩阵相乘
batch_mat = torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) # 2x2x2
mat = torch.tensor([[1, 0], [0, 1]]) # 2x2# 广播乘法
broadcast_product = torch.matmul(batch_mat, mat)
print(f"广播矩阵乘法结果:\n{broadcast_product}\n")
"""
广播矩阵乘法结果:
tensor([[[1, 2],[3, 4]],[[5, 6],[7, 8]]])
解释:相当于每个batch中的矩阵与单位矩阵相乘,结果不变
"""
-
不同维数混合乘法
############### 矩阵与向量乘法 ##############
# 矩阵 (2x3) 与向量 (3)
matrix = torch.tensor([[1, 2, 3], [4, 5, 6]]) # 2x3
vector = torch.tensor([1, 0, 2]) # 3# 矩阵乘向量
mv_product = torch.mv(matrix, vector)
print(f"矩阵-向量乘法结果:\n{mv_product}\n")
"""
矩阵-向量乘法结果:
tensor([ 7, 16])
解释:
[1*1 + 2*0 + 3*2] = 7
[4*1 + 5*0 + 6*2] = 16
"""############### 批量矩阵与向量乘法 ############### 批量矩阵 (2x2x3) 与批量向量 (2x3)
batch_matrix = torch.tensor([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]) # 2x2x3
batch_vector = torch.tensor([[1, 0, 2], [0, 1, 1]]) # 2x3# 批量矩阵-向量乘法
batch_mv_product = torch.bmm(batch_matrix, batch_vector.unsqueeze(2)).squeeze()
print(f"批量矩阵-向量乘法结果:\n{batch_mv_product}\n")
"""
批量矩阵-向量乘法结果:
tensor([[ 7, 16],[17, 23]])
解释:
第一个batch:
[[1,2,3] @ [1,0,2] = 7[4,5,6] @ [1,0,2] = 16]第二个batch:
[[7,8,9] @ [0,1,1] = 17[10,11,12] @ [0,1,1] = 23]
"""############### 批量矩阵与向量乘法 ############### 批量矩阵 (2x2x3) 与批量向量 (2x3)
batch_matrix = torch.tensor([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]) # 2x2x3
batch_vector = torch.tensor([[1, 0, 2], [0, 1, 1]]) # 2x3# 批量矩阵-向量乘法
batch_mv_product = torch.bmm(batch_matrix, batch_vector.unsqueeze(2)).squeeze()
print(f"批量矩阵-向量乘法结果:\n{batch_mv_product}\n")
"""
批量矩阵-向量乘法结果:
tensor([[ 7, 16],[17, 23]])
解释:
第一个batch:
[[1,2,3] @ [1,0,2] = 7[4,5,6] @ [1,0,2] = 16]第二个batch:
[[7,8,9] @ [0,1,1] = 17[10,11,12] @ [0,1,1] = 23]
"""
三、张量操作
1. 形状操作
x = torch.randn(2, 3, 4)# 改变形状
y = x.view(2, 12) # 调整为2x12 (必须保持元素总数不变)
z = x.reshape(2, 12) # 更灵活的reshape# 转置
t = x.transpose(1, 2) # 交换维度1和2 → 2x4x3
p = x.permute(2, 0, 1) # 自定义维度顺序 → 4x2x3# 压缩/扩展维度
squeezed = x.squeeze() # 移除所有长度为1的维度
unsqueezed = x.unsqueeze(0) # 在第0维增加维度 → 1x2x3x4
2. 连接与分割
# 连接张量
x = torch.randn(2, 3)
y = torch.randn(2, 3)
cat = torch.cat([x, y], dim=0) # 沿dim=0连接 → 4x3
stack = torch.stack([x, y]) # 新建维度堆叠 → 2x2x3# 分割张量
chunks = torch.chunk(x, 2, dim=1) # 沿dim=1分成2块 → 两个2x2张量
split = torch.split(x, [1, 2], dim=1) # 按[1,2]分割 → 2x1和2x2
四、归约操作
1. 统计计算
x = torch.tensor([[1, 2], [3, 4]])# 求和
sum_all = x.sum() # 所有元素和 → 10
sum_dim0 = x.sum(dim=0) # 沿dim=0求和 → [4, 6]# 其他统计
mean_val = x.mean() # 平均值
max_val, max_idx = x.max(dim=1) # 每行最大值及索引
min_val = x.min() # 最小值
prod = x.prod() # 所有元素乘积
2. 比较操作
x = torch.tensor([1, 2, 3])
y = torch.tensor([3, 2, 1])eq = x == y # [False, True, False]
gt = x > y # [False, False, True]
all_close = torch.allclose(x, y, rtol=1e-5) # 是否近似相等
五、高级操作
1. 梯度计算
x = torch.tensor(2.0, requires_grad=True)
y = x ** 2 + 3 * x + 1
y.backward() # 计算梯度
print(x.grad) # dy/dx = 2x+3 → 7.0
2. 索引与切片
x = torch.randn(3, 4)# 基础索引
row = x[1] # 第2行
col = x[:, 1] # 第2列
element = x[1, 2] # (2,3)位置的元素# 高级索引
indices = torch.tensor([0, 2])
selected = x[:, indices] # 选择第1和第3列# 布尔索引
mask = x > 0.5
filtered = x[mask] # 所有大于0.5的元素
3. 内存操作
x = torch.tensor([1, 2, 3])
y = x.clone() # 深拷贝
z = x.detach() # 分离计算图(用于固定某些层)# 设备转移
if torch.cuda.is_available():x_gpu = x.cuda() # 转移到GPUx_cpu = x_gpu.cpu() # 转回CPU
六、实用工具方法
1. 保存与加载
torch.save(x, 'tensor.pt') # 保存
loaded = torch.load('tensor.pt') # 加载# 状态字典保存(常用于模型)
state = {'tensor': x, 'step': 100}
torch.save(state, 'state.pt')
2. 类型转换
x = torch.tensor([1, 2, 3], dtype=torch.float32)
y = x.int() # 转为int32
z = x.double() # 转为float64
3. 与NumPy互转
import numpy as np# Tensor → NumPy
a = torch.ones(3)
b = a.numpy() # 共享内存(当在CPU时)# NumPy → Tensor
c = np.array([1, 2, 3])
d = torch.from_numpy(c) # 共享内存
七、性能优化技巧
- 避免CPU-GPU频繁传输:尽量减少设备间的数据转移
- 使用原地操作:后缀带下划线的方法可节省内存
x.add_(y) # 原地加法,等价于 x += y
- 向量化操作:尽量使用内置函数而非循环
- 预分配内存:对于循环中的张量操作,预先分配好内存
result = torch.empty(1000)
for i in range(1000):result[i] = i * 2
Tensor矩阵乘法与点积的区分
1. 点积 (Dot Product)
-
仅适用于1D向量
-
结果是一个标量值
-
计算方式:对应位置元素相乘后求和
import torch# 示例1: 向量点积
a = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])dot_product = torch.dot(a, b) # 1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32
print("向量点积:", dot_product) # 输出: tensor(32)# 示例2: 使用@运算符(当操作数是1D时等同于点积)
print("a @ b:", a @ b) # 同样输出: tensor(32)
2.矩阵乘法 (Matrix Multiplication)
-
适用于2D矩阵或更高维张量
-
结果是一个矩阵或张量
-
计算方式:行与列的点积
# 示例3: 基本矩阵乘法
A = torch.tensor([[1, 2], [3, 4]]) # 2x2
B = torch.tensor([[5, 6], [7, 8]]) # 2x2# 手动计算验证:
# 第一行: [1,2]·[5,7] = 1*5+2*7=19, [1,2]·[6,8]=1*6+2*8=22
# 第二行: [3,4]·[5,7]=3*5+4*7=43, [3,4]·[6,8]=3*6+4*8=50
mat_mul = A @ B
print("矩阵乘法结果:\n", mat_mul)
# 输出:
# tensor([[19, 22],
# [43, 50]])# 示例4: 不同形状的矩阵乘法
C = torch.tensor([[1, 2, 3], [4, 5, 6]]) # 2x3
D = torch.tensor([[1, 2], [3, 4], [5, 6]]) # 3x2# 结果应为2x2矩阵
# [1,2,3]·[1,3,5] = 1*1+2*3+3*5=1+6+15=22
# [1,2,3]·[2,4,6]=1*2+2*4+3*6=2+8+18=28
# [4,5,6]·[1,3,5]=4*1+5*3+6*5=4+15+30=49
# [4,5,6]·[2,4,6]=4*2+5*4+6*6=8+20+36=64
print("C @ D:\n", C @ D)
# 输出:
# tensor([[22, 28],
# [49, 64]])
3. 常见混淆场景
场景1: 向量与矩阵的乘法
# 向量(1D)与矩阵(2D)相乘
v = torch.tensor([1, 2, 3]) # 形状 (3,)
M = torch.tensor([[1, 2], [3, 4], [5, 6]]) # 形状 (3,2)# 这是矩阵乘法,不是点积!
# 向量被自动视为行向量 (1x3)
# 结果是一个行向量 (1x2)
result = v @ M # 等价于 torch.matmul(v, M)
print("向量与矩阵乘法:", result) # 输出: tensor([22, 28])
# 计算: 1*1 + 2*3 + 3*5 = 22, 1*2 + 2*4 + 3*6 = 28
场景2: 批量矩阵乘法 (3D张量)
# 批量矩阵乘法 (3D张量)
batch_A = torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) # 形状 (2,2,2)batch_B = torch.tensor([[[2, 0], [0, 2]], [[3, 0], [0, 3]]]) # 形状 (2,2,2)# 批量矩阵乘法
# 对每个2x2矩阵独立进行乘法
batch_result = batch_A @ batch_B
print("批量矩阵乘法结果:\n", batch_result)
# 输出:
# tensor([[[ 2, 4], # 第一个批次: [[1,2],[3,4]] @ [[2,0],[0,2]] = [[2,4],[6,8]]
# [ 6, 8]],
#
# [[15, 18], # 第二个批次: [[5,6],[7,8]] @ [[3,0],[0,3]] = [[15,18],[21,24]]
# [21, 24]]])
4. 特殊情况的等价性
只有当两个1D向量相乘时,点积和矩阵乘法结果是等价的:
u = torch.tensor([1, 2, 3])
v = torch.tensor([4, 5, 6])# 三种等效表示
print(torch.dot(u, v)) # 点积函数: tensor(32)
print(u @ v) # @运算符: tensor(32)
print(torch.matmul(u, v)) # 矩阵乘法函数: tensor(32)
5. 错误用法示例
# 错误1: 两个2D矩阵使用dot()
try:torch.dot(A, B) # A和B都是2x2
except RuntimeError as e:print("错误:", e) # 输出: 1D tensors expected, but got 2D and 2D tensors# 错误2: 维度不匹配的矩阵乘法
X = torch.tensor([[1, 2]]) # 1x2
Y = torch.tensor([[3, 4, 5]]) # 1x3try:X @ Y # 需要X的列数(2)等于Y的行数(1),但2≠1
except RuntimeError as e:print("错误:", e) # 输出: mat1 and mat2 shapes cannot be multiplied (1x2 and 1x3)
点积 (1D + 1D → 0D):[a₁, a₂, a₃] · [b₁, b₂, b₃] = a₁b₁ + a₂b₂ + a₃b₃矩阵乘法 (2D + 2D → 2D):⎡a₁₁ a₁₂⎤ ⎡b₁₁ b₁₂⎤ ⎡a₁₁b₁₁+a₁₂b₂₁ a₁₁b₁₂+a₁₂b₂₂⎤⎣a₂₁ a₂₂⎦ @ ⎣b₂₁ b₂₂⎦ = ⎣a₂₁b₁₁+a₂₂b₂₁ a₂₁b₁₂+a₂₂b₂₂⎦向量-矩阵乘法 (1D + 2D → 1D):[v₁, v₂] @ ⎡m₁₁ m₁₂⎤ = [v₁m₁₁+v₂m₂₁, v₁m₁₂+v₂m₂₂]⎣m₂₁ m₂₂⎦
点积:用于计算相似度、注意力分数等
矩阵乘法:神经网络层的核心操作(全连接层、Transformer等)
批量矩阵乘法:高效处理批量数据(卷积、RNN等)