myvllm/models/: Qwen3 (qwen3.py) and Llama 3.2 (llama.py). Both follow the same decoder-only transformer pattern and are fully tensor-parallel.
Architecture comparison
- Qwen3
- Llama 3.2
Qwen3 architecture
Class hierarchy
Qwen3ForCausalLM constructor
Key architectural choices
QK normalization. Qwen3 appliesLayerNorm (RMSNorm) to the query and key tensors after the QKV projection but before the rotary embedding. This prevents large values from destabilizing the softmax inside attention. Value tensors are not normalized because they do not participate in the attention score computation.
num_kv_heads < num_heads is fully supported. Each GPU holds num_heads // tp_size query heads and num_kv_heads // tp_size KV heads.
MergedColumnParallelLinear for gate + up. The MLP gate and up projections are merged into a single weight tensor. This is required because model checkpoints store gate_proj.weight and up_proj.weight as separate tensors with size (intermediate_size, hidden_size). A regular ColumnParallelLinear over intermediate_size * 2 would not know where the boundary is when loading. The merged layer’s weight_loader accepts a loaded_weight_id argument (0 or 1) that specifies which sub-matrix is being loaded.
Qwen3DecoderLayer maintains a running residual that is fused into the LayerNorm calls (see Neural Network Layers — LayerNorm):
Llama 3.2 architecture
The Llama 3.2 implementation mirrors Qwen3 almost exactly. The two structural differences are:- No QK normalization.
LlamaAttndoes not haveq_normork_norm. - NTK-scaled RoPE. The
RotaryEmbeddingis constructed withis_llama3=Trueand a much larger base (500000) plus scaling factors that adapt low-frequency dimensions for sequences beyond the training length.
loader.py are needed.
packed_module_mapping
Checkpoint weight names do not always match the attribute names used in the model.packed_module_mapping is a class-level dict that bridges this gap.
myvllm/utils/loader.py inspects this mapping to know:
- Which checkpoint keys correspond to merged parameters (e.g.
gate_up_projmaps to sub-index'0'of the mergedgate_uptensor). - Which
weight_loaderID argument to pass when calling the loader (e.g.'q','k','v'for the QKV projection).
Adding a new model
1
Implement the model class
Create
myvllm/models/mymodel.py. The class must:- Be a subclass of
nn.Module. - Expose
forward(input_ids)returning hidden states. - Expose
compute_logits(hidden_states)returning logits. - Define
packed_module_mappingas a class attribute. - Use the parallel layer classes from
myvllm/layers/for all weight tensors.
2
Register the model in ModelRunner
Open
myvllm/engine/model_runner.py and add a case to the match block inside ModelRunner.__init__:3
Provide a config dict
Create a config dict with the model-specific keys expected by your constructor and pass it to
LLMEngine: