截断拼接?模型输入很长怎么办?推理的时候和训练的时候
P1 · llm_training
📊 考点:inference · training
🏷 标签:long-input, truncation, sliding-window
1️⃣ 考察意图
面试官想考察你对 LLM 长输入处理的工程落地能力,而非单纯背诵概念。核心是区分训练和推理两个阶段的根本差异:训练时关注数据利用率与计算效率,推理时关注延迟与信息完整性。刁钻点在于:候选人常混淆两者策略,或只知截断不知更优方案。答好了能展示你对 tokenization、batch 构建、注意力机制开销的深刻理解,以及处理真实长文本场景(如文档问答、对话历史)的实战经验。
2️⃣ 标准答
训练阶段:核心是数据效率与计算约束
- 截断拼接(Truncation + Concatenation):将多个短文本拼接到最大长度(如 4096 tokens),用
[SEP]或[EOS]分隔。这是预训练和微调的主流做法,因为能最大化 GPU 利用率。坑:拼接后不同样本间可能产生跨文档注意力,导致信息泄露。解法:在 attention mask 中设置分段掩码,或使用document_mask隔离不同样本。 - 动态批处理(Dynamic Batching):按实际序列长度分组,而非固定长度。例如,用
torch.nn.utils.rnn.pad_sequence填充到组内最大长度。Trade-off:减少无效 padding 计算,但增加调度复杂度,需要实现 bucket 策略(如 512、1024、2048 分桶)。 - 滑动窗口训练(Sliding Window):将超长文档(如 100k tokens)切分为重叠窗口(窗口大小 4096,步长 2048)。这用于长上下文模型(如 Longformer、BigBird)的预训练。为什么这么做:避免截断丢失全局信息,但训练成本线性增长,需配合梯度累积。
- 实际落地的坑:训练时若使用截断,需确保截断策略与下游任务一致。例如,在对话数据中,截断尾部(保留最近对话)比截断头部更合理;在文档分类中,截断头部(保留开头摘要)更优。解法:在数据预处理阶段,根据任务类型动态选择截断位置(如
truncation_side='left'或'right')。
推理阶段:核心是延迟与信息完整性
- 截断(Truncation):直接丢弃超长部分。适用场景:实时对话系统(如客服机器人),延迟敏感,且历史信息可被压缩。坑:丢弃关键信息导致回答质量下降。解法:结合关键句提取(如 TextRank 或基于 embedding 的相似度过滤),先压缩再截断。
- 滑动窗口推理(Sliding Window):将输入分块,每块独立推理后聚合结果。例如,在长文档问答中,将 10k tokens 文档切为 3 个 4k 窗口(重叠 1k),每个窗口生成候选答案,再用投票或 reranker 选择最佳。Trade-off:增加推理延迟(O(n) 复杂度),但保留完整信息。实际落地的坑:窗口间上下文不连续,导致答案矛盾。解法:使用
StreamingLLM或KV cache复用技术,在窗口间保留关键 token 的注意力状态。 - 流式处理(Streaming):适用于无限长输入(如实时日志分析)。使用
StreamingLLM方法,维护一个固定大小的注意力池(如 256 tokens),只保留最近和最重要的 token。为什么这么做:避免 O(n²) 注意力计算,将复杂度降为 O(n)。实际落地的坑:注意力池的更新策略需精心设计,否则丢失长程依赖。解法:结合H2O(Heavy Hitter Oracle)方法,动态识别高频注意力 token 并保留。 - 关键句提取 + 压缩:先用轻量模型(如
BERT或TF-IDF)提取关键句子,再送入 LLM。适用场景:文档摘要、法律合同分析。Trade-off:增加预处理延迟,但显著降低 LLM 推理成本。实际落地的坑:提取模型可能遗漏关键细节。解法:使用Cohere Rerank或Cross-Encoder对候选句子重排序,确保召回率。
训练与推理的一致性:必须确保训练时的截断/窗口策略与推理时一致,否则产生分布偏移。例如,训练时用尾部截断,推理时用头部截断,模型会困惑于输入格式。解法:在模型配置中固定 truncation_side 和 max_length,并在 tokenizer 中显式设置。
3️⃣ 答题模板(30 秒电梯版)
“这个问题我从训练和推理两个阶段分别回答。训练阶段,核心是数据效率,常用截断拼接和动态批处理,但需注意跨文档注意力泄露和截断策略一致性。推理阶段,核心是延迟与信息完整性,可选截断、滑动窗口或流式处理,具体取决于任务场景。总结一句:训练时优先保证计算效率,推理时优先保证信息完整性,且两者截断策略必须对齐。”
4️⃣ 高频追问 & 应对
追问 1:滑动窗口推理时,窗口重叠大小怎么选?有没有理论依据?
重叠大小取决于任务类型。对于问答任务,建议重叠 20-30% 窗口大小(如 4k 窗口重叠 1k),确保关键实体不被切分。理论依据是:窗口边界处注意力衰减最快,重叠可补偿边界信息丢失。实际中,可通过实验调优:在验证集上测试不同重叠比例(10%、20%、30%),选择 F1 分数最高的值。注意:重叠越大,推理延迟越高,需平衡。
追问 2:训练时用截断拼接,如何避免不同样本间的注意力干扰?
核心是使用
attention_mask隔离。具体做法:在拼接时,为每个样本分配独立的注意力掩码,例如[1,1,1,0,0,0,1,1,1,0,0,0],其中 0 表示分隔符或 padding。更高级的做法是使用document_mask,在 Transformer 的forward函数中传入document_ids,让模型只计算同文档内的注意力。这需要修改模型代码,但能彻底避免信息泄露。
追问 3:流式处理中,StreamingLLM 的注意力池大小怎么确定?有没有替代方案?
注意力池大小通常设为 256-512 tokens,取决于模型层数和任务复杂度。理论依据是:注意力分布是长尾的,少量 token 占据大部分注意力权重。替代方案包括
H2O(保留高频注意力 token)和Scissorhands(基于梯度剪枝)。实际落地时,建议在目标数据集上测试不同池大小(128、256、512),选择困惑度最低且延迟可接受的值。
5️⃣ 避坑 · 常见错误答法
- ❌ 回答“训练和推理都用截断,直接丢掉超长部分就行” → ✅ 正确切入:训练时截断需考虑数据利用率,可结合拼接或滑动窗口;推理时截断需结合关键句提取,避免信息丢失。
- ❌ 回答“滑动窗口推理时,窗口大小和步长随便设,反正能覆盖所有内容” → ✅ 正确切入:窗口大小受模型最大长度限制(如 4096),步长需考虑重叠比例,避免边界信息丢失,且需评估延迟开销。
- ❌ 回答“流式处理只适用于推理,训练用不了” → ✅ 正确切入:流式处理也可用于训练,例如
LongNet的 dilated attention,但需修改训练框架支持动态序列长度。
6️⃣ 简历呼应
- 如果你有 RAG 项目:从文档分块和检索后拼接切入,强调训练时如何构建 chunk 拼接数据(如
[DOC]分隔符),推理时如何用滑动窗口处理超长检索结果。 - 如果你只做过传统 NLP:用序列标注任务类比,训练时如何 padding 和截断(如
BERT的max_length),推理时如何用滑动窗口处理长文本(如BiLSTM-CRF的 chunk 推理)。 - 如果你是校招无项目:聚焦论文复现,如
Longformer的滑动窗口注意力,或StreamingLLM的注意力池实现,展示对长输入处理的原理理解。
7️⃣ 延伸阅读
- Longformer: The Long-Document Transformer(Beltagy et al., 2020)
- StreamingLLM: Efficient Streaming Language Models with Attention Sinks(Xiao et al., 2023)
- H2O: Heavy-Hitter Oracle for Efficient Generative Inference of Large Language Models(Liu et al., 2023)
- Hugging Face Tokenizer 文档:truncation_side 和 max_length 参数详解
- Cohere Rerank API 文档:用于关键句重排序的实践指南