3、推理流水线概述:从输入prompt到输出文本的完整流程
大模型推理(Inference)并非简单的"输入一句话、输出一句话"的黑盒操作,而是一条由多个阶段紧密衔接的工程流水线。从用户输入原始文本(Prompt)到最终流式呈现的文本(Output),中间涉及文本预处理、化、模型前向计算、采样策略、后处理与流式传输等多个环节。理解这条流水线的整体架构,是进行性能调优、故障排查和二次开发的基础。本章将完整拆解这一过程,并重点剖析各阶段的功能、瓶颈与工程实现要点。
上图展示了推理流水线的四个核心阶段及其循环关系。在实际工程中,TGI(Text Generation Inference)等框架会将上述流程封装为高并发的服务,并引入Continuous Batching、Paged Attention等优化技术。下面我们逐一深入每个阶段的原理与实现细节。
3.1 预处理阶段:从原始文本到 IDs
核心原理:预处理是将人类可读的文本转换为模型可计算的数值向量的第一步。大模型通常使用BPE(Byte Pair Encoding)或SentencePiece等子词分词算法,将文本切分为序列。每个对应词表中的唯一ID。预处理阶段还需处理特殊(如<bos>、<eos>、<pad>),并生成Attention Mask以区分真实与填充。
操作流程:
- 文本清洗:去除不可见字符、统一换行符、处理BOM头,确保输入编码为UTF-8。
- 截断与填充:若输入超过模型最大上下文长度(如4096),需进行头部保留或尾部截断策略;批量推理时,短序列需填充至Batch内最大长度。
- Tokenize:调用分词器将文本转为 IDs列表,同时记录与原始字符的偏移映射(用于后续高亮或溯源)。
- 构造模型输入:生成
input_ids、attention_mask,部分模型还需position_ids。
['请','解释','量子','纠缠'],对应IDs为 [102, 356, 789, 2345]。若Batch内另一条输入更长,则短序列末尾填充<pad>(ID=0),Attention Mask对应位置置0,防止模型关注填充位。
| 预处理组件 | 输入 | 输出 | 典型耗时占比 |
|---|---|---|---|
| 文本清洗 | 原始字符串 | 规范化字符串 | <1ms |
| 分词器 | 规范化字符串 | IDs + 偏移量 | 1-5ms |
| 批处理组装 | 多条序列 | Padding后的张量 | <1ms |
attention_mask会导致模型对Padding位置计算注意力,产生无效计算并可能引入噪声。此外,不同分词器对空格、标点的处理规则不同,跨语言场景需验证分词一致性。
3.2 模型前向计算:从到Logits
核心原理:模型前向是推理流水线的计算核心。 IDs首先经过Embedding层映射为稠密向量,随后逐层通过Transformer Block(包含Self-Attention、Feed-Forward、LayerNorm等子层)。在自回归解码中,每一步仅生成一个,但需要将当前序列的所有重新输入模型计算。为加速推理,TGI等框架引入了KV-Cache技术,缓存历史的Key和Value矩阵,避免重复计算。
计算流程:
- Embedding Lookup:从词表矩阵中取出对应的向量,维度通常为
hidden_size(如4096)。 - Transformer Layers:每个Layer包含多头自注意力(MHA)或分组查询注意力(GQA)、前馈网络(FFN)。计算量随序列长度平方增长(注意力部分),但KV-Cache将增量计算降为线性。
- 输出投影:最后一层输出经LM Head(权重与Embedding共享或独立)映射为词表大小的Logits向量。
# 伪代码示意(TGI内部逻辑)
for step in range(max_new_tokens):
if step == 0:
kv_cache = None
logits, kv_cache = model(input_ids, past_key_values=kv_cache)
next_ = sample(logits[:, -1, :]) # 仅取最后一个位置的Logits
input_ids = torch.cat([input_ids, next_], dim=-1)
if next_ == eos__id:
break
| 计算组件 | 计算量复杂度 | 显存占用 | 优化手段 |
|---|---|---|---|
| Self-Attention | O(n²·d) | O(n²) 中间矩阵 | FlashAttention、PagedAttention |
| FFN | O(n·d²) | O(n·d) | MoE稀疏激活 |
| KV-Cache | O(n·d·layers) | O(n·d·layers·2) | 量化、GQA、窗口注意力 |
--max-batch-total-tokens参数限制总数,超出时触发调度等待。
3.3 采样与解码策略:从Logits到下一个
核心原理:模型输出的Logits是一个未归一化的分数向量,需通过采样策略决定最终选择的 ID。采样策略直接影响生成文本的多样性、连贯性和创造性。TGI支持多种策略,包括Greedy Search、Temperature采样、Top-k、Top-p(核采样)以及Beam Search。
判断与操作流程:
- Logits缩放:将Logits除以Temperature参数(T)。T>1使分布更平滑(增加随机性),T<1使分布更尖锐(趋于确定性)。
- Top-k过滤:仅保留概率最高的k个,其余置为负无穷。
- Top-p过滤:按概率从高到低累加,直到累计概率超过p,保留该集合内的。
- Softmax归一化:将过滤后的Logits转为概率分布。
- 随机采样:从分布中抽取一个 ID。
# TGI 请求参数示例
{
"inputs": "请写一首关于春天的诗",
"parameters": {
"temperature": 0.8,
"top_k": 50,
"top_p": 0.95,
"max_new_tokens": 128,
"repetition_penalty": 1.1
}
}
[2.0, 1.0, 0.5, -1.0],T=0.5时缩放为 [4.0, 2.0, 1.0, -2.0],Softmax后概率约为 [0.84, 0.11, 0.04, 0.01]。若Top-p=0.9,则保留前两个(累计概率0.95),第三个被过滤。最终采样结果大概率是第一个,但仍有小概率选第二个,从而增加多样性。
| 策略 | 特点 | 适用场景 | 风险 |
|---|---|---|---|
| Greedy | 确定性最高 | 代码生成、数学推理 | 易重复、缺乏创意 |
| Temperature | 全局调节随机性 | 对话、故事生成 | 过高导致胡言乱语 |
| Top-k | 限制候选集大小 | 通用场景 | k值固定,动态性差 |
| Top-p | 动态候选集 | 创意写作 | 与Temperature叠加需调参 |
3.4 后处理与流式输出:从 IDs到用户可见文本
核心原理:模型生成的 IDs需经过Detokenize还原为文本,并过滤特殊(如<eos>、<pad>)。流式输出则是在生成过程中逐或逐片段地将文本推送给客户端,显著降低首延迟(TTFT)的感知,提升交互体验。
实现流程:
- 增量Detokenize:由于一个可能对应半个字符(如UTF-8多字节字符),需维护一个解码缓冲区,等待完整字符后再输出。
- 特殊处理:移除
<eos>、<bos>,将<unk>替换为占位符或保留原文。 - 流式传输:基于SSE(Server-Sent Events)或WebSocket,将增量文本封装为事件推送。TGI支持
stream=true参数,返回data: {"": {"text": "..."}}\n\n格式。
# 流式响应示例(SSE格式)
data: {"": {"text": "春天"}}
data: {"": {"text": "来了"}}
data: {"": {"text": ",万物"}}
data: {"": {"text": "复苏"}}
data: {"finished": true, "generated_tokens": 4}
--max-stop-sequences可配置停止词,如遇到"用户:"时提前终止生成。
| 后处理环节 | 输入 | 输出 | 关键点 |
|---|---|---|---|
| Detokenize | IDs序列 | 拼接文本 | 处理字节级BPE的跨字符 |
| 特殊过滤 | 含控制的序列 | 纯净文本 | 保留<|assistant|>等角色标记 |
| 流式封装 | 增量文本 | SSE/WS帧 | 心跳保活、错误重传机制 |
--max-batch-prefill-tokens控制预填充阶段数,防止大Prompt阻塞小请求的流式响应。
3.5 全流程串联与性能调优要点
核心原理:推理流水线的整体性能取决于最慢阶段。预处理阶段通常为CPU密集型,模型前向为GPU密集型,采样与后处理为CPU与GPU混合。TGI通过异步流水线、Continuous Batching和CUDA Graph等技术,将各阶段重叠执行,最大化硬件利用率。
调优操作流程:
- 分析瓶颈:使用
nvidia-smi监控GPU利用率,若低于50%则可能受CPU预处理或采样拖累。 - 调整Batch策略:增大
--max-batch-total-tokens可提升吞吐,但会增加TTFT;需平衡SLA要求。 - 启用优化内核:开启FlashAttention、PagedAttention,可降低显存占用并加速注意力计算。
- 量化与剪枝:使用FP16/BF16混合精度,或INT8/INT4量化(如、AWQ),减少显存带宽压力。
max_new_tokens从512降至256;③使用Top-p=0.9替代Beam Search(Beam=4)。最终TTFT降至800ms,吞吐提升2.3倍,但生成质量略有下降(ROUGE-L从0.42降至0.39),通过增加repetition_penalty=1.15部分弥补。
| 优化手段 | 影响指标 | 代价 | 适用场景 |
|---|---|---|---|
| Continuous Batching | 吞吐↑,TTFT↓ | 调度复杂度↑ | 高并发在线服务 |
| KV-Cache量化 | 显存↓ | 精度轻微损失 | 长上下文场景 |
| 投机解码(Speculative Decoding) | TPOT↓ | 需草稿模型 | 自回归生成瓶颈 |
| CUDA Graph | 延迟↓ | 显存占用↑ | 固定Shape推理 |
--metrics-format=prometheus,监控tgi_request_duration、tgi_queue_size等指标,建立基准后逐步调整参数。同时,流式输出并非所有场景必需,离线批处理任务可关闭以简化日志与错误处理。