Skip to main content

add-archon-model

Guide for adding a new model to the Archon engine. Use when user wants to add support for a new HuggingFace model architecture in ArchonEngine.

معلومات المصدر

المستودع
areal-project/AReaL
آخر نشاط في المصدر
٢٨ فبراير ٢٠٢٦ في ١٢:١٣
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٥٬٨٣٦
التفرعات
٦٢٨

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
add-archon-model
description
Guide for adding a new model to the Archon engine. Use when user wants to add support for a new HuggingFace model architecture in ArchonEngine.
# Add Archon Model Add support for a new HuggingFace model architecture in the Archon training engine. ## When to Use This skill is triggered when: - User asks "how do I add a model to Archon?" - User wants to support a new model family (e.g., Llama, Mistral, DeepSeek) in ArchonEngine - User mentions adding a new `ModelSpec` or model type for Archon ## Prerequisites Before starting, ensure: - The target model is available on HuggingFace (has `config.json` with `model_type`) - You know the HuggingFace model ID (e.g., `meta-llama/Llama-3-8B`) - The model uses a standard transformer architecture (decoder-only) ## Step-by-Step Guide ### Step 1: Analyze the Target Model Architecture Read the HuggingFace model's source code to extract key architecture information. **Action**: Fetch and analyze the model's HuggingFace configuration and modeling files. 1. Read the model's `config.json` (via `AutoConfig.from_pretrained`) to identify: - `model_type` string (this is the key used for registry lookup) - All architecture hyperparameters (hidden_size, num_layers, etc.) - Any model-specific fields (e.g., `qk_norm`, `attention_bias`, MoE fields) 1. Read the HuggingFace `modeling_*.py` source to identify: - **Attention variant**: Does it have Q/K norm? Attention bias? Sliding window? Multi-latent attention? - **FFN variant**: SwiGLU (gate_proj + up_proj + down_proj)? GeGLU? Standard MLP? - **MoE support**: Does it have MoE layers? What router type? Shared experts? - **RoPE variant**: Standard RoPE? YaRN? NTK-aware scaling? What is the inv_freq formula? - **Normalization**: RMSNorm or LayerNorm? Pre-norm or post-norm? Elementwise affine? - **Weight tying**: Does `tie_word_embeddings` appear in config? - **State dict key names**: What are the HF weight key naming conventions? 1. Summarize findings in a checklist like: ``` Target model: <name> HF model_type: "<model_type>" (and variants like "<model_type>_moe" if applicable) Attention: [standard GQA / with QK norm / with bias / sliding window / ...] FFN: [SwiGLU / GeGLU / standard MLP / ...] MoE: [no / yes - num_experts, top_k, shared_experts] RoPE: [standard / YaRN / NTK-aware / ...] Norm: [RMSNorm / LayerNorm] with [pre-norm / post-norm] Weight tying: [yes / no] ``` ### Step 2: Select the Reference Model Choose the closest existing implementation as a starting point: | Target characteristics | Reference | Why | | ------------------------------------ | --------- | --------------------------------------- | | Dense-only, standard GQA, no QK norm | `qwen2` | Simplest baseline, pure dense | | Has QK norm, or has MoE support | `qwen3` | Supports QK norm + MoE + shared experts | **Action**: Copy the reference model directory as the starting point: ``` areal/experimental/models/archon/<model>/ __init__.py spec.py model/ args.py model.py rope.py state_dict_adapter.py infra/ parallelize.py ``` ### Step 3: Implement `args.py` Adapt `<Model>ModelArgs` to match the target model's HuggingFace config fields. **Key changes from reference**: 1. Update the `@dataclass` fields to match the target model's hyperparameters: - Field names should use Archon conventions (`dim`, `n_layers`, `n_heads`, `n_kv_heads`, `vocab_size`, `head_dim`, `hidden_dim`, `norm_eps`, `rope_theta`, etc.) - Default values should match the smallest variant of the target model - Add model-specific fields (e.g., `attention_bias`, `qk_norm`, `sliding_window`) 1. Update `from_hf_config()` to correctly map HuggingFace config attributes: - Use `getattr(hf_config, "field_name", default)` for optional fields - Handle variant-specific fields (e.g., MoE fields only present in MoE variants) - The method must return an instance of the model args class **Critical**: Verify every field mapping against the HF model's `config.json`. Incorrect mappings here cause silent errors downstream. **Base class contract** (`BaseModelArgs`): ```python @dataclass class <Model>ModelArgs(BaseModelArgs): # ... model-specific fields ... @classmethod def from_hf_config( cls, hf_config: PretrainedConfig, is_critic: bool = False, **kwargs, ) -> <Model>ModelArgs: # Map HF config fields to Archon model args ... ``` ### Step 4: Implement `model.py` Adapt the model architecture to match the target model. **Key components to adapt**: 1. **Normalization** (`RMSNorm` or similar): - Check if `elementwise_affine` is configurable - Check the epsilon default value - If the model uses `LayerNorm`, implement accordingly 1. **Attention** module: - Q/K/V projection: Check bias presence (`nn.Linear(..., bias=True/False)`) - QK norm: Add `q_norm`/`k_norm` if the model has them, remove if it doesn't - GQA: `n_kv_heads` \< `n_heads` for grouped-query attention - Ulysses SP: Keep the `set_cp_group` / `_sp_enabled` pattern from the reference - Output projection: Check bias presence 1. **FeedForward** module: - SwiGLU: `w2(silu(w1(x)) * w3(x))` -- most common for modern LLMs - Check bias in linear layers - For MoE models: `MoE` module replaces `FeedForward` on designated layers 1. **TransformerBlock**: Pre-norm (most modern LLMs) vs post-norm - MoE layer detection via `_is_moe_layer()` if applicable 1. **Top-level Model** (`<Model>Model(BaseArchonModel)`): - `tok_embeddings`, `layers` (as `ModuleDict`), `norm`, `output`/`score` - `init_weights()`: Match initialization scheme from HF - `init_buffers()`: RoPE cache + MoE buffers - `forward()`: Must follow `BaseArchonModel` signature: `(tokens, positions, cu_seqlens, max_seqlen, tree_attn_meta=None) -> Tensor` **Base class contract** (`BaseArchonModel`): ```python class <Model>Model(BaseArchonModel): def forward(self, tokens, positions, cu_seqlens, max_seqlen, tree_attn_meta=None) -> torch.Tensor: ... def init_weights(self) -> None: ... def init_buffers(self, buffer_device) -> None: ... ``` ### Step 5: Implement `rope.py` Handle the rotary position embedding variant. **Options**: 1. **Standard RoPE** (same as qwen2/qwen3): Re-export from qwen2: ```python from areal.experimental.models.archon.qwen2.model.rope import ( apply_rotary_emb, precompute_rope_cache, repeat_kv, reshape_for_broadcast, rotate_half, ) ``` 1. **Custom RoPE** (YaRN, NTK-aware, etc.): Implement custom `precompute_rope_cache()` and `apply_rotary_emb()` functions. The key difference is usually in how `inv_freq` is computed (scaling factors, interpolation, etc.). ### Step 6: Implement `state_dict_adapter.py` Map between HuggingFace and Archon weight key names. **This is the most error-prone step.** The adapter must correctly handle: 1. **Key name mapping** (`from_hf_map` dict): - Embedding: `model.embed_tokens.weight` -> `tok_embeddings.weight` - Attention: `model.layers.{}.self_attn.q_proj.weight` -> `layers.{}.attention.wq.weight` - FFN: `model.layers.{}.mlp.gate_proj.weight` -> `layers.{}.feed_forward.w1.weight` - Norms: `model.layers.{}.input_layernorm.weight` -> `layers.{}.attention_norm.weight` - Output: `lm_head.weight` -> `output.weight` - Skip keys (set to `None`): `rotary_emb.inv_freq` (computed at runtime) - Model-specific keys: bias terms, QK norm weights, etc. 1. **Reverse mapping** (`to_hf_map`): Auto-generated from `from_hf_map` 1. **MoE expert weights** (if applicable): 3D\<->2D conversion for expert weights. Copy the MoE handling from qwen3 if the model has MoE. 1. **Weight tying**: Skip `output.weight` during `to_hf()` if `tie_word_embeddings=True` **Verification approach**: After implementation, the adapter should satisfy: ```python # Roundtrip: archon -> hf -> archon preserves all keys hf_sd = adapter.to_hf(archon_sd) roundtrip_sd = adapter.from_hf(hf_sd) assert set(roundtrip_sd.keys()) == set(archon_sd.keys()) ``` **Base class contract** (`BaseStateDictAdapter`): ```python class <Model>StateDictAdapter(BaseStateDictAdapter): def from_hf(self, hf_state_dict) -> dict[str, Any]: ... def to_hf(self, archon_state_dict) -> dict[str, Any]: ... def convert_single_to_hf(self, name, tensor) -> list[tuple[str, torch.Tensor]]: ... ``` ### Step 7: Implement `parallelize.py` Define the parallelization strategy for the model. **The parallelize function** applies parallelism in this order: 1. TP (Tensor Parallelism) -- shard attention/FFN across devices 1. EP (Expert Parallelism) -- for MoE models only 1. CP (Context Parallelism / Ulysses SP) -- sequence parallelism 1. AC (Activation Checkpointing) -- memory optimization 1. torch.compile -- compilation optimization 1. FSDP (Fully Sharded Data Parallelism) -- data parallelism **Key adaptations by model architecture**: - **Attention with QK norm**: wq/wk use `use_local_output=False` (DTensor output for norm), add `SequenceParallel(sequence_dim=2)` for q_norm/k_norm - **Attention without QK norm**: wq/wk/wv all use `use_local_output=True` - **Attention with bias**: Bias terms follow the same parallel plan as their weights - **MoE layers**: Separate TP plan for MoE input/output, router gate, and expert weights. Copy from qwen3's `apply_moe_ep_tp()` and `apply_non_moe_tp()` - **Dense-only models**: Simpler plan without MoE handling. Copy from qwen2 **Function signature** (must match `ParallelizeFn` protocol): ```python def parallelize_<model>( model: nn.Module, parallel_dims: ArchonParallelDims, param_dtype: torch.dtype = torch.bfloat16, reduce_dtype: torch.dtype = torch.float32, loss_parallel: bool = True, cpu_offload: bool = False, reshard_after_forward_policy: str = "default", ac_config: ActivationCheckpointConfig | None = None, enable_compile: bool = True, ) -> nn.Module: ``` ### Step 8: Create `spec.py` and Register Assemble the `ModelSpec` and register it. ```python from areal.experimental.models.archon.model_spec import ModelSpec, register_model_spec from areal.experimental.models.archon.pipeline_parallel import pipeline_llm from areal.experimental.models.archon.<model>.infra.parallelize import parallelize_<model> from areal.experimental.models.archon.<model>.model.args import <Model>ModelArgs from areal.experimental.models.archon.<model>.model.model import <Model>Model from areal.experimental.models.archon.<model>.model.state_dict_adapter import ( <Model>StateDictAdapter, ) <MODEL>_SPEC = ModelSpec( name="<Model>", model_class=<Model>Model, model_args_class=<Model>ModelArgs, state_dict_adapter_class=<Model>StateDictAdapter, parallelize_fn=parallelize_<model>, supported_model_types=frozenset({"<model_type>"}), # From HF config.json pipelining_fn=pipeline_llm, ) # Auto-register when module is imported register_model_spec(<MODEL>_SPEC) __all__ = ["<MODEL>_SPEC"] ``` **Note**: `supported_model_types` should include all HF `model_type` strings that this implementation handles (e.g., `{"qwen3", "qwen3_moe"}` for Qwen3). ### Step 9: Register in `__init__.py` Add the import to `areal/experimental/models/archon/__init__.py`: ```python from areal.experimental.models.archon.<model> import spec as <model>_spec # noqa: F401 ``` This triggers auto-registration when the module is imported. ### Step 10: Verify and Test Verification should be done in stages, adapting based on available hardware and the test
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub