CoolFace
Modelpublic

Premchan369/Q-TensorFormer

sourceHugging Faceapache-2.0updated 9d agoView on Hugging Face
2likes185downloads
models.py309 linesDownload Raw Back to src
1"""2Q-TensorFormer: Complete Model Architecture.3 4Unified Information-to-Resource Allocation Architecture.5Integrates:6  - Nested TT-FFN (ranks 1, 2, 4, 8 with instantaneous slicing)7  - Token Information State (8D feature tracking)8  - Information-Value Resource Allocator (marginal utility optimization)9  - Hardware-Aware Cost Profiling10  - Adaptive KV Cache with multi-precision & eviction11  - Deployment Presets:12      QTF_FULL, QTF_BALANCED, QTF_LATENCY, QTF_MEMORY,13      QTF_ENERGY, QTF_EDGE, QTF_CLASSICAL_ONLY14"""15 16import torch17import torch.nn as nn18import torch.nn.functional as F19import math20from typing import Optional, Dict, List, Tuple, Union21 22from .blocks import HybridBlock23from .config import ModelConfig24from .kv_cache import AdaptiveKVCache25from .resource_allocator import AllocationBudget26from .hardware_cost_model import HardwareCostModel27 28 29class PositionalEncoding(nn.Module):30    def __init__(self, d_model: int, max_len: int = 512, dropout: float = 0.1):31        super().__init__()32        self.dropout = nn.Dropout(dropout)33        pe = torch.zeros(max_len, d_model)34        pos = torch.arange(0, max_len).float().unsqueeze(1)35        div = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))36        pe[:, 0::2] = torch.sin(pos * div)37        pe[:, 1::2] = torch.cos(pos * div)38        self.register_buffer("pe", pe.unsqueeze(0))39 40    def forward(self, x: torch.Tensor, start_pos: int = 0) -> torch.Tensor:41        seq_len = x.size(1)42        return self.dropout(x + self.pe[:, start_pos:start_pos + seq_len, :])43 44 45class QTensorFormer(nn.Module):46    """47    Q-TensorFormer: Closed-Loop Information-to-Resource Adaptive Transformer.48    """49 50    DEPLOYMENT_PRESETS = [51        "QTF_FULL",52        "QTF_BALANCED",53        "QTF_LATENCY",54        "QTF_MEMORY",55        "QTF_ENERGY",56        "QTF_EDGE",57        "QTF_CLASSICAL_ONLY",58    ]59 60    def __init__(self, config: ModelConfig, preset: str = "QTF_BALANCED"):61        super().__init__()62        self.config = config63        self.current_preset = preset.upper()64 65        self.embedding = nn.Embedding(config.vocab_size, config.d_model)66        self.pos_encoding = PositionalEncoding(config.d_model, config.max_seq_len, config.dropout)67 68        # Transformer blocks69        backend_type = getattr(config, "backend_type", "classical_surrogate")70        self.blocks = nn.ModuleList([71            HybridBlock(72                d_model=config.d_model,73                n_heads=config.n_heads,74                n_kv_heads=getattr(config, "n_kv_heads", None),75                ff_multiplier=config.ff_multiplier,76                tt_rank=config.tt_rank,77                tt_min_rank=config.tt_min_rank,78                use_quantum=config.use_quantum,79                n_qubits=config.n_qubits,80                backend_type=backend_type,81                dropout=config.dropout,82                max_seq_len=config.max_seq_len,83                hysteresis_tau=getattr(config, "hysteresis_tau", 0.15),84                default_preset=self.current_preset.replace("QTF_", "").lower(),85                enable_early_exit=getattr(config, "enable_early_exit", False),86                early_exit_threshold=getattr(config, "early_exit_threshold", 0.20),87                vocab_size=config.vocab_size,88            )89            for _ in range(config.n_layers)90        ])91 92        self.ln_f = nn.LayerNorm(config.d_model)93        self.lm_head = nn.Linear(config.d_model, config.vocab_size, bias=False)94        self.lm_head.weight = self.embedding.weight  # Weight tying95 96        # Hardware cost model97        self.hardware_model = HardwareCostModel()98 99        self._init_weights()100 101    def _init_weights(self):102        for name, p in self.named_parameters():103            if "weight" in name and p.dim() >= 2:104                nn.init.xavier_uniform_(p)105            elif "bias" in name:106                nn.init.zeros_(p)107 108    def set_preset(self, preset_name: str):109        """Switch deployment preset."""110        preset = preset_name.upper()111        if preset not in self.DEPLOYMENT_PRESETS:112            raise ValueError(f"Unknown preset {preset}. Choose from {self.DEPLOYMENT_PRESETS}")113        self.current_preset = preset114 115    def forward(116        self,117        input_ids: torch.Tensor,118        attention_mask: Optional[torch.Tensor] = None,119        kv_caches: Optional[List[AdaptiveKVCache]] = None,120        budget: Optional[AllocationBudget] = None,121        return_stats: bool = False,122        preset: Optional[str] = None,123    ) -> Union[torch.Tensor, Tuple[torch.Tensor, List[Dict]]]:124        """125        Forward pass with dynamic information-to-resource allocation.126        """127        if preset is not None:128            self.set_preset(preset)129 130        B, T = input_ids.shape131        start_pos = kv_caches[0].seq_len if (kv_caches is not None and kv_caches[0].seq_len > 0) else 0132 133        x = self.embedding(input_ids)134        x = self.pos_encoding(x, start_pos=start_pos)135 136        preset_str = self.current_preset.replace("QTF_", "").lower()137        force_classical = (self.current_preset in ["QTF_CLASSICAL_ONLY", "QTF_EDGE"] or not self.config.use_quantum)138 139        all_stats = []140        for i, block in enumerate(self.blocks):141            layer_kv = kv_caches[i] if kv_caches is not None else None142            x, stats = block(143                x,144                mask=attention_mask,145                kv_cache=layer_kv,146                budget=budget,147                preset=preset_str,148                force_classical=force_classical,149            )150            all_stats.append(stats)151            if stats.get("early_exit_triggered", False) and "early_exit_logits" in stats:152                logits = stats["early_exit_logits"]153                if return_stats:154                    return logits, all_stats155                return logits156 157        x = self.ln_f(x)158        logits = self.lm_head(x)159 160        if return_stats:161            return logits, all_stats162        return logits163 164    @torch.no_grad()165    def generate(166        self,167        input_ids: torch.Tensor,168        max_new_tokens: int = 20,169        temperature: float = 1.0,170        top_k: int = 50,171        use_cache: bool = True,172    ) -> torch.Tensor:173        """Autoregressive generation with KV Cache."""174        self.eval()175        B = input_ids.shape[0]176 177        kv_caches = None178        if use_cache:179            kv_caches = [180                AdaptiveKVCache(max_capacity=self.config.max_seq_len)181                for _ in range(self.config.n_layers)182            ]183 184        # Prefill phase185        curr_input = input_ids186        for _ in range(max_new_tokens):187            if kv_caches is not None and kv_caches[0].seq_len > 0:188                step_input = curr_input[:, -1:]189            else:190                step_input = curr_input191 192            logits = self(step_input, kv_caches=kv_caches)193            next_logits = logits[:, -1, :] / max(1e-5, temperature)194 195            if top_k > 0:196                v, _ = torch.topk(next_logits, min(top_k, next_logits.size(-1)))197                next_logits[next_logits < v[:, [-1]]] = float("-inf")198 199            probs = F.softmax(next_logits, dim=-1)200            next_token = torch.multinomial(probs, num_samples=1)201            curr_input = torch.cat([curr_input, next_token], dim=-1)202 203        return curr_input204 205    def reset_schedulers(self):206        for block in self.blocks:207            block.reset_scheduler()208 209    @property210    def total_params(self) -> int:211        return sum(p.numel() for p in self.parameters())212 213    @property214    def active_params(self) -> int:215        tt_active = sum(b.tt_ffn.active_params for b in self.blocks)216        base = self.total_params - sum(b.tt_ffn.total_params for b in self.blocks)217        return base + tt_active218 219    @property220    def compression_ratio(self) -> float:221        dense_per_block = 2 * self.config.d_model * self.config.d_model * self.config.ff_multiplier222        base = self.total_params - sum(b.tt_ffn.total_params for b in self.blocks)223        active_tt = sum(b.tt_ffn.active_params for b in self.blocks)224        return (base + dense_per_block * self.config.n_layers) / max(base + active_tt, 1)225 226    def flops_estimate(self, batch_size: int = 1, seq_len: int = 32) -> Dict:227        total = 0228        breakdown = {}229        for i, block in enumerate(self.blocks):230            b = block.flops_estimate(batch_size, seq_len)231            total += b["total"]232            breakdown[f"block_{i}"] = b233        return {"total": total, "breakdown": breakdown}234 235 236class DenseBaseline(nn.Module):237    """238    Standard dense transformer baseline with identical hyperparameters.239    """240 241    def __init__(self, config: ModelConfig):242        super().__init__()243        self.config = config244 245        self.embedding = nn.Embedding(config.vocab_size, config.d_model)246        self.pos_encoding = PositionalEncoding(config.d_model, config.max_seq_len, config.dropout)247 248        self.blocks = nn.ModuleList([249            nn.ModuleDict({250                "ln1": nn.LayerNorm(config.d_model),251                "attn": nn.MultiheadAttention(config.d_model, config.n_heads, dropout=config.dropout, batch_first=True),252                "ln2": nn.LayerNorm(config.d_model),253                "ffn": nn.Sequential(254                    nn.Linear(config.d_model, config.d_model * config.ff_multiplier),255                    nn.GELU(),256                    nn.Linear(config.d_model * config.ff_multiplier, config.d_model),257                ),258                "dropout": nn.Dropout(config.dropout),259            })260            for _ in range(config.n_layers)261        ])262 263        self.ln_f = nn.LayerNorm(config.d_model)264        self.lm_head = nn.Linear(config.d_model, config.vocab_size, bias=False)265        self.lm_head.weight = self.embedding.weight266        self._init_weights()267 268    def _init_weights(self):269        for name, p in self.named_parameters():270            if "weight" in name and p.dim() >= 2:271                nn.init.xavier_uniform_(p)272            elif "bias" in name:273                nn.init.zeros_(p)274 275    def forward(self, input_ids, attention_mask=None, return_stats=False):276        x = self.embedding(input_ids)277        x = self.pos_encoding(x)278 279        for block in self.blocks:280            normed = block["ln1"](x)281            attn_out, _ = block["attn"](normed, normed, normed, need_weights=False)282            x = x + block["dropout"](attn_out)283            ffn_out = block["ffn"](block["ln2"](x))284            x = x + block["dropout"](ffn_out)285 286        x = self.ln_f(x)287        logits = self.lm_head(x)288        if return_stats:289            return logits, []290        return logits291 292    @property293    def total_params(self) -> int:294        return sum(p.numel() for p in self.parameters())295 296 297def create_model(config: ModelConfig, model_type: str = "qtensor", preset: str = "QTF_BALANCED"):298    """Factory helper to build models."""299    if model_type in ["qtensor", "hybrid"]:300        return QTensorFormer(config, preset=preset)301    elif model_type in ["dense", "baseline"]:302        return DenseBaseline(config)303    elif model_type == "tensor_only":304        cfg = ModelConfig(**config.__dict__)305        cfg.use_quantum = False306        return QTensorFormer(cfg, preset="QTF_CLASSICAL_ONLY")307    else:308        raise ValueError(f"Unknown model_type: {model_type}")309