| """Configuration for STRATA neural models.""" |
|
|
| from __future__ import annotations |
|
|
| import json |
| from dataclasses import asdict, dataclass |
| from pathlib import Path |
| from typing import Any |
|
|
|
|
| @dataclass(frozen=True, slots=True) |
| class StrataConfig: |
| """Plain-PyTorch decoder configuration. |
| |
| The config intentionally has no DeepSpeed, CPU offload, or distributed |
| runtime knobs. Those concerns must stay outside the core model. |
| """ |
|
|
| vocab_size: int = 64_288 |
| max_position_embeddings: int = 4096 |
| d_model: int = 768 |
| num_layers: int = 12 |
| num_heads: int = 12 |
| d_ff: int = 3072 |
| dropout: float = 0.0 |
| local_attention_window: int = 1024 |
| predicate_block_every: int = 3 |
| graph_relation_types: int = 16 |
| node_type_vocab_size: int = 16 |
| chart_type_vocab_size: int = 64 |
| max_graph_edges_per_token: int = 8 |
| use_attention_bias_from_graph: bool = True |
| |
| |
| use_graph_object_memory: bool = False |
| graph_object_relation_types: int = 70 |
| graph_object_node_types: int = 20 |
| graph_object_gate_init: float = -4.0 |
| |
| |
| |
| graph_object_relation_conditioned_messages: bool = False |
| |
| |
| |
| |
| graph_object_predicate_slot_memory: bool = False |
| |
| |
| |
| emit_all_block_graph_heads: bool = False |
| tie_word_embeddings: bool = True |
| initializer_range: float = 0.02 |
| pad_token_id: int = 0 |
| bos_token_id: int = 1 |
| eos_token_id: int = 2 |
|
|
| def __post_init__(self) -> None: |
| self.validate() |
|
|
| def validate(self) -> None: |
| if self.vocab_size <= 0: |
| raise ValueError("vocab_size must be positive") |
| if self.max_position_embeddings <= 0: |
| raise ValueError("max_position_embeddings must be positive") |
| if self.d_model <= 0: |
| raise ValueError("d_model must be positive") |
| if self.num_layers <= 0: |
| raise ValueError("num_layers must be positive") |
| if self.num_heads <= 0: |
| raise ValueError("num_heads must be positive") |
| if self.d_model % self.num_heads != 0: |
| raise ValueError("d_model must be divisible by num_heads") |
| if self.d_ff <= 0: |
| raise ValueError("d_ff must be positive") |
| if not 0.0 <= self.dropout < 1.0: |
| raise ValueError("dropout must be in [0, 1)") |
| if self.local_attention_window <= 0: |
| raise ValueError("local_attention_window must be positive") |
| if self.predicate_block_every <= 0: |
| raise ValueError("predicate_block_every must be positive") |
| if self.graph_relation_types <= 0: |
| raise ValueError("graph_relation_types must be positive") |
| if self.node_type_vocab_size <= 0: |
| raise ValueError("node_type_vocab_size must be positive") |
| if self.chart_type_vocab_size <= 0: |
| raise ValueError("chart_type_vocab_size must be positive") |
| if self.max_graph_edges_per_token <= 0: |
| raise ValueError("max_graph_edges_per_token must be positive") |
| if self.graph_object_relation_types <= 0: |
| raise ValueError("graph_object_relation_types must be positive") |
| if self.graph_object_node_types <= 0: |
| raise ValueError("graph_object_node_types must be positive") |
|
|
| @property |
| def head_dim(self) -> int: |
| return self.d_model // self.num_heads |
|
|
| def to_dict(self) -> dict[str, Any]: |
| return asdict(self) |
|
|
| @classmethod |
| def from_dict(cls, values: dict[str, Any]) -> "StrataConfig": |
| return cls(**values) |
|
|
| @classmethod |
| def from_json_file(cls, path: str | Path) -> "StrataConfig": |
| with Path(path).open("r", encoding="utf-8") as handle: |
| payload = json.load(handle) |
| if not isinstance(payload, dict): |
| raise ValueError("config JSON must contain an object") |
| return cls.from_dict(payload) |
|
|
| def to_json_file(self, path: str | Path) -> None: |
| destination = Path(path) |
| destination.parent.mkdir(parents=True, exist_ok=True) |
| with destination.open("w", encoding="utf-8") as handle: |
| json.dump(self.to_dict(), handle, indent=2, sort_keys=True) |
| handle.write("\n") |
|
|