以下内容由Trae生成。我只管问和排版。
Nano-vLLM 是一个从零构建的轻量级vLLM实现项目,具备快速离线推理、代码可读性高和优化功能丰富等特点,性能表现和原版vLLM相媲美。以下是该项目各目录和文件的功能说明:
1. 根目录:
bench.py
:用于存放基准测试代码,可查看模型性能测试结果。example.py
:提供项目使用示例,展示API调用方法。pyproject.toml
:Python项目配置文件,管理项目依赖和元数据。
2. nanovllm目录:
__init__.py
:标识该目录为Python包。config.py
:定义配置类Config
,用于管理模型运行的各种参数。engine
子目录:存放推理引擎相关代码,包含block_manager.py
、llm_engine.py
、model_runner.py
、scheduler.py
和sequence.py
。layers
子目录:存放模型各层的实现代码,如激活层、注意力层等。llm.py
:可能实现LLM核心功能。models
子目录:存放特定模型的实现,如qwen3.py
。sampling_params.py
:可能用于定义采样参数。utils
子目录:存放工具函数,如context.py
和loader.py
。
一、engine 目录
engine目录负责推理引擎的实现,管理模型推理的整个流程,协调各组件工作。
Nano-vLLM engine推理引擎以模块化设计,主要由 LLMEngine
、ModelRunner
、Scheduler
、BlockManager
和 Sequence
几个核心组件构成,各组件分工协作完成推理任务。
核心组件及实现原理
-
Sequence(序列管理)
- 用于管理单个推理序列的状态和数据,包括 token ID、状态(等待、运行、完成)、缓存信息等。
- 提供了获取块数据、追加 token 等方法,方便对序列进行操作。
-
BlockManager(块管理)
- 负责管理缓存块的分配和释放,使用哈希算法来实现块的缓存,提高推理效率。
- 通过
hash_to_block_id
字典记录哈希值和块 ID 的映射关系,减少重复计算。 - 提供了分配、释放和追加块的方法,确保块资源的有效利用。
-
Scheduler(调度器)
- 负责管理待处理和正在运行的序列,根据资源限制和块管理状态进行序列调度。
- 分为预填充(prefill)和解码(decode)两个阶段调度序列,在资源不足时会抢占序列。
- 对推理结果进行后处理,更新序列状态并释放完成序列的资源。
-
ModelRunner(模型运行器)
- 负责初始化模型、预热模型、分配 KV 缓存等操作。
- 支持张量并行,使用共享内存进行进程间通信。
- 提供了准备输入数据、运行模型和采样等方法,支持 CUDA Graph 优化推理性能。
-
LLMEngine(推理引擎)
- 作为推理引擎的入口,负责初始化模型运行器、调度器和分词器。
- 提供添加请求、单步推理和生成结果等方法,支持进度显示和吞吐量统计。
- 使用多进程实现张量并行,提高推理速度。
推理流程
- 用户通过
LLMEngine.generate
方法添加推理请求。 Scheduler
将请求加入等待队列,并在资源充足时进行调度。ModelRunner
准备输入数据,调用模型进行推理,并使用Sampler
进行采样。BlockManager
管理缓存块,提高重复计算的效率。Scheduler
对推理结果进行后处理,更新序列状态,直到所有序列完成。
二、layers目录
layers 目录存放模型各基础层的实现代码,为模型提供基础的计算单元,保证模型能完成复杂的计算任务。从已有代码可知,该目录主要有以下功能:
1、激活层( activation.py )
激活层的作用是向神经网络中引入非线性因素,使得神经网络可以拟合复杂的非线性函数。
项目中实现了 SiluAndMul 激活层,对输入张量进行 SiLU 激活和元素乘法操作,引入非线性因素。代码如下:
class SiluAndMul(nn.Module):def __init__(self):super().__init__()@torch.compiledef forward(self, x: torch.Tensor) -> torch.Tensor:x, y = x.chunk(2, -1)return F.silu(x) * y
SiluAndMul 类继承自 nn.Module ,在 forward 方法中,先将输入张量 x 沿最后一个维度分成两部分,对第一部分应用 SiLU(Sigmoid Linear Unit)激活函数,再与第二部分进行元素乘法运算。
2、注意力层( attention.py ) :
注意力层是Transformer架构的核心组件,它允许模型在处理序列数据时,动态地关注序列中不同位置的信息。
项目中的 Attention 类实现了注意力机制,支持多头注意力机制,利用 Triton 优化 KV 缓存存储,结合 Flash Attention 提高计算效率。代码如下:
class Attention(nn.Module):def __init__(self,num_heads,head_dim,scale,num_kv_heads,):super().__init__()# ...已有代码...def forward(self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor):# ...已有代码...
Attention 类支持多头注意力机制,在 forward 方法中,根据上下文 context 的状态选择不同的注意力计算方式:
- prefill 阶段 :使用 flash_attn_varlen_func 计算注意力,支持前缀缓存(prefix cache)。
- decode 阶段 :使用 flash_attn_with_kvcache 结合KV缓存计算注意力。
此外,项目还使用 Triton 实现了 store_kvcache_kernel 核函数,用于将键(key)和值(value)存储到缓存中,提高计算效率。
3、采样(sampler.py)
项目里, Sampler 类是一个继承自 torch.nn.Module 的模块,用于实现采样操作。采样是从模型输出的概率分布中选取下一个 token 的过程,在自然语言处理里常用于生成文本。
从 sampler.py 文件可知, Sampler 类的 forward 方法接收 logits (模型未经过 softmax 的原始输出)和 temperatures 作为输入,实现了两种采样方式:
- 贪心采样(Greedy Sampling) :当 temperatures 为 0 时,直接选取 logits 中概率最大的 token。
- 基于温度调整的采样 :当 temperatures 不为 0 时,先对 logits 除以温度值,再通过 torch.softmax 转换为概率分布,最后结合指数分布对概率进行调整,选取调整后概率最大的 token。
这种采样机制可以在确定性输出(贪心采样)和随机性输出(基于温度调整的采样)之间进行平衡,从而控制生成文本的多样性。
4、嵌入层与语言模型头(embed_head.py)
- VocabParallelEmbedding 类 :实现了词表并行的嵌入层,支持在分布式环境下对词表进行分片处理,不同进程处理词表的不同部分,最后通过 all_reduce 操作汇总结果。
- ParallelLMHead 类 :继承自 VocabParallelEmbedding ,实现了并行的语言模型头。在 prefill 阶段会提取最后一个时间步的特征,然后进行线性变换得到对数几率(logits)。
5、归一化层(layernorm.py)
- RMSNorm 类 :实现了 Root Mean Square (RMS) 归一化。支持两种前向传播方式:一种是普通的 RMS 归一化,另一种是带有残差连接的 RMS 归一化。
6、线性层(linear.py)
- LinearBase 类 :线性层的基类,定义了线性层的基本属性和方法。
- ReplicatedLinear 类 :实现了普通的线性层,权重在所有进程中保持一致。
- ColumnParallelLinear 类 :实现了列并行的线性层,输出维度在不同进程间进行分片。
- MergedColumnParallelLinear 类 :继承自 ColumnParallelLinear ,支持将多个输出维度合并处理。
- QKVParallelLinear 类 :继承自 ColumnParallelLinear ,专门用于处理查询(Q)、键(K)、值(V)的并行线性变换。
- RowParallelLinear 类 :实现了行并行的线性层,输入维度在不同进程间进行分片,计算结果通过 all_reduce 操作汇总。
7、旋转位置编码层(rotary_embedding.py)
- RotaryEmbedding 类 :实现了旋转位置编码(Rotary Position Embedding, RoPE),通过正弦和余弦函数为查询(query)和键(key)添加位置信息。
- get_rope 函数 :用于获取 RotaryEmbedding 实例,使用 lru_cache 缓存实例,避免重复创建。
layers构建语言模型推理链路流程
- 输入处理阶段
- 嵌入层( embed_head.py ) :将输入token转换为连续向量表示(词嵌入),是模型处理的起点。
- 位置编码( rotary_embedding.py ) :通过旋转位置编码(RoPE)为嵌入向量添加位置信息,使模型能感知序列顺序(如 apply_rotary_emb 函数实现)。
- 特征提取与变换阶段
- 注意力层( attention.py ) :利用带位置信息的嵌入向量,通过多头注意力机制计算上下文依赖(如 flash_attn_varlen_func 处理前缀缓存, flash_attn_with_kvcache 结合KV缓存优化推理)。
- 激活层( activation.py ) :在注意力输出或前馈网络中应用SiLU激活函数(如 SiluAndMul 层将输入分块后执行 F.silu(x) * y ),增强模型非线性表达能力。
- 线性变换层( linear.py ) :通过 ColumnParallelLinear / RowParallelLinear 等并行线性层,完成向量空间的线性变换(如QKV投影、前馈网络映射)。
- 归一化层( layernorm.py ) :使用 RMSNorm 对各层输出进行归一化(如 rms_forward 方法),稳定训练过程。
- 输出生成阶段
- 采样器( sampler.py ) :基于模型最终输出的logits,通过贪心采样或温度调整采样选择下一个token(如 temperatures=0 时选最大概率token,非0时缩放logits后softmax)。
协作核心机制
各层通过 engine 模块的 ModelRunner 和 LLMEngine 协调:
- ModelRunner 初始化时为注意力层分配共享KV缓存( k_cache / v_cache 属性),并通过 context 对象传递 slot_mapping 等元数据(如 attention.py 中 context = get_context() 获取状态)。
- LLMEngine 调度请求,根据 context.is_prefill 标志切换注意力层计算模式(前缀填充/单步解码),确保各层在正确上下文(如内存管理、并行策略)中执行。
综上, layers 的基础层通过“输入处理→特征变换→输出生成”的流水线协作,配合 engine 的资源管理,共同实现高效的大语言模型推理。
三、models目录
models 目录实现具体的模型架构,会调用 layers 目录中的基础层来构建完整模型。以 qwen3.py 为例,实现了 Qwen3ForCausalLM 模型,其功能如下:
- 模型组件封装 :将 Attention 、 SiluAndMul 等基础层封装到 Qwen3Attention 、 Qwen3MLP 等模块中。
- 模型架构搭建 :通过 Qwen3DecoderLayer 和 Qwen3Model 类构建完整的 Qwen3 模型架构。
四、各目录关联工作方式
layers 、 models 和 engine 目录的组件通过以下流程协同工作:
- 初始化阶段 :
- LLMEngine 初始化时创建 ModelRunner 实例, ModelRunner 初始化 Qwen3ForCausalLM 模型。
- Qwen3ForCausalLM 模型在构建过程中调用 layers 目录下的基础层,如 Attention 、 SiluAndMul 等。
- ModelRunner 分配 KV 缓存,并将缓存张量绑定到模型各层的 k_cache 和 v_cache 属性上。
- 推理阶段 :
- 用户请求通过 LLMEngine 的 add_request 方法添加到调度队列。
- Scheduler 调度请求, LLMEngine 调用 ModelRunner 的 run 方法执行推理。
- ModelRunner 准备输入数据,设置上下文信息,调用 Qwen3ForCausalLM 模型进行前向传播。
- Qwen3ForCausalLM 模型在计算过程中调用 layers 目录下的基础层完成具体计算。
- ModelRunner 使用 Sampler 进行采样,生成最终结果。
- 结果处理阶段 :
- LLMEngine 收集推理结果,通过 tokenizer 解码生成文本返回给用户。
最后感谢DeepSeek nano-vllm作者俞星凯,感谢字节trae,让我有幸了解到了推理引擎的工作原理。
另附一个深度学习的学习笔记 https://github.com/AccumulateMore/CV