关于 long-context
面向模型开发者和实践者的 Transformer 上下文窗口扩展指南,介绍 RoPE、YaRN、ALiBi 和位置插值,并提供实现、微调与部署建议。
主要功能
- 01RoPE 与 YaRN 技术
- 02ALiBi 与位置插值
- 03实现示例与参考资料
- 04微调和部署指南
适用场景
- 01扩展预训练模型的上下文
- 02使用 Transformer 处理长文档
- 03训练具备长度外推能力的模型
- 04部署可处理可变长度输入的模型
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ kalarislabs/ research-agent-skills --skill long-context安装后在 Claude Code 中输入/long-context确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/extension_methods.mdfine_tuning.mdimplementation-patterns.mdrope.md详细介绍
长上下文:扩展 Transformer 上下文窗口
何时使用此技能
当你需要以下操作时,请使用长上下文技术:
- 处理长文档(32k、64k、128k+ 个 token),并使用 Transformer 模型
- 扩展预训练模型(LLaMA、Mistral 等)的上下文窗口
- 实现高效的位置编码(RoPE、ALiBi)
- 训练具备长度外推能力的模型
- 部署能够高效处理可变长度输入的模型
- 微调现有模型,以尽可能少的计算资源支持更长上下文
关键技术:RoPE(旋转位置嵌入)、YaRN、ALiBi(线性偏置注意力)、位置插值
论文:RoFormer(arXiv 2104.09864)、YaRN(arXiv 2309.00071)、ALiBi(arXiv 2108.12409)、位置插值(arXiv 2306.15595)
安装
# HuggingFace Transformers (includes RoPE, YaRN support)
pip install transformers torch
# For custom implementations
pip install einops # Tensor operations
pip install rotary-embedding-torch # Standalone RoPE
# Optional: FlashAttention for efficiency
pip install flash-attn --no-build-isolation
快速开始
RoPE(旋转位置嵌入)
import torch
import torch.nn as nn
class RotaryEmbedding(nn.Module):
"""Rotary Position Embeddings (RoPE)."""
def __init__(self, dim, max_seq_len=8192, base=10000):
super().__init__()
# Compute inverse frequencies
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))
self.register_buffer("inv_freq", inv_freq)
self.max_seq_len = max_seq_len
def forward(self, seq_len, device):
# Position indices
t = torch.arange(seq_len, device=device).type_as(self.inv_freq)
# Compute frequencies
freqs = torch.outer(t, self.inv_freq) # (seq_len, dim/2)
# Compute sin and cos
emb = torch.cat((freqs, freqs), dim=-1) # (seq_len, dim)
return emb.cos(), emb.sin()
def rotate_half(x):
"""Rotate half the hidden dimensions."""
x1, x2 = x.chunk(2, dim=-1)
return torch.cat((-x2, x1), dim=-1)
def apply_rotary_pos_emb(q, k, cos, sin):
"""Apply rotary embeddings to queries and keys."""
# q, k shape: (batch, heads, seq_len, dim)
q_embed = (q * cos) + (rotate_half(q) * sin)
k_embed = (k * cos) + (rotate_half(k) * sin)
return q_embed, k_embed
# Usage
rope = RotaryEmbedding(dim=64, max_seq_len=8192)
cos, sin = rope(seq_len=2048, device='cuda')
# In attention layer
q_rotated, k_rotated = apply_rotary_pos_emb(query, key, cos, sin)
ALiBi(线性偏置注意力)
def get_alibi_slopes(num_heads):
"""Get ALiBi slope values for each attention head."""
def get_slopes_power_of_2(n):
start = 2 ** (-(2 ** -(math.log2(n) - 3)))
ratio = start
return [start * (ratio ** i) for i in range(n)]
if math.log2(num_heads).is_integer():
return get_slopes_power_of_2(num_heads)
else:
# Closest power of 2
closest_power = 2 ** math.floor(math.log2(num_heads))
slopes = get_slopes_power_of_2(closest_power)
# Add extra slopes
extra = get_slopes_power_of_2(2 * closest_power)
slopes.extend(extra[0::2][:num_heads - closest_power])
return slopes
def create_alibi_bias(seq_len, num_heads):
"""Create ALiBi attention bias."""
# Distance matrix
context_position = torch.arange(seq_len)
memory_position = torch.arange(seq_len)
relative_position = memory_position[None, :] - context_position[:, None]
# Get slopes
slopes = torch.tensor(get_alibi_slopes(num_heads))
# Apply slopes to distances
alibi = slopes[:, None, None] * relative_position[None, :, :]
return alibi # (num_heads, seq_len, seq_len)
# Usage in attention
num_heads = 8
seq_len = 2048
alibi_bias = create_alibi_bias(seq_len, num_heads).to('cuda')
# Add bias to attention scores
# attn_scores shape: (batch, num_heads, seq_len, seq_len)
attn_scores = attn_scores + alibi_bias
attn_weights = torch.softmax(attn_scores, dim=-1)
LLaMA 的位置插值
from transformers import LlamaForCausalLM, LlamaTokenizer
# Original context: 2048 tokens
model = LlamaForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf")
# Extend to 32k with position interpolation
# Modify RoPE base frequency
model.config.rope_scaling = {
"type": "linear",
"factor": 16.0 # 2048 * 16 = 32768
}
# Or use dynamic scaling
model.config.rope_scaling = {
"type": "dynamic",
"factor": 16.0
}
# Fine-tune with long documents (minimal steps needed)
# Position interpolation works out-of-the-box after this config change
核心概念
1. RoPE(旋转位置嵌入)
工作原理:
- 通过旋转矩阵编码绝对位置
- 在注意力中提供相对位置依赖
- 支持长度外推
数学公式:
q_m = (W_q * x_m) * e^(imθ)
k_n = (W_k * x_n) * e^(inθ)
where θ_j = base^(-2j/d) for j ∈ [0, d/2)
优势:
- token 间依赖会随距离增加而衰减
- 兼容线性注意力
- 比绝对位置编码具有更好的外推能力
2. YaRN(又一种 RoPE 扩展方法)
关键创新:
- 感知 NTK(神经切线核)的插值
- 注意力温度缩放
- 高效扩展上下文(相比基线方法,所需 token 减少 10×)
参数:
# YaRN configuration
yarn_config = {
"scale": 16, # Extension factor
"original_max_position": 2048, # Base context
"extrapolation_factor": 1.0, # NTK parameter
"attn_factor": 1.0, # Attention scaling
"beta_fast": 32, # High-frequency scale
"beta_slow": 1, # Low-frequency scale
}
性能:
- 将 LLaMA 扩展至 128k 个 token
- 比基线方法少 2.5× 的训练步数
- 上下文窗口扩展领域的最先进方法
3. ALiBi(线性偏置注意力)
核心思路:
- 不向 token 添加位置嵌入
- 直接对注意力分数施加距离惩罚
- 偏置与键和查询之间的距离成正比
公式:
attention_bias[i, j] = -m * |i - j|
where m = slope for each attention head
优势:
- 比正弦嵌入快 11% 的训练速度
- 内存用量减少 11%
- 具有很强的长度外推能力(用 1k 训练,用 2k+ 测试)
- 具有偏向近期内容的归纳偏置
4. 位置插值
技术:
- 线性缩小位置索引
- 在训练范围内插值(而非向范围外外推)
- 只需少量微调
公式:
# Original: position indices [0, 1, 2, ..., L]
# Extended: position indices [0, 0.5, 1.0, ..., L/2]
# (for 2× extension)
scaled_position[i] = i / extension_factor
结果:
- 将 LLaMA 7B-65B 扩展至 32k 个 token
- 1000 个微调步数即可满足需求
- 稳定性比外推高 600×
方法对比
| 方法 | 最大上下文 | 是否需要训练 | 内存 | 外推能力 | 最适用场景 |
|---|---|---|---|---|---|
| RoPE | 8k-32k | 完整预训练 | 中等 | 良好 | 新模型 |
| YaRN | 32k-128k | 少量(效率高 10×) | 中等 | 极佳 | 扩展现有模型 |
| ALiBi | 无限 | 完整预训练 | 低(-11%) | 极佳 | 从头训练 |
| 位置插值 | 32k+ | 少量(1000 步) | 中等 | 较差(有意为之) | 快速扩展 |
实现模式
详细说明、代码示例和参数表:references/implementation-patterns.md。适用此步骤时请阅读。
长上下文微调
少量微调(位置插值)
from transformers import Trainer, TrainingArguments
# Extend model config
model.config.max_position_embeddings = 32768
model.config.rope_scaling = {"type": "linear", "factor": 16.0}
# Training args (minimal steps needed)
training_args = TrainingArguments(
output_dir="./llama-32k",
num_train_epochs=1,
max_steps=1000, # Only 1000 steps!
per_device_train_batch_size=1,
gradient_accumulation_steps=16,
learning_rate=2e-5,
warmup_steps=100,
logging_steps=10,
save_steps=500,
)
# Train on long documents
trainer = Trainer(
model=model,
args=training_args,
train_dataset=long_document_dataset, # 32k token sequences
)
trainer.train()
YaRN 微调
# Clone YaRN implementation
git clone https://github.com/jquesnelle/yarn
cd yarn
# Fine-tune LLaMA with YaRN
python scripts/train.py \
--model meta-llama/Llama-2-7b-hf \
--scale 16 \
--rope_theta 10000 \
--max_length 32768 \
--batch_size 1 \
--gradient_accumulation 16 \
--steps 400 \
--learning_rate 2e-5
最佳实践
1. 选择合适的方法
# For NEW models (training from scratch)
use_method = "ALiBi" # Best extrapolation, lowest memory
# For EXTENDING existing RoPE models
use_method = "YaRN" # Most efficient extension (10× less data)
# For QUICK extension with minimal compute
use_method = "Position Interpolation" # 1000 steps
# For MODERATE extension with good efficiency
use_method = "Linear RoPE Scaling" # Built-in, simple
2. 选择缩放因子
# Conservative (safer, better quality)
scaling_factor = 2.0 # 8k → 16k
# Moderate (good balance)
scaling_factor = 4.0 # 8k → 32k
# Aggressive (requires more fine-tuning)
scaling_factor = 8.0 # 8k → 64k
scaling_factor = 16.0 # 8k → 128k
# Rule: Larger factors need more fine-tuning steps
steps_needed = 100 * scaling_factor # Rough estimate
3. 微调数据
# ✅ Good: Long documents matching target length
train_data = [
{"text": long_doc_32k_tokens}, # Full 32k
{"text": long_doc_24k_tokens}, # Varied lengths
{"text": long_doc_16k_tokens},
]
# ❌ Bad: Short documents (won't learn long context)
train_data = [
{"text": short_doc_2k_tokens},
]
# Use datasets like:
# - PG-19 (books, long texts)
# - arXiv papers
# - Long-form conversations
# - GitHub repositories (concatenated files)
4. 避免常见问题
# ❌ Bad: Applying position interpolation without fine-tuning
model.config.rope_scaling = {"type": "linear", "factor": 16.0}
# Model will perform poorly without fine-tuning!
# ✅ Good: Fine-tune after scaling
model.config.rope_scaling = {"type": "linear", "factor": 16.0}
fine_tune(model, long_documents, steps=1000)
# ❌ Bad: Too aggressive scaling without data
scale_to_1M_tokens() # Won't work without massive fine-tuning
# ✅ Good: Incremental scaling
# 8k → 16k → 32k → 64k (fine-tune at each step)
生产部署
长上下文推理
from transformers import AutoModelForCausalLM, AutoTokenizer
# Load long-context model
model = AutoModelForCausalLM.from_pretrained(
"togethercomputer/LLaMA-2-7B-32K", # 32k context
torch_dtype=torch.float16,
device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained("togethercomputer/LLaMA-2-7B-32K")
# Process long document
long_text = "..." * 30000 # 30k tokens
inputs = tokenizer(long_text, return_tensors="pt", truncation=False).to('cuda')
# Generate
outputs = model.generate(
**inputs,
max_new_tokens=512,
temperature=0.7,
)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
内存优化
# Use gradient checkpointing for fine-tuning
model.gradient_checkpointing_enable()
# Use Flash Attention 2
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
attn_implementation="flash_attention_2", # 2-3× faster
torch_dtype=torch.float16
)
# Use paged attention (vLLM)
from vllm import LLM
llm = LLM(
model="togethercomputer/LLaMA-2-7B-32K",
max_model_len=32768, # 32k context
gpu_memory_utilization=0.9
)
资源
- RoPE 论文:https://arxiv.org/abs/2104.09864 (RoFormer)
- YaRN 论文:https://arxiv.org/abs/2309.00071
- ALiBi 论文:https://arxiv.org/abs/2108.12409 (Train Short, Test Long)
- 位置插值:https://arxiv.org/abs/2306.15595
- HuggingFace RoPE 工具:https://github.com/huggingface/transformers/blob/main/src/transformers/modeling_rope_utils.py
- YaRN 实现:https://github.com/jquesnelle/yarn
- Together AI 博客:https://www.together.ai/blog/llama-2-7b-32k
另请参阅
references/rope.md- RoPE 实现与理论详解references/extension_methods.md- YaRN、ALiBi、位置插值对比references/fine_tuning.md- 上下文扩展完整微调指南
Agent 操作流程
- 检查环境。 确认 GPU 内存、模型检查点和许可证、框架版本及输入格式。
- 明确输入。 根据数据或用户确认格式、标识符和参数。任何会影响结果的值都应询问,不要猜测。
- 先运行小规模版本。 先对单个样本以低分辨率或较短长度运行推理。
- 使用上述说明和参考资料执行完整任务。
- 验证结果。 使用定性方式和任务指标检查输出;检查生成内容的许可证限制。
- 报告。 说明运行了什么(版本、命令、参数)、检查了什么,以及仍有哪些不确定之处。
| 如果发生这种情况 | 请这样做 |
|---|---|
| 大型输入导致内存不足 | 降低分辨率或序列长度、使用半精度,或对输入进行分块。 |
| 这些说明中的函数、标志或端点在已安装版本中不存在 | 查阅已安装版本自身的文档(help()、--help、官方文档),进行适配并告知用户。切勿虚构 API。 |
| 必需的输入、标识符或参数不明确 | 询问用户,或在运行前明确说明假设。 |
诚信准则
- 切勿捏造结果、参数、标识符、引用或统计数据。如果无法运行或验证某项内容,请如实说明。
- 在商业用途或发布内容前,检查模型和数据集许可证。
- 将此处与版本相关的细节视为可能已过时:请对照已安装版本的官方文档进行确认。
- 对于会产生费用、占用共享 GPU 或云配额、涉及个人或患者数据,或无法撤销的操作,须先征得同意。
评论
支持 Markdown