rubentium's picture
Archive modified and untracked RCP SparseAtt working-tree files
f05d2eb verified
Raw History Blame Contribute Delete
3.99 kB
"""
Qwen3 Model Configuration.
"""
from dataclasses import dataclass, field
from typing import List, Optional
@dataclass
class Qwen3Config:
"""Configuration class for Qwen3 model."""
vocab_size: int = 151936
hidden_size: int = 1024
intermediate_size: int = 3072
num_hidden_layers: int = 28
num_attention_heads: int = 16
num_key_value_heads: int = 8
head_dim: int = 128
hidden_act: str = "silu"
max_position_embeddings: int = 32768
initializer_range: float = 0.02
rms_norm_eps: float = 1e-6
use_cache: bool = True
tie_word_embeddings: bool = True
rope_theta: float = 1000000.0
rope_scaling: Optional[dict] = None
# ``rope`` (default) preserves legacy behavior; ``alibi`` disables RoPE
# and applies Press et al. head-specific causal distance biases.
positional: str = "rope"
# QK normalisation is part of the published Qwen3-style attention path.
# Keep it on by default so checkpoints/configs written before this flag are
# bit-identical; ``off`` removes both per-head RMSNorm modules.
qk_norm: str = "on"
# Keep Q/K RMSNorm gains and their AdamW state in FP32 during training.
qk_gain_fp32: bool = False
# Training-only RoPE position scales. When non-empty, every attention layer
# independently samples one scale per forward pass. Evaluation always uses
# the standard scale 1.0. This provides a dense positional-augmentation
# control without deleting attention links.
rope_train_position_scale_set: Optional[List[float]] = None
attention_bias: bool = False
attention_dropout: float = 0.0
bos_token_id: int = 151643
eos_token_id: int = 151643
checkpoint_activations: bool = False
attention_type: str = "dense"
sparse_block_size: int = 128
sparse_num_random_blocks: int = 1
sparse_mask_pool_size: int = 1000
sparse_max_seq_length: int = 1024
# When set, only the listed layer indices use sparse attention; all others use dense.
# When None (default), attention_type applies to all layers uniformly.
sparse_layer_indices: Optional[List[int]] = None
# Directory to cache pre-built block masks (one file per layer). If None, masks are rebuilt every run.
sparse_mask_cache_dir: Optional[str] = None
# Seed offset for the frozen (pool_size=1) fixed mask. 0 = legacy (layer-index only).
# Distinct values yield distinct fixed masks (fixed-mask seeds).
sparse_mask_seed: int = 0
# Mixed-sparsity training: if set to a non-empty list, each mask-pool entry draws its
# OWN num_random_blocks uniformly from this set, so the per-step mask (picked at random
# from the pool) also resamples the sparsity LEVEL. None/empty = legacy fixed-nrb pool.
# This is the "Mixed" training arm of the paper; without it the arm silently degenerates
# to a fixed-nrb model.
sparse_mixed_nrb_set: Optional[List[int]] = None
# --- deployment-time baselines (learned MoBA + ASEntmax) ---
# moba_top_k is the per-query block budget used by the top-k deployment ladder.
moba_block_size: int = 128
moba_top_k: int = 32
asentmax_alpha: float = 1.5
asentmax_learn_temp: bool = True
asentmax_init_temp: float = 1.0
def is_layer_sparse(self, layer_idx: int) -> bool:
"""Return True if this layer should use sparse stochastic attention."""
if self.attention_type != "sparse_stochastic":
return False
if self.sparse_layer_indices is None:
return True # all layers sparse (existing behaviour)
return layer_idx in self.sparse_layer_indices
@classmethod
def from_dict(cls, config_dict: dict) -> "Qwen3Config":
return cls(**{k: v for k, v in config_dict.items() if k in cls.__dataclass_fields__})
@classmethod
def from_json(cls, path: str) -> "Qwen3Config":
import json
with open(path, "r") as f:
config_dict = json.load(f)
return cls.from_dict(config_dict)