从向量到张量:图解‘内积’、‘外积’与‘克罗内克积’在PyTorch/TensorFlow里的那些事儿
从向量到张量:图解‘内积’、‘外积’与‘克罗内克积’在PyTorch/TensorFlow里的那些事儿
当你第一次在PyTorch或TensorFlow中看到torch.matmul、tf.tensordot、*这些运算符时,是否感到困惑?它们有什么区别?什么时候该用哪一个?本文将用直观的图解和代码示例,带你理清这些概念,让你在编写神经网络模型时能够游刃有余。
1. 向量运算:从基础到框架实现
1.1 内积(点积):神经网络中的基础构建块
内积(Inner Product),也称为点积(Dot Product),是深度学习中最基础的运算之一。在PyTorch和TensorFlow中,实现向量内积有多种方式:
# PyTorch实现 import torch a = torch.tensor([1, 2, 3]) b = torch.tensor([4, 5, 6]) dot_product = torch.dot(a, b) # 32 dot_product_alt = torch.sum(a * b) # 等价实现 # TensorFlow实现 import tensorflow as tf a = tf.constant([1, 2, 3]) b = tf.constant([4, 5, 6]) dot_product = tf.tensordot(a, b, axes=1) # 32内积在神经网络中的应用场景包括:
- 全连接层的计算
- 注意力机制中的query-key相似度计算
- 损失函数(如余弦相似度)的实现
注意:框架中的
dot函数通常只支持一维向量的点积运算。对于更高维度的张量,需要使用matmul或tensordot。
1.2 外积:两种容易混淆的概念
在中文语境中,"外积"实际上对应着两个不同的数学概念:
- Outer Product(张量积):
- 结果是一个矩阵
- 计算方式:列向量 × 行向量
- 框架实现:
# PyTorch a = torch.tensor([1, 2, 3]) b = torch.tensor([4, 5]) outer = torch.outer(a, b) # 3x2矩阵 # TensorFlow outer = tf.tensordot(a, b, axes=0)- Exterior Product(叉积/叉乘):
- 仅适用于3D空间中的向量
- 结果是一个垂直于输入向量的新向量
- 框架实现:
# PyTorch a = torch.tensor([1, 0, 0]) b = torch.tensor([0, 1, 0]) cross = torch.cross(a, b) # [0, 0, 1] # TensorFlow cross = tf.linalg.cross(a, b)| 特性 | Outer Product | Exterior Product |
|---|---|---|
| 输入维度 | 任意向量 | 仅3D向量 |
| 输出维度 | 矩阵 | 向量 |
| 数学符号 | ⊗ | × |
| 主要应用 | 特征交互、核方法 | 3D图形学、物理模拟 |
2. 矩阵运算:从基础概念到框架API
2.1 矩阵乘法:神经网络的核心运算
矩阵乘法(matmul)是深度学习中最常见的运算之一。在框架中,有几种等效的实现方式:
# PyTorch A = torch.randn(2, 3) B = torch.randn(3, 4) matmul = torch.matmul(A, B) # 2x4 matmul_alt = A @ B # 等效写法 # TensorFlow matmul = tf.matmul(A, B)矩阵乘法在神经网络中的应用包括:
- 全连接层的前向传播
- 卷积运算的im2col实现
- 注意力机制中的QKV变换
2.2 逐元素乘法与哈达玛积
逐元素乘法(Element-wise Multiplication)和哈达玛积(Hadamard Product)实际上是相同的概念:
# PyTorch A = torch.randn(2, 2) B = torch.randn(2, 2) hadamard = A * B # 逐元素相乘 # TensorFlow hadamard = tf.multiply(A, B)应用场景:
- 注意力权重与value的加权
- 门控机制(如LSTM中的门控)
- 数据增强中的掩码操作
3. 高阶张量运算:克罗内克积与张量缩并
3.1 克罗内克积:矩阵的升维运算
克罗内克积(Kronecker Product)是一种将两个矩阵组合成更大矩阵的运算:
# PyTorch实现 def kronecker(A, B): return torch.einsum('ab,cd->acbd', A, B).reshape(A.size(0)*B.size(0), A.size(1)*B.size(1)) # TensorFlow实现 def kronecker(A, B): return tf.reshape(tf.einsum('ab,cd->acbd', A, B), [A.shape[0]*B.shape[0], A.shape[1]*B.shape[1]])克罗内克积在深度学习中的应用:
- 卷积神经网络中的膨胀卷积(Dilated Convolution)
- 某些类型的注意力机制
- 参数矩阵的结构化扩展
3.2 张量缩并:einsum的强大威力
爱因斯坦求和约定(einsum)是处理高阶张量运算的利器:
# 矩阵乘法 torch.einsum('ij,jk->ik', A, B) # 批量矩阵乘法 torch.einsum('bij,bjk->bik', batch_A, batch_B) # 注意力分数计算 torch.einsum('bqd,bkd->bqk', Q, K)常见缩并模式及其应用:
| 缩并模式 | 等效运算 | 应用场景 |
|---|---|---|
| 'ij,jk->ik' | 矩阵乘法 | 全连接层 |
| 'bij,bjk->bik' | 批量矩阵乘 | 序列模型 |
| 'bqd,bkd->bqk' | 矩阵乘+转置 | 注意力分数 |
| 'bhqd,bhkd->bhqk' | 多头注意力 | Transformer |
4. 实战应用:从理论到代码实现
4.1 自注意力机制中的各种积
让我们看看这些运算如何在Transformer的自注意力机制中发挥作用:
def scaled_dot_product_attention(Q, K, V, mask=None): """Q, K, V的形状: (batch_size, seq_len, d_model)""" d_k = Q.size(-1) # 计算注意力分数(内积的批量版本) scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k) if mask is not None: scores = scores.masked_fill(mask == 0, -1e9) # 计算注意力权重(softmax) attention_weights = torch.softmax(scores, dim=-1) # 应用注意力权重到V上(加权求和) output = torch.matmul(attention_weights, V) return output, attention_weights在这个实现中,我们使用了:
matmul计算query和key的相似度(本质是批量内积)- 逐元素运算(softmax和masking)
- 最后的
matmul实现注意力权重对value的加权
4.2 核方法中的外积应用
外积在核方法中有着重要应用,特别是在特征映射方面:
def polynomial_kernel(X, Y, degree=2): """多项式核函数""" # 先计算内积 inner = torch.matmul(X, Y.T) # 然后加上偏置并取幂 return (inner + 1) ** degree def rbf_kernel(X, Y, gamma=None): """RBF核函数""" if gamma is None: gamma = 1.0 / X.size(1) # 计算两两距离 XX = torch.sum(X**2, dim=1, keepdim=True) YY = torch.sum(Y**2, dim=1, keepdim=True) XY = torch.matmul(X, Y.T) distances = XX - 2 * XY + YY.T return torch.exp(-gamma * distances)在实际项目中,选择合适的运算需要考虑以下因素:
- 输入张量的形状和维度
- 期望的输出形状
- 计算效率(某些运算在特定硬件上更高效)
- 数值稳定性(如softmax前的缩放)
