十进制本身是周期性的,二进制也是周期性的
构建n维的位置编码,每一维用不同的周期函数刻画取值
“叠加旋转位置编码的方式由加法改乘法”
假设两个token的embedding为
RoFormer提出Rotary PE,在embedding维度为2的情况下:
回忆下欧拉公式:
因此,上述函数
RoPE的2D实现
RoPE的n维实现
不同于经典Transformers结构,只对输入的token做位置编码的叠加
LlaMA中的RoPE在Transformer的每一层都会对Q和K进行位置编码的叠加
在深度学习中,tensor操作是构建模型的基础。理解各种tensor操作对于实现LLM等复杂模型至关重要。
view()
/ reshape()
- 改变tensor形状transpose()
/ permute()
- 转置和维度重排squeeze()
/ unsqueeze()
- 压缩/扩展维度matmul()
/ @
- 矩阵乘法bmm()
- 批量矩阵乘法einsum()
- 爱因斯坦求和约定contiguous()
gather()
/ scatter()
- 按索引收集/分散index_select()
- 按索引选择masked_select()
- 按掩码选择view()
: 返回与原tensor共享存储的新视图,要求tensor在内存中连续reshape()
: 如果可能则返回view,否则返回副本# view() - 要求tensor连续
x = torch.randn(2, 3, 4)
y = x.view(6, 4) # 成功:2*3=6
# 如果tensor不连续,view()会报错
x_transposed = x.transpose(0, 1) # 不连续
# y = x_transposed.view(12, 2) # 报错!
# reshape() - 自动处理连续性问题
y = x_transposed.reshape(12, 2) # 成功:自动处理
transpose() - 交换两个维度
x = torch.randn(2, 3, 4, 5)
y = x.transpose(1, 3) # 交换维度1和3
print(x.shape) # torch.Size([2, 3, 4, 5])
print(y.shape) # torch.Size([2, 5, 4, 3])
permute() - 重新排列所有维度
x = torch.randn(2, 3, 4, 5)
y = x.permute(0, 3, 1, 2) # 重新排列维度
print(x.shape) # torch.Size([2, 3, 4, 5])
print(y.shape) # torch.Size([2, 5, 3, 4])
squeeze() - 移除大小为1的维度
x = torch.randn(1, 3, 1, 4)
y = x.squeeze() # 移除所有大小为1的维度
z = x.squeeze(0) # 只移除第0维
print(x.shape) # torch.Size([1, 3, 1, 4])
print(y.shape) # torch.Size([3, 4])
print(z.shape) # torch.Size([3, 1, 4])
unsqueeze() - 在指定位置插入大小为1的维度
x = torch.randn(3, 4)
y = x.unsqueeze(0) # 在第0维插入
z = x.unsqueeze(-1) # 在最后一维插入
print(x.shape) # torch.Size([3, 4])
print(y.shape) # torch.Size([1, 3, 4])
print(z.shape) # torch.Size([3, 4, 1])
Broadcasting是PyTorch中一种强大的机制,允许不同形状的tensor进行运算。它遵循以下规则:
# 示例1: 标量与tensor
a = torch.tensor([1, 2, 3])
b = 2
c = a + b # [3, 4, 5] - 标量自动广播到每个元素
# 示例2: 不同形状的tensor
A = torch.randn(3, 4) # [3, 4]
B = torch.randn(4) # [4]
C = A + B # [3, 4] - B自动扩展为[1, 4]然后[3, 4]
# 示例3: 更复杂的广播
A = torch.randn(2, 3, 4) # [2, 3, 4]
B = torch.randn(3, 1) # [3, 1]
C = A + B # [2, 3, 4] - B扩展为[1, 3, 1]然后[2, 3, 4]
# 1. 添加偏置项
x = torch.randn(32, 128) # [batch_size, features]
bias = torch.randn(128) # [features]
y = x + bias # 每个样本都加上相同的偏置
# 2. 注意力机制中的mask
scores = torch.randn(2, 8, 8) # [batch, seq_len, seq_len]
mask = torch.tensor([1, 1, 1, 0, 0, 0, 0, 0]) # [seq_len]
masked_scores = scores + mask.unsqueeze(0).unsqueeze(0) # 广播到[2, 8, 8]
# 3. 批量归一化
x = torch.randn(32, 64, 28, 28) # [batch, channels, height, width]
mean = torch.mean(x, dim=(0, 2, 3), keepdim=True) # [1, 64, 1, 1]
normalized = (x - mean) / torch.std(x, dim=(0, 2, 3), keepdim=True)
不同矩阵乘法的使用场景
torch.matmul()
/ @
: 通用矩阵乘法,支持广播torch.bmm()
: 批量矩阵乘法,专门用于3D tensortorch.mm()
: 2D矩阵乘法# 批量矩阵乘法
A_batch = torch.randn(2, 3, 4)
B_batch = torch.randn(2, 4, 5)
C_batch = torch.bmm(A_batch, B_batch)
print(C_batch.shape) # torch.Size([2, 3, 5])
einsum提供了一种简洁的方式来表达复杂的tensor操作:
# 矩阵乘法: C[i,j] = sum_k A[i,k] * B[k,j]
A = torch.randn(3, 4)
B = torch.randn(4, 5)
C = torch.einsum('ik,kj->ij', A, B)
# 批量矩阵乘法
A_batch = torch.randn(2, 3, 4)
B_batch = torch.randn(2, 4, 5)
C_batch = torch.einsum('bik,bkj->bij', A_batch, B_batch)
# 注意力机制中的QK^T计算
Q = torch.randn(2, 8, 64) # [batch, seq_len, d_model]
K = torch.randn(2, 8, 64)
scores = torch.einsum('bqd,bkd->bqk', Q, K)
gather() - 按索引收集元素
# 在指定维度上按索引收集元素
x = torch.randn(3, 4)
indices = torch.tensor([0, 2, 1])
y = torch.gather(x, 1, indices.unsqueeze(1))
print(x)
print(y) # 每行按indices选择元素
# 将元素分散到指定位置
x = torch.zeros(3, 4)
values = torch.randn(3, 2)
indices = torch.tensor([[0, 2], [1, 3], [0, 1]])
x.scatter_(1, indices, values)
print(x)
Hugging Face
Accelerating a Hugging Face Llama 2 and Llama 3 models with Transformer Engine
RoPE部分
Transformer升级之路:10、RoPE是一种β进制编码. 苏剑林
RoFormer: Enhanced Transformer with Rotary Position Embedding
PyTorch Tensor操作
PyTorch官方文档 - Tensor操作
Einops库 - 更优雅的tensor操作
https://marp.app/
<p align="center"> <img width="500" height="200" src="images/l4/nju.png"> <img width="500" height="200" src="images/l4/nju2.png"> </p>

