Image-Text-to-Text
Transformers
Safetensors
English
dendro_omni
text-generation
phillnet
phillnet-mini
dendro
visual-question-answering
multimodal
adaptive-reasoning
code-generation
long-context
custom-code
text-vision-only
conversational
custom_code
Instructions to use ayjays132/Phillnet-Mini-Max with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use ayjays132/Phillnet-Mini-Max with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="ayjays132/Phillnet-Mini-Max", trust_remote_code=True) messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("ayjays132/Phillnet-Mini-Max", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use ayjays132/Phillnet-Mini-Max with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "ayjays132/Phillnet-Mini-Max" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "ayjays132/Phillnet-Mini-Max", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/ayjays132/Phillnet-Mini-Max
- SGLang
How to use ayjays132/Phillnet-Mini-Max with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "ayjays132/Phillnet-Mini-Max" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "ayjays132/Phillnet-Mini-Max", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "ayjays132/Phillnet-Mini-Max" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "ayjays132/Phillnet-Mini-Max", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Docker Model Runner
How to use ayjays132/Phillnet-Mini-Max with Docker Model Runner:
docker model run hf.co/ayjays132/Phillnet-Mini-Max
| """One physical recurrent Dendro cell containing the complete model mechanism.""" | |
| from __future__ import annotations | |
| import math | |
| from dataclasses import dataclass | |
| from typing import Any | |
| import torch | |
| from torch.nn import functional as F | |
| from ._source_bound import SourceBoundModule | |
| from .cache import DendroKVCache | |
| from .configuration_dendro_omni import DendroOmniConfig | |
| from .modalities import DendroModalityLayout | |
| from .source import DendroSourceLayer | |
| from .spatial import apply_rotary_position_embedding | |
| class DendroCellState: | |
| depth_index: int | |
| phase: str | |
| activation_heat: torch.Tensor | |
| entropy_pressure: torch.Tensor | |
| novelty: torch.Tensor | |
| salience: torch.Tensor | |
| route_probs: torch.Tensor | |
| expert_probs: torch.Tensor | |
| coherence: torch.Tensor | |
| residual_gate: torch.Tensor | |
| memory_write_strength: torch.Tensor | |
| workspace_write_strength: torch.Tensor | |
| plasticity_rate: torch.Tensor | |
| readiness: torch.Tensor | |
| contradiction: torch.Tensor | |
| attention_entropy: torch.Tensor | None = None | |
| top_attention_indices: torch.Tensor | None = None | |
| def summary(self) -> dict[str, float | int | str]: | |
| def mean(value: torch.Tensor) -> float: | |
| return float(value.detach().float().mean().cpu().item()) | |
| return { | |
| "depth_index": self.depth_index, | |
| "phase": self.phase, | |
| "activation_heat": mean(self.activation_heat), | |
| "entropy_pressure": mean(self.entropy_pressure), | |
| "novelty": mean(self.novelty), | |
| "salience": mean(self.salience), | |
| "coherence": mean(self.coherence), | |
| "residual_gate": mean(self.residual_gate), | |
| "memory_write_strength": mean(self.memory_write_strength), | |
| "workspace_write_strength": mean(self.workspace_write_strength), | |
| "plasticity_rate": mean(self.plasticity_rate), | |
| "readiness": mean(self.readiness), | |
| "contradiction": mean(self.contradiction), | |
| } | |
| class DendroCellOutput: | |
| hidden_states: torch.Tensor | |
| cache: DendroKVCache | None | |
| state: DendroCellState | |
| attention_weights: torch.Tensor | None = None | |
| class DendroRecurrentCell(SourceBoundModule): | |
| """The single physical layer recurrently applied at all virtual depths. | |
| Attention, local structure, climate control, sticky plasticity, associative | |
| retrieval, global workspace, memory organs, routed shared-FFN computation, | |
| entropy regulation, coherence and dream/reflection behavior are all functions of | |
| one source layer. This class contains no ``Parameter``, ``Linear`` or | |
| ``Embedding`` of its own. | |
| """ | |
| def __init__(self, config: DendroOmniConfig, source: DendroSourceLayer) -> None: | |
| super().__init__(source) | |
| self.config = config | |
| def _split_heads(self, tensor: torch.Tensor) -> torch.Tensor: | |
| batch, length, _hidden = tensor.shape | |
| return tensor.view(batch, length, self.config.num_attention_heads, self.config.head_dim).transpose(1, 2) | |
| def _merge_heads(self, tensor: torch.Tensor) -> torch.Tensor: | |
| return tensor.transpose(1, 2).contiguous().flatten(-2) | |
| def _effort_condition( | |
| self, | |
| hidden: torch.Tensor, | |
| depth_code: torch.Tensor, | |
| phase_code: torch.Tensor, | |
| *, | |
| effort_id: int, | |
| effort_level: float, | |
| phase_progress: float, | |
| remaining_budget_fraction: float, | |
| ) -> torch.Tensor | None: | |
| """Build a source-derived effort/budget code without private parameters. | |
| The zero-strength branch intentionally requests no new source primitives, | |
| preserving both legacy checkpoint numerics and inference cost. | |
| """ | |
| strength = float(self.config.reasoning_effort_conditioning_strength) | |
| if strength <= 0.0: | |
| return None | |
| batch = hidden.shape[0] | |
| effort_count = int(self.config.reasoning_effort_condition_count) | |
| checked_effort_id = min(max(0, int(effort_id)), effort_count - 1) | |
| # Reuse otherwise-idle rows at the end of the existing recurrent-depth | |
| # table. Effort is therefore a phenotype of the same depth substrate, | |
| # not a separately materialized logical embedding. | |
| effort_row_start = max(0, int(self.config.max_recurrent_depth) - effort_count) | |
| effort_ids = torch.full( | |
| (batch,), | |
| effort_row_start + checked_effort_id, | |
| device=hidden.device, | |
| dtype=torch.long, | |
| ) | |
| categorical = self.source.embedding( | |
| effort_ids, | |
| "recurrence/depth", | |
| self.config.max_recurrent_depth, | |
| self.config.hidden_size, | |
| ).unsqueeze(1) | |
| level = min(1.0, max(0.0, float(effort_level))) | |
| progress = min(1.0, max(0.0, float(phase_progress))) | |
| remaining = min(1.0, max(0.0, float(remaining_budget_fraction))) | |
| # Continuous budget information modulates already-computed depth and | |
| # phase codes. This preserves their influence and source gradients while | |
| # avoiding another HxH projection and its saved autograd state. | |
| return torch.tanh( | |
| categorical * (0.50 + 0.50 * level + 0.25 * remaining) | |
| + phase_code * (0.25 + 0.50 * progress) | |
| + depth_code * (0.25 * remaining) | |
| ) | |
| def _depth_condition( | |
| self, | |
| hidden: torch.Tensor, | |
| depth_idx: int, | |
| phase: str, | |
| *, | |
| effort_id: int, | |
| effort_level: float, | |
| phase_progress: float, | |
| remaining_budget_fraction: float, | |
| ) -> tuple[torch.Tensor, torch.Tensor | None]: | |
| source = self.source | |
| batch = hidden.shape[0] | |
| depth_ids = torch.full((batch,), depth_idx, device=hidden.device, dtype=torch.long) | |
| depth_code = source.embedding( | |
| depth_ids, | |
| "recurrence/depth", | |
| self.config.max_recurrent_depth, | |
| self.config.hidden_size, | |
| ).unsqueeze(1) | |
| phase_id = {"base": 0, "reasoning": 1, "verification": 2, "dream": 3}.get(phase, 0) | |
| phase_ids = torch.full((batch,), phase_id, device=hidden.device, dtype=torch.long) | |
| phase_code = source.embedding(phase_ids, "recurrence/phase", 4, self.config.hidden_size).unsqueeze(1) | |
| effort_condition = self._effort_condition( | |
| hidden, | |
| depth_code, | |
| phase_code, | |
| effort_id=effort_id, | |
| effort_level=effort_level, | |
| phase_progress=phase_progress, | |
| remaining_budget_fraction=remaining_budget_fraction, | |
| ) | |
| conditioning_code = depth_code + phase_code | |
| if effort_condition is not None: | |
| effort_strength = float(self.config.reasoning_effort_conditioning_strength) | |
| conditioning_code = conditioning_code + effort_strength * effort_condition | |
| # Depth, phase and effort all share the same FiLM transform. The | |
| # zero-strength branch receives the exact legacy input and operation order. | |
| scale, shift = source.project_many( | |
| conditioning_code, | |
| ( | |
| ("recurrence/film_scale", self.config.hidden_size, False), | |
| ("recurrence/film_shift", self.config.hidden_size, False), | |
| ), | |
| ) | |
| conditioned = ( | |
| hidden * (1.0 + 0.10 * torch.tanh(scale)) | |
| + 0.10 * shift | |
| + 0.10 * depth_code | |
| + 0.05 * phase_code | |
| ) | |
| if effort_condition is not None: | |
| conditioned = ( | |
| conditioned | |
| + 0.05 * effort_strength * effort_condition | |
| ) | |
| return conditioned, effort_condition | |
| def _context_mean(self, hidden: torch.Tensor, layout: DendroModalityLayout) -> torch.Tensor: | |
| """Return a mask-correct context mean without future-text leakage. | |
| Prefix tokens may use the complete perceptual prefix under ``prefix_bidi``; | |
| causal text tokens only use valid physical positions up to themselves. | |
| """ | |
| valid = layout.attention_mask.unsqueeze(-1).to(hidden.dtype) | |
| cumulative = (hidden * valid).cumsum(dim=1) | |
| cumulative_count = valid.cumsum(dim=1).clamp_min(1.0) | |
| causal_mean = cumulative / cumulative_count | |
| if self.config.attention_mode == "causal": | |
| return causal_mean | |
| if self.config.attention_mode == "bidirectional": | |
| global_mean = (hidden * valid).sum(dim=1, keepdim=True) / valid.sum(dim=1, keepdim=True).clamp_min(1.0) | |
| return global_mean.expand_as(hidden) | |
| prefix_valid = (layout.is_prefix & layout.attention_mask).unsqueeze(-1) | |
| prefix_weight = prefix_valid.to(hidden.dtype) | |
| prefix_mean = (hidden * prefix_weight).sum(dim=1, keepdim=True) | |
| prefix_mean = prefix_mean / prefix_weight.sum(dim=1, keepdim=True).clamp_min(1.0) | |
| return torch.where(prefix_valid, prefix_mean.expand_as(hidden), causal_mean) | |
| def _climate( | |
| self, | |
| hidden: torch.Tensor, | |
| *, | |
| layout: DendroModalityLayout, | |
| depth_idx: int, | |
| cache: DendroKVCache | None, | |
| ) -> tuple[dict[str, torch.Tensor], dict[str, torch.Tensor]]: | |
| source = self.source | |
| activation_heat = hidden.float().pow(2).mean(dim=-1, keepdim=True).to(hidden.dtype) | |
| feature_probs = torch.softmax(hidden.float(), dim=-1) | |
| entropy = -(feature_probs * feature_probs.clamp_min(1e-9).log()).sum(dim=-1, keepdim=True) | |
| entropy = (entropy / math.log(max(2, hidden.shape[-1]))).to(hidden.dtype) | |
| centered = hidden - self._context_mean(hidden, layout) | |
| novelty = centered.float().pow(2).mean(dim=-1, keepdim=True).clamp_min(1e-12).sqrt().to(hidden.dtype) | |
| memory_pressure = torch.zeros_like(activation_heat) | |
| route_imbalance = torch.zeros_like(activation_heat) | |
| plasticity_volatility = torch.zeros_like(activation_heat) | |
| # Runtime organs are consumed through causal scans below. Feeding their | |
| # *final* cached summaries back into every token here would make chunked | |
| # decoding differ from full-sequence training. These slots remain reserved | |
| # for source-compatible climate extensions that provide tokenwise histories. | |
| del cache, depth_idx | |
| metrics = torch.cat( | |
| [activation_heat, entropy, novelty, memory_pressure, route_imbalance, plasticity_volatility], | |
| dim=-1, | |
| ) | |
| controls_raw = source.project(metrics, "climate/controller", 8, low_bit=False) | |
| controls = { | |
| "temperature": 0.55 + 0.90 * torch.sigmoid(controls_raw[..., 0:1]), | |
| "residual_gate": 0.10 + 0.90 * torch.sigmoid(controls_raw[..., 1:2]), | |
| "plasticity_rate": 0.20 * torch.sigmoid(controls_raw[..., 2:3]), | |
| "memory_write": torch.sigmoid(controls_raw[..., 3:4]), | |
| "workspace_write": torch.sigmoid(controls_raw[..., 4:5]), | |
| "attention_focus": torch.sigmoid(controls_raw[..., 5:6]), | |
| "entropy_compress": torch.sigmoid(controls_raw[..., 6:7]), | |
| "dream_gate": torch.sigmoid(controls_raw[..., 7:8]), | |
| } | |
| return { | |
| "activation_heat": activation_heat, | |
| "entropy": entropy, | |
| "novelty": novelty, | |
| "memory_pressure": memory_pressure, | |
| "route_imbalance": route_imbalance, | |
| "plasticity_volatility": plasticity_volatility, | |
| }, controls | |
| def _plasticity( | |
| self, | |
| hidden: torch.Tensor, | |
| controls: dict[str, torch.Tensor], | |
| layout: DendroModalityLayout, | |
| depth_idx: int, | |
| cache: DendroKVCache | None, | |
| ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: | |
| source = self.source | |
| salience = source.gate(hidden, "plasticity/salience", 1) | |
| if hidden.shape[1] > 1: | |
| previous = F.pad(hidden[:, :-1], (0, 0, 1, 0)) | |
| novelty = 1.0 - F.cosine_similarity(hidden.float(), previous.float(), dim=-1).unsqueeze(-1) | |
| novelty[:, 0] = 0.0 | |
| novelty = novelty.to(hidden.dtype) | |
| else: | |
| novelty = torch.zeros_like(salience) | |
| old_trace = cache.get_runtime_state("plasticity_trace", depth_idx) if cache is not None else None | |
| if old_trace is None: | |
| old_trace = torch.zeros(hidden.shape[0], hidden.shape[-1], device=hidden.device, dtype=hidden.dtype) | |
| else: | |
| old_trace = old_trace.to(device=hidden.device, dtype=hidden.dtype) | |
| writes = salience * (1.0 + novelty) * hidden | |
| rates = controls["plasticity_rate"] | |
| valid = layout.attention_mask.unsqueeze(-1) | |
| trace = old_trace | |
| token_traces: list[torch.Tensor] = [] | |
| # This is an actual sticky causal state scan. It makes the full-sequence | |
| # training path obey the same no-future contract as token-by-token decoding. | |
| for token_idx in range(hidden.shape[1]): | |
| candidate = self.config.plasticity_decay * trace + rates[:, token_idx] * writes[:, token_idx] | |
| trace = torch.where(valid[:, token_idx], candidate, trace) | |
| token_traces.append(trace) | |
| stacked = torch.stack(token_traces, dim=1) | |
| modulation = source.project(stacked, "plasticity/trace_modulation", self.config.hidden_size, low_bit=False) | |
| return salience, novelty, stacked + 0.05 * modulation, trace | |
| def _make_attention_mask( | |
| self, | |
| *, | |
| query_layout: DendroModalityLayout, | |
| key_positions: torch.Tensor, | |
| key_is_prefix: torch.Tensor, | |
| key_attention_mask: torch.Tensor, | |
| ) -> torch.Tensor: | |
| q_pos = query_layout.sequence_positions.unsqueeze(-1) | |
| k_pos = key_positions.unsqueeze(-2) | |
| q_prefix = query_layout.is_prefix.unsqueeze(-1) | |
| k_prefix = key_is_prefix.unsqueeze(-2) | |
| mode = self.config.attention_mode | |
| if mode == "bidirectional": | |
| allowed = torch.ones_like(q_pos <= k_pos, dtype=torch.bool) | |
| elif mode == "causal": | |
| allowed = k_pos <= q_pos | |
| else: # prefix_bidi | |
| allowed = (q_prefix & k_prefix) | (~q_prefix & (k_prefix | (k_pos <= q_pos))) | |
| q_valid = query_layout.attention_mask.unsqueeze(-1) | |
| k_valid = key_attention_mask.unsqueeze(-2) | |
| allowed = allowed & q_valid & k_valid | |
| # SDPA rows may not be entirely masked. Invalid query rows are later zeroed. | |
| first_key = torch.zeros_like(allowed) | |
| first_key[..., 0] = True | |
| allowed = allowed | (~q_valid & first_key) | |
| return allowed | |
| def _make_local_attention_mask( | |
| self, | |
| *, | |
| query_layout: DendroModalityLayout, | |
| key_positions: torch.Tensor, | |
| key_is_prefix: torch.Tensor, | |
| key_attention_mask: torch.Tensor, | |
| ) -> torch.Tensor: | |
| """Cache-aware three-position local mask over the shared Q/K/V stream.""" | |
| full = self._make_attention_mask( | |
| query_layout=query_layout, | |
| key_positions=key_positions, | |
| key_is_prefix=key_is_prefix, | |
| key_attention_mask=key_attention_mask, | |
| ) | |
| q_pos = query_layout.sequence_positions.unsqueeze(-1) | |
| k_pos = key_positions.unsqueeze(-2) | |
| distance = q_pos - k_pos | |
| if self.config.attention_mode == "bidirectional": | |
| local = distance.abs() <= 1 | |
| elif self.config.attention_mode == "causal": | |
| local = (distance >= 0) & (distance < 3) | |
| else: | |
| q_prefix = query_layout.is_prefix.unsqueeze(-1) | |
| k_prefix = key_is_prefix.unsqueeze(-2) | |
| prefix_local = k_prefix & (distance.abs() <= 1) | |
| text_local = (distance >= 0) & (distance < 3) | |
| local = torch.where(q_prefix, prefix_local, text_local) | |
| local = local & full | |
| q_valid = query_layout.attention_mask.unsqueeze(-1) | |
| first_key = torch.zeros_like(local) | |
| first_key[..., 0] = True | |
| return local | (~q_valid & first_key) | |
| def _attention( | |
| self, | |
| hidden: torch.Tensor, | |
| *, | |
| layout: DendroModalityLayout, | |
| controls: dict[str, torch.Tensor], | |
| plasticity_trace: torch.Tensor, | |
| depth_idx: int, | |
| cache: DendroKVCache | None, | |
| use_cache: bool, | |
| output_attentions: bool, | |
| ) -> tuple[ | |
| torch.Tensor, | |
| torch.Tensor, | |
| torch.Tensor | None, | |
| torch.Tensor, | |
| tuple[torch.Tensor | None, torch.Tensor | None], | |
| ]: | |
| source = self.source | |
| qkv = source.project(hidden, "cell/attention/qkv", 3 * self.config.hidden_size) | |
| q, k, v = qkv.chunk(3, dim=-1) | |
| q, k, v = self._split_heads(q), self._split_heads(k), self._split_heads(v) | |
| if self.config.qkv_norm: | |
| if self.config.align_qkv_norms: | |
| q, k, v = source.aligned_qkv_norm(q, k, v, "cell/attention/qkv_norm", eps=self.config.layer_norm_eps) | |
| else: | |
| q = source.rms_norm(q, "cell/attention/q_norm", eps=self.config.layer_norm_eps) | |
| k = source.rms_norm(k, "cell/attention/k_norm", eps=self.config.layer_norm_eps) | |
| v = source.rms_norm(v, "cell/attention/v_norm", eps=self.config.layer_norm_eps) | |
| q, k = apply_rotary_position_embedding( | |
| q, | |
| k, | |
| layout.sequence_positions, | |
| theta=self.config.rope_theta, | |
| ) | |
| trace_heads = plasticity_trace.view( | |
| plasticity_trace.shape[0], | |
| plasticity_trace.shape[1], | |
| self.config.num_attention_heads, | |
| self.config.head_dim, | |
| ).transpose(1, 2) | |
| q = q + 0.02 * trace_heads | |
| if use_cache: | |
| if cache is None: | |
| raise RuntimeError("use_cache=True requires a DendroKVCache") | |
| key, value = cache.update( | |
| k, | |
| v, | |
| depth_idx, | |
| { | |
| "is_prefix": layout.is_prefix, | |
| "positions": layout.sequence_positions, | |
| "attention_mask": layout.attention_mask, | |
| "modality_ids": layout.modality_ids, | |
| }, | |
| ) | |
| key_positions = cache.key_positions | |
| key_is_prefix = cache.key_is_prefix | |
| key_attention = cache.key_attention_mask | |
| assert key_positions is not None and key_is_prefix is not None and key_attention is not None | |
| key_positions = key_positions.to(hidden.device) | |
| key_is_prefix = key_is_prefix.to(hidden.device) | |
| key_attention = key_attention.to(hidden.device) | |
| else: | |
| key, value = k, v | |
| key_positions = layout.sequence_positions | |
| key_is_prefix = layout.is_prefix | |
| key_attention = layout.attention_mask | |
| allowed = self._make_attention_mask( | |
| query_layout=layout, | |
| key_positions=key_positions, | |
| key_is_prefix=key_is_prefix, | |
| key_attention_mask=key_attention, | |
| ) | |
| attn_mask = allowed.unsqueeze(1) | |
| local_mask = self._make_local_attention_mask( | |
| query_layout=layout, | |
| key_positions=key_positions, | |
| key_is_prefix=key_is_prefix, | |
| key_attention_mask=key_attention, | |
| ).unsqueeze(1) | |
| dropout_p = self.config.attention_dropout if self.training else 0.0 | |
| attention_weights = None | |
| attention_entropy = None | |
| top_indices = None | |
| scale = 1.0 / math.sqrt(self.config.head_dim) | |
| temperature = controls["temperature"].transpose(1, 2).unsqueeze(-1).to(q.dtype) | |
| tempered_q = q / temperature | |
| if output_attentions: | |
| logits = torch.matmul(tempered_q.float(), key.float().transpose(-1, -2)) * scale | |
| logits = logits.masked_fill(~attn_mask, torch.finfo(logits.dtype).min) | |
| attention_weights = torch.softmax(logits, dim=-1).to(hidden.dtype) | |
| attention_weights = F.dropout(attention_weights, p=dropout_p, training=self.training) | |
| context = torch.matmul(attention_weights, value) | |
| probs = attention_weights.float().clamp_min(1e-9) | |
| attention_entropy = -(probs * probs.log()).sum(dim=-1).mean(dim=1) | |
| top_indices = attention_weights.detach().mean(dim=1).topk( | |
| k=min(4, attention_weights.shape[-1]), dim=-1 | |
| ).indices | |
| else: | |
| context = F.scaled_dot_product_attention( | |
| tempered_q, | |
| key, | |
| value, | |
| attn_mask=attn_mask, | |
| dropout_p=dropout_p, | |
| is_causal=False, | |
| scale=scale, | |
| ) | |
| local_context = F.scaled_dot_product_attention( | |
| tempered_q, | |
| key, | |
| value, | |
| attn_mask=local_mask, | |
| dropout_p=dropout_p, | |
| is_causal=False, | |
| scale=scale, | |
| ) | |
| context = context * layout.attention_mask[:, None, :, None].to(context.dtype) | |
| local_context = local_context * layout.attention_mask[:, None, :, None].to(local_context.dtype) | |
| # Shared head-communication state lets heads exchange summaries without a | |
| # second attention module or independent parameters. | |
| head_summary = self._merge_heads(context) | |
| previous_comm = cache.get_runtime_state("head_communication", depth_idx) if cache is not None else None | |
| if previous_comm is None: | |
| comm_state = torch.zeros( | |
| head_summary.shape[0], | |
| self.config.hidden_size, | |
| device=head_summary.device, | |
| dtype=head_summary.dtype, | |
| ) | |
| else: | |
| comm_state = previous_comm.to(head_summary.device, head_summary.dtype) | |
| comm_tokens: list[torch.Tensor] = [] | |
| for token_idx in range(head_summary.shape[1]): | |
| candidate = source.project( | |
| head_summary[:, token_idx] + comm_state, | |
| "cell/attention/head_communication", | |
| self.config.hidden_size, | |
| low_bit=False, | |
| ) | |
| valid = layout.attention_mask[:, token_idx, None] | |
| comm_state = torch.where(valid, candidate, comm_state) | |
| comm_tokens.append(torch.where(valid, candidate, torch.zeros_like(candidate))) | |
| comm = torch.stack(comm_tokens, dim=1) | |
| comm_gate = source.gate(hidden, "cell/attention/head_communication_gate", self.config.hidden_size) | |
| comm_heads = self._split_heads(comm) | |
| gate_heads = self._split_heads(comm_gate) | |
| context = context + 0.05 * comm_heads * gate_heads | |
| return ( | |
| self._merge_heads(context), | |
| self._merge_heads(local_context), | |
| attention_weights, | |
| comm_state, | |
| (attention_entropy, top_indices), | |
| ) | |
| def _memory_slots( | |
| self, | |
| hidden: torch.Tensor, | |
| cache: DendroKVCache | None, | |
| depth_idx: int, | |
| ) -> torch.Tensor: | |
| cached_memory = cache.get_runtime_state("memory", depth_idx) if cache is not None else None | |
| if cached_memory is not None: | |
| return cached_memory.to(device=hidden.device, dtype=hidden.dtype) | |
| seeds = self.source.primitive("memory/slots", (self.config.memory_slots, self.config.hidden_size)) | |
| organ_ids = torch.arange(self.config.memory_slots, device=hidden.device) % self.config.num_memory_organs | |
| organs = self.source.embedding( | |
| organ_ids, | |
| "memory/organs", | |
| self.config.num_memory_organs, | |
| self.config.hidden_size, | |
| ) | |
| return (seeds + 0.10 * organs).unsqueeze(0).expand(hidden.shape[0], -1, -1) | |
| def _workspace_slots( | |
| self, | |
| hidden: torch.Tensor, | |
| cache: DendroKVCache | None, | |
| depth_idx: int, | |
| ) -> torch.Tensor: | |
| cached_workspace = cache.get_runtime_state("workspace", depth_idx) if cache is not None else None | |
| if cached_workspace is not None: | |
| return cached_workspace.to(device=hidden.device, dtype=hidden.dtype) | |
| seeds = self.source.primitive("workspace/slots", (self.config.workspace_slots, self.config.hidden_size)) | |
| return seeds.unsqueeze(0).expand(hidden.shape[0], -1, -1) | |
| def _affine_slot_states( | |
| initial: torch.Tensor, | |
| updates: torch.Tensor, | |
| valid: torch.Tensor, | |
| decay: float, | |
| ) -> tuple[torch.Tensor, torch.Tensor]: | |
| """Return every pre-update state and the final affine recurrent state.""" | |
| scan_dtype = torch.float32 if initial.dtype in {torch.float16, torch.bfloat16} else initial.dtype | |
| scan_valid = valid.unsqueeze(-1).unsqueeze(-1) | |
| multiplier = torch.where( | |
| scan_valid, | |
| torch.full_like(scan_valid, float(decay), dtype=scan_dtype), | |
| torch.ones_like(scan_valid, dtype=scan_dtype), | |
| ) | |
| additive = updates.to(scan_dtype) * scan_valid | |
| products = torch.cumprod(multiplier, dim=1) | |
| scaled = additive / products.clamp_min(torch.finfo(scan_dtype).tiny) | |
| inclusive = torch.cumsum(scaled, dim=1) | |
| before_sum = inclusive - scaled | |
| before_product = torch.cat([torch.ones_like(products[:, :1]), products[:, :-1]], dim=1) | |
| initial_scan = initial.to(scan_dtype) | |
| states_before = before_product * (initial_scan.unsqueeze(1) + before_sum) | |
| final = products[:, -1] * (initial_scan + inclusive[:, -1]) | |
| return states_before.to(initial.dtype), final.to(initial.dtype) | |
| def _slot_scan( | |
| self, | |
| hidden: torch.Tensor, | |
| slots: torch.Tensor, | |
| controls: dict[str, torch.Tensor], | |
| layout: DendroModalityLayout, | |
| name: str, | |
| ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: | |
| """Read then write a memory/workspace organ token by token. | |
| This is a real causal state machine: token ``t`` reads only the organ state | |
| created by cached history and tokens ``< t``, then writes the state used by | |
| token ``t+1``. The same routine is used in full-sequence training and | |
| one-token cached generation. | |
| """ | |
| if name not in {"memory", "workspace"}: | |
| raise ValueError(f"unsupported slot scan {name!r}") | |
| source = self.source | |
| decay = self.config.memory_decay if name == "memory" else self.config.workspace_decay | |
| strength_key = "memory_write" if name == "memory" else "workspace_write" | |
| # Token projections are independent of the recurrent slot state. Project | |
| # the complete sequence once; only the actual read/write state transition | |
| # remains causal below. The affine recurrence itself has a closed-form | |
| # prefix scan, evaluated in bounded blocks to avoid long-context underflow. | |
| queries = source.project(hidden, f"{name}/query", self.config.hidden_size, low_bit=False) | |
| routers = torch.softmax( | |
| source.project(hidden, f"{name}/write_router", slots.shape[1], low_bit=False).float(), | |
| dim=-1, | |
| ).to(hidden.dtype) | |
| writes = source.project(hidden, f"{name}/write_value", self.config.hidden_size, low_bit=False) | |
| strength = controls[strength_key] | |
| valid = layout.attention_mask | |
| if hidden.shape[1] == 1: | |
| key = source.project(slots, f"{name}/key", self.config.hidden_size, low_bit=False) | |
| value = source.project(slots, f"{name}/value", self.config.hidden_size, low_bit=False) | |
| scores = torch.einsum("bh,bsh->bs", queries[:, 0].float(), key.float()) | |
| scores = scores / math.sqrt(self.config.hidden_size) | |
| probabilities = torch.softmax(scores, dim=-1).to(hidden.dtype) | |
| read = torch.einsum("bs,bsh->bh", probabilities, value).unsqueeze(1) | |
| update = strength[:, 0].unsqueeze(1) * routers[:, 0].unsqueeze(-1) * writes[:, 0].unsqueeze(1) | |
| candidate = decay * slots + update | |
| mask = valid[:, 0, None, None] | |
| final = torch.where(mask, candidate, slots) | |
| final_router = torch.where(valid[:, 0, None], routers[:, 0], torch.zeros_like(routers[:, 0])) | |
| return read, final, final_router | |
| updates = ( | |
| strength.unsqueeze(-1) | |
| * routers.unsqueeze(-1) | |
| * writes.unsqueeze(-2) | |
| ) | |
| # A 512-token training window is deliberately handled by one tensor scan, | |
| # without entering a Python block loop. Extremely long contexts retain a | |
| # bounded fallback so products cannot underflow and peak memory stays sane. | |
| scan_block = 1024 | |
| if hidden.shape[1] <= scan_block: | |
| states_before, current = self._affine_slot_states(slots, updates, valid, decay) | |
| key = source.project(states_before, f"{name}/key", self.config.hidden_size, low_bit=False) | |
| value = source.project(states_before, f"{name}/value", self.config.hidden_size, low_bit=False) | |
| scores = torch.einsum("bth,btsh->bts", queries.float(), key.float()) | |
| scores = scores / math.sqrt(self.config.hidden_size) | |
| read_probs = torch.softmax(scores, dim=-1).to(hidden.dtype) | |
| reads = torch.einsum("bts,btsh->bth", read_probs, value) | |
| else: | |
| read_blocks: list[torch.Tensor] = [] | |
| current = slots | |
| for start in range(0, hidden.shape[1], scan_block): | |
| end = min(hidden.shape[1], start + scan_block) | |
| states_before, current = self._affine_slot_states( | |
| current, | |
| updates[:, start:end], | |
| valid[:, start:end], | |
| decay, | |
| ) | |
| key = source.project(states_before, f"{name}/key", self.config.hidden_size, low_bit=False) | |
| value = source.project(states_before, f"{name}/value", self.config.hidden_size, low_bit=False) | |
| scores = torch.einsum("bth,btsh->bts", queries[:, start:end].float(), key.float()) | |
| scores = scores / math.sqrt(self.config.hidden_size) | |
| read_probs = torch.softmax(scores, dim=-1).to(hidden.dtype) | |
| read_blocks.append(torch.einsum("bts,btsh->bth", read_probs, value)) | |
| reads = torch.cat(read_blocks, dim=1) | |
| positions = torch.arange(hidden.shape[1], device=hidden.device).unsqueeze(0) | |
| last_index = torch.where(valid, positions, -1).amax(dim=1) | |
| safe_index = last_index.clamp_min(0) | |
| last_router = routers.gather( | |
| 1, | |
| safe_index[:, None, None].expand(-1, 1, routers.shape[-1]), | |
| ).squeeze(1) | |
| last_router = torch.where((last_index >= 0).unsqueeze(-1), last_router, torch.zeros_like(last_router)) | |
| return reads, current, last_router | |
| def _associative_scan( | |
| self, | |
| hidden: torch.Tensor, | |
| salience: torch.Tensor, | |
| layout: DendroModalityLayout, | |
| cache: DendroKVCache | None, | |
| depth_idx: int, | |
| ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: | |
| """Bounded causal associative recall and online write path.""" | |
| source = self.source | |
| batch, _length, hidden_size = hidden.shape | |
| keys = cache.get_runtime_state("associative_keys", depth_idx) if cache is not None else None | |
| values = cache.get_runtime_state("associative_values", depth_idx) if cache is not None else None | |
| scores = cache.get_runtime_state("associative_scores", depth_idx) if cache is not None else None | |
| if keys is None or values is None: | |
| keys = hidden.new_empty(batch, 0, hidden_size) | |
| values = hidden.new_empty(batch, 0, hidden_size) | |
| scores = hidden.new_empty(batch, 0) | |
| else: | |
| keys = keys.to(device=hidden.device, dtype=hidden.dtype) | |
| values = values.to(device=hidden.device, dtype=hidden.dtype) | |
| if scores is None: | |
| scores = torch.ones(batch, keys.shape[1], device=hidden.device, dtype=hidden.dtype) | |
| else: | |
| scores = scores.to(device=hidden.device, dtype=hidden.dtype) | |
| projected_queries = source.project(hidden, "associative/query", hidden_size, low_bit=False) | |
| projected_keys = source.project(hidden, "associative/key", hidden_size, low_bit=False) | |
| projected_values = source.project(hidden, "associative/value", hidden_size, low_bit=False) | |
| new_scores = torch.where( | |
| layout.attention_mask, | |
| salience[..., 0], | |
| torch.full_like(salience[..., 0], -1.0), | |
| ) | |
| if hidden.shape[1] == 1: | |
| if keys.shape[1] == 0: | |
| read = torch.zeros_like(hidden) | |
| else: | |
| logits = torch.einsum("bh,bkh->bk", projected_queries[:, 0].float(), keys.float()) | |
| logits = logits / math.sqrt(hidden_size) | |
| logits = logits + scores.float().clamp_min(1e-8).log() | |
| probabilities = torch.softmax(logits, dim=-1).to(hidden.dtype) | |
| read = torch.einsum("bk,bkh->bh", probabilities, values).unsqueeze(1) | |
| keys = torch.cat([keys, projected_keys], dim=1) | |
| values = torch.cat([values, projected_values], dim=1) | |
| scores = torch.cat([scores, new_scores], dim=1) | |
| keep = min(self.config.associative_slots, keys.shape[1]) | |
| final_scores, final_indices = scores.topk(keep, dim=1) | |
| gather = final_indices.unsqueeze(-1).expand(-1, -1, hidden_size) | |
| return read, keys.gather(1, gather), values.gather(1, gather), final_scores | |
| initial_count = keys.shape[1] | |
| candidate_keys = torch.cat([keys, projected_keys], dim=1) | |
| candidate_values = torch.cat([values, projected_values], dim=1) | |
| candidate_scores = torch.cat([scores, new_scores], dim=1) | |
| candidate_count = candidate_keys.shape[1] | |
| keep = min(self.config.associative_slots, candidate_count) | |
| token_index = torch.arange(hidden.shape[1], device=hidden.device).view(1, -1, 1) | |
| candidate_index = torch.arange(candidate_count, device=hidden.device).view(1, 1, -1) | |
| allowed = candidate_index < (initial_count + token_index) | |
| ranked = candidate_scores.unsqueeze(1).expand(-1, hidden.shape[1], -1).masked_fill(~allowed, float("-inf")) | |
| _top_scores, top_indices = ranked.topk(keep, dim=-1) | |
| # Do not expand candidates to [B, T, C, H] before gather. Although that | |
| # expansion is a cheap forward view, GatherBackward allocates its full | |
| # gradient (42+ GiB for T=3340/H=1024). Flattened batch offsets let | |
| # IndexSelectBackward accumulate directly into the compact [B, C, H] | |
| # candidate table while returning the identical [B, T, K, H] values. | |
| batch_offsets = ( | |
| torch.arange(batch, device=hidden.device, dtype=top_indices.dtype) | |
| * candidate_count | |
| ).view(batch, 1, 1) | |
| flat_indices = (top_indices + batch_offsets).reshape(-1) | |
| selected_shape = (*top_indices.shape, hidden_size) | |
| selected_keys = candidate_keys.reshape( | |
| batch * candidate_count, hidden_size | |
| ).index_select(0, flat_indices).reshape(selected_shape) | |
| selected_values = candidate_values.reshape( | |
| batch * candidate_count, hidden_size | |
| ).index_select(0, flat_indices).reshape(selected_shape) | |
| selected_scores = candidate_scores.unsqueeze(1).expand(-1, hidden.shape[1], -1).gather(2, top_indices) | |
| selected_valid = allowed.expand(hidden.shape[0], -1, -1).gather(2, top_indices) | |
| logits = torch.einsum("bth,btkh->btk", projected_queries.float(), selected_keys.float()) | |
| logits = logits / math.sqrt(hidden_size) | |
| logits = logits + selected_scores.float().clamp_min(1e-8).log() | |
| logits = logits.masked_fill(~selected_valid, -1e9) | |
| probs = torch.softmax(logits, dim=-1).to(hidden.dtype) * selected_valid.to(hidden.dtype) | |
| probs = probs / probs.sum(dim=-1, keepdim=True).clamp_min(1e-8) | |
| reads = torch.einsum("btk,btkh->bth", probs, selected_values) | |
| final_keep = min(self.config.associative_slots, candidate_count) | |
| final_scores, final_indices = candidate_scores.topk(final_keep, dim=1) | |
| final_gather = final_indices.unsqueeze(-1).expand(-1, -1, hidden_size) | |
| final_keys = candidate_keys.gather(1, final_gather) | |
| final_values = candidate_values.gather(1, final_gather) | |
| return reads, final_keys, final_values, final_scores | |
| def _route_mix( | |
| self, | |
| hidden: torch.Tensor, | |
| attention: torch.Tensor, | |
| local_attention: torch.Tensor, | |
| memory: torch.Tensor, | |
| workspace: torch.Tensor, | |
| associative: torch.Tensor, | |
| controls: dict[str, torch.Tensor], | |
| layout: DendroModalityLayout, | |
| effort_condition: torch.Tensor | None = None, | |
| *, | |
| effort_level: float = 0.0, | |
| phase: str = "base", | |
| phase_progress: float = 1.0, | |
| ) -> tuple[torch.Tensor, torch.Tensor]: | |
| source = self.source | |
| del layout | |
| local = source.project(local_attention, "routes/local", self.config.hidden_size, low_bit=False) | |
| residual_route = source.project(hidden, "routes/residual", self.config.hidden_size, low_bit=False) | |
| components = [attention, local, memory, workspace, associative, residual_route] | |
| while len(components) < self.config.num_routes: | |
| index = len(components) | |
| components.append(source.project(hidden, f"routes/aux_{index}", self.config.hidden_size, low_bit=False)) | |
| components = components[: self.config.num_routes] | |
| route_logits = source.project(hidden, "routes/router", self.config.num_routes, low_bit=False) | |
| if effort_condition is not None: | |
| route_logits = route_logits + float( | |
| self.config.reasoning_effort_conditioning_strength | |
| ) * source.project( | |
| effort_condition, | |
| "routes/router", | |
| self.config.num_routes, | |
| bias=False, | |
| low_bit=False, | |
| ) | |
| prior_strength = float(self.config.reasoning_route_prior_strength) | |
| if prior_strength > 0.0 and self.config.num_routes > 0: | |
| # Route order is attention, local, memory, workspace, associative, | |
| # residual. Deliberation should increasingly consult shared memory | |
| # and workspace rather than repeatedly amplifying the residual path. | |
| # This is an architectural prior, not a task-answer heuristic, and it | |
| # introduces no parameters or checkpoint memory. | |
| semantic_prior = hidden.new_tensor( | |
| [0.25, -0.25, 0.35, 0.55, 0.45, -0.55] | |
| ) | |
| if self.config.num_routes < semantic_prior.numel(): | |
| semantic_prior = semantic_prior[: self.config.num_routes] | |
| elif self.config.num_routes > semantic_prior.numel(): | |
| semantic_prior = F.pad( | |
| semantic_prior, | |
| (0, self.config.num_routes - semantic_prior.numel()), | |
| ) | |
| semantic_prior = semantic_prior - semantic_prior.mean() | |
| level = min(1.0, max(0.0, float(effort_level))) | |
| progress = min(1.0, max(0.0, float(phase_progress))) | |
| if phase == "base": | |
| phase_gain = 0.25 * level | |
| elif phase == "reasoning": | |
| phase_gain = (0.75 + 0.25 * level) * (0.75 + 0.25 * progress) | |
| elif phase == "verification": | |
| phase_gain = 1.0 | |
| else: | |
| phase_gain = 0.50 * level | |
| route_logits = route_logits + prior_strength * phase_gain * semantic_prior | |
| focus = controls["attention_focus"] | |
| if self.config.num_routes > 0: | |
| route_logits[..., :1] = route_logits[..., :1] + focus | |
| route_probs = torch.softmax(route_logits.float(), dim=-1).to(hidden.dtype) | |
| stacked = torch.stack(components, dim=-2) | |
| mixed = (route_probs.unsqueeze(-1) * stacked).sum(dim=-2) | |
| return mixed, route_probs | |
| def _shared_routed_ffn( | |
| self, | |
| hidden: torch.Tensor, | |
| effort_condition: torch.Tensor | None = None, | |
| ) -> tuple[torch.Tensor, torch.Tensor]: | |
| source = self.source | |
| normalized = source.rms_norm(hidden, "cell/ffn/input_norm", eps=self.config.layer_norm_eps) | |
| gate, value = source.project_many( | |
| normalized, | |
| ( | |
| ("cell/ffn/gate", self.config.intermediate_size, None), | |
| ("cell/ffn/value", self.config.intermediate_size, None), | |
| ), | |
| ) | |
| router_logits = source.project(normalized, "cell/ffn/expert_router", self.config.num_experts, low_bit=False) | |
| if effort_condition is not None: | |
| router_logits = router_logits + float( | |
| self.config.reasoning_effort_conditioning_strength | |
| ) * source.project( | |
| effort_condition, | |
| "cell/ffn/expert_router", | |
| self.config.num_experts, | |
| bias=False, | |
| low_bit=False, | |
| ) | |
| probs = torch.softmax(router_logits.float(), dim=-1).to(hidden.dtype) | |
| if self.config.expert_top_k < self.config.num_experts: | |
| top_values, top_indices = probs.topk(self.config.expert_top_k, dim=-1) | |
| sparse = torch.zeros_like(probs).scatter(-1, top_indices, top_values) | |
| probs = sparse / sparse.sum(dim=-1, keepdim=True).clamp_min(1e-8) | |
| # Experts are source-derived channel phenotypes over one shared FFN, not | |
| # duplicated expert matrices. | |
| expert_codes = self.source.primitive( | |
| "cell/ffn/expert_codes", | |
| (self.config.num_experts, self.config.intermediate_size), | |
| ) | |
| modulation = torch.matmul(probs, expert_codes) | |
| activated = F.silu(gate) * value * (1.0 + 0.15 * torch.tanh(modulation)) | |
| output = source.project(activated, "cell/ffn/down", self.config.hidden_size) | |
| return output, probs | |
| def _coherence_and_entropy( | |
| self, | |
| hidden: torch.Tensor, | |
| proposal: torch.Tensor, | |
| controls: dict[str, torch.Tensor], | |
| *, | |
| phase: str, | |
| ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: | |
| source = self.source | |
| identity = source.project(hidden, "coherence/identity", self.config.hidden_size, low_bit=False) | |
| whole = source.project(proposal, "coherence/whole", self.config.hidden_size, low_bit=False) | |
| coherence = F.cosine_similarity(identity.float(), whole.float(), dim=-1).unsqueeze(-1).to(hidden.dtype) | |
| residual_gate = controls["residual_gate"] * torch.sigmoid(2.0 * coherence) | |
| merged = hidden + self.config.residual_scale * residual_gate * proposal | |
| normalized = source.rms_norm(merged, "entropy/input_norm", eps=self.config.layer_norm_eps) | |
| compressed = source.project(normalized, "entropy/compression", self.config.hidden_size, low_bit=False) | |
| merged = merged + 0.10 * controls["entropy_compress"] * torch.tanh(compressed) | |
| # Dream/reflection is deterministic and source-derived. It introduces no | |
| # random inference drift and remains cache-parity friendly. | |
| dream = source.project(torch.sin(normalized), "dream/reflection", self.config.hidden_size, low_bit=False) | |
| phase_strength = 1.0 if phase in {"reasoning", "verification", "dream"} else 0.25 | |
| merged = merged + 0.05 * phase_strength * controls["dream_gate"] * torch.tanh(dream) | |
| readiness = source.gate(torch.cat([merged, whole], dim=-1), "reasoning/readiness", 1) | |
| contradiction = source.gate(torch.cat([merged, -whole], dim=-1), "reasoning/contradiction", 1) | |
| correction_strength = float(self.config.reasoning_correction_strength) | |
| if correction_strength > 0.0: | |
| # A signed gate is neutral when both uncalibrated heads sit at 0.5. | |
| # Once trained, readiness advances a proposal while contradiction | |
| # suppresses or reverses it. The feature is opt-in for compatibility. | |
| correction_gate = (readiness - contradiction).clamp(-1.0, 1.0) | |
| correction_phase = 1.0 if phase in {"reasoning", "verification"} else 0.25 | |
| merged = ( | |
| merged | |
| + correction_strength | |
| * correction_phase | |
| * correction_gate | |
| * torch.tanh(proposal) | |
| ) | |
| return merged, coherence, readiness, contradiction | |
| def _update_runtime_state( | |
| self, | |
| *, | |
| memory: torch.Tensor, | |
| memory_scores: torch.Tensor, | |
| workspace: torch.Tensor, | |
| associative_keys: torch.Tensor, | |
| associative_values: torch.Tensor, | |
| associative_scores: torch.Tensor, | |
| route_probs: torch.Tensor, | |
| plasticity_trace: torch.Tensor, | |
| communication: torch.Tensor, | |
| depth_idx: int, | |
| cache: DendroKVCache, | |
| ) -> None: | |
| # The tokenwise scans already produced the exact causal final states. This | |
| # method only commits them to the cache; it performs no second hidden update. | |
| cache.set_runtime_state("memory", memory, depth_idx) | |
| cache.set_runtime_state("memory_scores", memory_scores, depth_idx) | |
| cache.set_runtime_state("workspace", workspace, depth_idx) | |
| cache.set_runtime_state("plasticity_trace", plasticity_trace, depth_idx) | |
| cache.set_runtime_state("head_communication", communication, depth_idx) | |
| route_mean = route_probs.mean(dim=1) | |
| old_route = cache.get_runtime_state("route_history", depth_idx) | |
| route_history = route_mean if old_route is None else 0.90 * old_route.to(route_mean.device) + 0.10 * route_mean | |
| cache.set_runtime_state("route_history", route_history, depth_idx) | |
| cache.set_runtime_state("associative_keys", associative_keys, depth_idx) | |
| cache.set_runtime_state("associative_values", associative_values, depth_idx) | |
| cache.set_runtime_state("associative_scores", associative_scores, depth_idx) | |
| def forward( | |
| self, | |
| hidden_states: torch.Tensor, | |
| *, | |
| layout: DendroModalityLayout, | |
| depth_idx: int, | |
| phase: str = "base", | |
| effort_id: int = 0, | |
| effort_level: float = 0.0, | |
| phase_progress: float = 1.0, | |
| remaining_budget_fraction: float = 0.0, | |
| cache: DendroKVCache | None = None, | |
| use_cache: bool = False, | |
| output_attentions: bool = False, | |
| ) -> DendroCellOutput: | |
| if hidden_states.ndim != 3 or hidden_states.shape[-1] != self.config.hidden_size: | |
| raise ValueError("hidden_states must be [batch, sequence, hidden_size]") | |
| if not 0 <= depth_idx < self.config.max_recurrent_depth: | |
| raise ValueError("depth_idx exceeds max_recurrent_depth") | |
| source = self.source | |
| conditioned, effort_condition = self._depth_condition( | |
| hidden_states, | |
| depth_idx, | |
| phase, | |
| effort_id=effort_id, | |
| effort_level=effort_level, | |
| phase_progress=phase_progress, | |
| remaining_budget_fraction=remaining_budget_fraction, | |
| ) | |
| normalized = source.rms_norm(conditioned, "cell/input_norm", eps=self.config.layer_norm_eps) | |
| climate, controls = self._climate( | |
| normalized, | |
| layout=layout, | |
| depth_idx=depth_idx, | |
| cache=cache, | |
| ) | |
| salience, novelty, token_trace, final_trace = self._plasticity( | |
| normalized, | |
| controls, | |
| layout, | |
| depth_idx, | |
| cache, | |
| ) | |
| attention, local_attention, attention_weights, communication, diagnostics = self._attention( | |
| normalized, | |
| layout=layout, | |
| controls=controls, | |
| plasticity_trace=token_trace, | |
| depth_idx=depth_idx, | |
| cache=cache, | |
| use_cache=use_cache, | |
| output_attentions=output_attentions, | |
| ) | |
| memory_slots = self._memory_slots(normalized, cache, depth_idx) | |
| workspace_slots = self._workspace_slots(normalized, cache, depth_idx) | |
| memory_read, final_memory, memory_scores = self._slot_scan( | |
| normalized, | |
| memory_slots, | |
| controls, | |
| layout, | |
| "memory", | |
| ) | |
| workspace_read, final_workspace, _workspace_scores = self._slot_scan( | |
| normalized, | |
| workspace_slots, | |
| controls, | |
| layout, | |
| "workspace", | |
| ) | |
| associative_read, associative_keys, associative_values, associative_scores = self._associative_scan( | |
| normalized, | |
| salience, | |
| layout, | |
| cache, | |
| depth_idx, | |
| ) | |
| mixed, route_probs = self._route_mix( | |
| normalized, | |
| attention, | |
| local_attention, | |
| memory_read, | |
| workspace_read, | |
| associative_read, | |
| controls, | |
| layout, | |
| effort_condition, | |
| effort_level=effort_level, | |
| phase=phase, | |
| phase_progress=phase_progress, | |
| ) | |
| attention_out = source.project(mixed, "cell/attention/output", self.config.hidden_size) | |
| hidden = conditioned + self.config.residual_scale * controls["residual_gate"] * attention_out | |
| ffn_out, expert_probs = self._shared_routed_ffn(hidden, effort_condition) | |
| hidden, coherence, readiness, contradiction = self._coherence_and_entropy( | |
| hidden, | |
| ffn_out, | |
| controls, | |
| phase=phase, | |
| ) | |
| hidden = F.dropout(hidden, p=self.config.dropout, training=self.training) | |
| hidden = hidden * layout.attention_mask.unsqueeze(-1).to(hidden.dtype) | |
| if use_cache: | |
| assert cache is not None | |
| self._update_runtime_state( | |
| memory=final_memory, | |
| memory_scores=memory_scores, | |
| workspace=final_workspace, | |
| associative_keys=associative_keys, | |
| associative_values=associative_values, | |
| associative_scores=associative_scores, | |
| route_probs=route_probs, | |
| plasticity_trace=final_trace, | |
| communication=communication, | |
| depth_idx=depth_idx, | |
| cache=cache, | |
| ) | |
| attention_entropy, top_indices = diagnostics if diagnostics is not None else (None, None) | |
| state = DendroCellState( | |
| depth_index=depth_idx, | |
| phase=phase, | |
| activation_heat=climate["activation_heat"], | |
| entropy_pressure=climate["entropy"], | |
| novelty=novelty, | |
| salience=salience, | |
| route_probs=route_probs, | |
| expert_probs=expert_probs, | |
| coherence=coherence, | |
| residual_gate=controls["residual_gate"], | |
| memory_write_strength=controls["memory_write"], | |
| workspace_write_strength=controls["workspace_write"], | |
| plasticity_rate=controls["plasticity_rate"], | |
| readiness=readiness, | |
| contradiction=contradiction, | |
| attention_entropy=attention_entropy, | |
| top_attention_indices=top_indices, | |
| ) | |
| return DendroCellOutput( | |
| hidden_states=hidden, | |
| cache=cache, | |
| state=state, | |
| attention_weights=attention_weights, | |
| ) | |