"""Exact staged evaluation of split canonical routing and value translation.""" from __future__ import annotations import gc from pathlib import Path import random import time import torch import torch.nn.functional as F from transformers import AutoModelForCausalLM, AutoTokenizer from pcm.planner.canonical import CanonicalPConfig, CanonicalPStore from pcm.planner.cache import SlotSource from pcm.planner.pythia_split_translate import PythiaSplitTranslatedModel from pcm.planner.pythia_split_translate import pythia_model_identifier from pcm.planner.representation import CANONICAL, HISTORICAL, FactorizedStateRepresentation from pcm.planner.split_translator import ( ByteEntityEncoder, CanonicalPRouter, CanonicalRouterIndex, FactorizedCanonicalQuery, FrozenLexicalAnchorProjector, RouterConfig, SplitPTranslatePackage, SplitTranslateConfig, config_checksum, ) from pcm.planner.canonical import CANONICAL_VALUE_LABELS as VALUE_LABELS ADJECTIVES = tuple( "silver gold crimson azure ivory ebony amber jade copper iron crystal shadow bright " "quiet ancient hidden broken little grand northern southern eastern western moon sun " "star river storm winter summer autumn".split() ) NOUNS = tuple( "key ring blade crown lantern compass chalice mirror scroll seal pendant coin map book " "box door tower bridge garden harbor temple forest castle chamber wagon banner stone " "cloak staff mask bell".split() ) RELATION_PROMPTS = ( "The owner of the {entity} is", "The current location of the {entity} is", "The current status of the {entity} is", ) HELDOUT_LEADS = ( "After a long unrelated scene at the inn, ", "Following several jokes and descriptions of the rainy road, ", ) TRAIN_LEADS = ( "After unrelated conversation, ", "With the source state absent from recent context, ", ) SLOT_SIZES = (4, 20, 64, 128, 256, 512) def entity_split(): train, heldout = [], [] for adjective_index, adjective in enumerate(ADJECTIVES): for noun_index, noun in enumerate(NOUNS): surface = f"{adjective} {noun}" target = heldout if (adjective_index * 31 + noun_index * 17) % 5 == 0 else train target.append(surface) for required in ("silver key", "gold key"): if required in train: train.remove(required) heldout.append(required) return train, heldout def _bytes(parameters) -> int: return sum(parameter.numel() * parameter.element_size() for parameter in parameters) def run_split_translator_experiment( path: str | Path, representation: FactorizedStateRepresentation, *, attachment_count: int, query_steps: int = 400, router_steps: int = 400, value_steps: int = 400, causal_steps: int = 256, seed: int = 307, package_path: str | Path | None = None, router_path: str | Path | None = None, ): if attachment_count not in (1, 2, 4): raise ValueError("attachment_count must be 1, 2, or 4") if not torch.cuda.is_available(): raise RuntimeError("CUDA is required") torch.manual_seed(seed) rng = random.Random(seed) path = Path(path) tokenizer = AutoTokenizer.from_pretrained(path, local_files_only=True) tokenizer.pad_token = tokenizer.eos_token tokenizer.padding_side = "left" base = AutoModelForCausalLM.from_pretrained( path, local_files_only=True, dtype=torch.float16, low_cpu_mem_usage=True ).to("cuda").eval() depth = len(base.gpt_neox.layers) layers = tuple(range(depth - attachment_count, depth)) package = SplitPTranslatePackage(SplitTranslateConfig( model_id=pythia_model_identifier(base), model_hidden_width=int(base.config.hidden_size), attachment_layers=layers, model_config_sha256=config_checksum(base.config), top_k=1, )).to("cuda", dtype=torch.float32) router = CanonicalPRouter(RouterConfig()).to("cuda") byte_encoder = ByteEntityEncoder(128) wrapper = PythiaSplitTranslatedModel(base, package, router, byte_encoder).to("cuda").train() representation.eval() all_train_surfaces, all_heldout_surfaces = entity_split() split_rng = random.Random(seed + 1) train_surfaces = split_rng.sample(all_train_surfaces, 256) required = ["silver key", "gold key"] train_adjectives = {surface.split()[0] for surface in train_surfaces} train_nouns = {surface.split()[1] for surface in train_surfaces} compositional_heldout = [ surface for surface in all_heldout_surfaces if surface.split()[0] in train_adjectives and surface.split()[1] in train_nouns and surface not in required ] heldout_surfaces = required + compositional_heldout[:62] train_surface_set = set(train_surfaces) assert not train_surface_set.intersection(heldout_surfaces) encoded_values = [tokenizer.encode(" " + value, add_special_tokens=False) for value in VALUE_LABELS] if any(len(ids) != 1 for ids in encoded_values): raise RuntimeError("controlled values must be single Pythia tokens") value_token_ids = [ids[0] for ids in encoded_values] lm_values = base.get_output_embeddings().weight[value_token_ids].detach().float() normalized_lm_values = F.normalize(lm_values, dim=-1) def query_texts(surfaces, relations, leads): texts, names, relation_ids = [], [], [] for lead in leads: for surface, relation in zip(surfaces, relations): texts.append(lead + RELATION_PROMPTS[relation].format(entity=surface)) names.append(surface) relation_ids.append(relation) return texts, names, relation_ids def tokenize(texts): return tokenizer( texts, return_tensors="pt", padding=True, add_special_tokens=False ).to("cuda") def capture(texts, chunk=24): by_layer = {layer: [] for layer in layers} handles = [ base.gpt_neox.layers[layer].register_forward_hook( lambda _module, _inputs, output, layer=layer: by_layer[layer].append( output[:, -1].detach().cpu() ) ) for layer in layers ] for start in range(0, len(texts), chunk): with torch.inference_mode(): wrapper(**tokenize(texts[start:start + chunk]), use_cache=False) for handle in handles: handle.remove() return torch.stack([ torch.cat(by_layer[layer]).to("cuda") for layer in layers ]) train_relations = [index % 3 for index in range(len(train_surfaces))] train_texts, train_names, train_relation_ids = query_texts( train_surfaces, train_relations, TRAIN_LEADS ) train_hidden = capture(train_texts) train_names = train_names train_relation_ids = torch.tensor(train_relation_ids, device="cuda") train_entity_targets = byte_encoder(train_names).to("cuda") heldout_relations = [index % 3 for index in range(len(heldout_surfaces))] heldout_texts, heldout_names, heldout_relation_ids = query_texts( heldout_surfaces, heldout_relations, (HELDOUT_LEADS[0],) ) heldout_hidden = capture(heldout_texts) heldout_relation_ids = torch.tensor(heldout_relation_ids, device="cuda") heldout_entity_targets = byte_encoder(heldout_names).to("cuda") query_optimizer = torch.optim.AdamW(package.query_projector.parameters(), lr=2e-3, eps=1e-6) query_losses = [] for _ in range(query_steps): surface_indices = rng.sample(range(len(train_surfaces)), 32) hidden = torch.stack([ train_hidden[rng.randrange(attachment_count), index] for index in surface_indices ]) projected = package.query_projector(hidden) targets = byte_encoder([train_surfaces[index] for index in surface_indices]).to("cuda") relations = torch.tensor( [train_relations[index] for index in surface_indices], device="cuda" ) entity_loss = 1 - F.cosine_similarity(projected.entity, targets, dim=-1).mean() contrastive = F.cross_entropy( projected.entity @ targets.T / 0.07, torch.arange(len(surface_indices), device="cuda"), ) relation_loss = F.cross_entropy(projected.relation_logits, relations) metadata_loss = F.cross_entropy( projected.metadata_logits, torch.zeros(len(surface_indices), dtype=torch.long, device="cuda"), ) loss = entity_loss + contrastive + relation_loss + 0.25 * metadata_loss query_optimizer.zero_grad(set_to_none=True) loss.backward() query_optimizer.step() query_losses.append(float(loss.detach())) del query_optimizer def query_metrics(hidden, names, relations): with torch.inference_mode(): projected = package.query_projector(hidden.mean(0)) targets = byte_encoder(names).to("cuda") entity_scores = projected.entity @ targets.T return { "entity_accuracy": float(( entity_scores.argmax(-1) == torch.arange(len(names), device="cuda") ).float().mean()), "relation_accuracy": float(( projected.relation_logits.argmax(-1) == relations ).float().mean()), "metadata_accuracy": float(( projected.metadata_logits.argmax(-1) == 0 ).float().mean()), "entity_cosine": float(F.cosine_similarity( projected.entity, targets, dim=-1 ).mean()), } query_heldout_metrics = query_metrics( heldout_hidden, heldout_names, heldout_relation_ids ) byte_surface_metrics = { "entity_accuracy": 1.0, "relation_accuracy": query_heldout_metrics["relation_accuracy"], "metadata_accuracy": query_heldout_metrics["metadata_accuracy"], "entity_cosine": 1.0, "tokenizer_independent": True, "oracle_slot_assignments": 0, } lexical_projector = FrozenLexicalAnchorProjector(int(base.config.hidden_size)).to("cuda") embedding = base.get_input_embeddings().weight.detach() def lexical(surfaces): values = [] for surface in surfaces: ids = tokenizer.encode(" " + surface, add_special_tokens=False) values.append(embedding[torch.tensor(ids, device="cuda")].float().mean(0)) return torch.stack(values) train_lexical = lexical(train_surfaces) lexical_optimizer = torch.optim.AdamW(lexical_projector.parameters(), lr=2e-3) for _ in range(query_steps): indices = torch.tensor(rng.sample(range(len(train_surfaces)), 32), device="cuda") output = lexical_projector(train_lexical.index_select(0, indices)) target = byte_encoder([train_surfaces[int(index)] for index in indices]).to("cuda") loss = 1 - F.cosine_similarity(output, target, dim=-1).mean() lexical_optimizer.zero_grad(set_to_none=True) loss.backward() lexical_optimizer.step() with torch.inference_mode(): lexical_output = lexical_projector(lexical(heldout_surfaces)) lexical_targets = byte_encoder(heldout_surfaces).to("cuda") lexical_metrics = { "entity_accuracy": float(( (lexical_output @ lexical_targets.T).argmax(-1) == torch.arange(len(heldout_surfaces), device="cuda") ).float().mean()), "entity_cosine": float(F.cosine_similarity( lexical_output, lexical_targets, dim=-1 ).mean()), } del lexical_optimizer, lexical_projector, train_lexical for parameter in package.query_projector.parameters(): parameter.requires_grad_(False) router_optimizer = torch.optim.AdamW(router.parameters(), lr=1e-2) router_losses = [] for _ in range(router_steps): source_index = rng.randrange(len(train_names)) correct_surface = train_names[source_index] relation = int(train_relation_ids[source_index]) relation_logits = torch.full((1, 3), -12.0, device="cuda") relation_logits[0, relation] = 12.0 query = FactorizedCanonicalQuery( entity=byte_encoder([correct_surface]).to("cuda"), relation_logits=relation_logits, metadata_logits=torch.tensor([[12.0, -12.0, -12.0, -12.0]], device="cuda"), ) candidates = [correct_surface, rng.choice(train_surfaces)] while candidates[1] == correct_surface: candidates[1] = rng.choice(train_surfaces) candidates.extend((correct_surface, correct_surface)) candidate_relations = [relation, relation, (relation + 1) % 3, relation] candidate_metadata = [CANONICAL, CANONICAL, CANONICAL, HISTORICAL] while len(candidates) < 128: candidates.append(rng.choice(train_surfaces)) candidate_relations.append(rng.randrange(3)) candidate_metadata.append(CANONICAL) permutation = list(range(len(candidates))) rng.shuffle(permutation) candidates = [candidates[index] for index in permutation] index = CanonicalRouterIndex( entity=byte_encoder(candidates).to("cuda"), relation_id=torch.tensor([candidate_relations[i] for i in permutation], device="cuda"), metadata_id=torch.tensor([candidate_metadata[i] for i in permutation], device="cuda"), valid=torch.ones(len(candidates), dtype=torch.bool, device="cuda"), ) target = torch.tensor([permutation.index(0)], device="cuda") scores, _ = router.all_scores(query, index) labels = torch.zeros_like(scores) labels[:, target] = 1.0 loss = F.cross_entropy(scores, target) + F.binary_cross_entropy_with_logits( scores, labels, pos_weight=torch.tensor([len(candidates) - 1.0], device="cuda") ) router_optimizer.zero_grad(set_to_none=True) loss.backward() router_optimizer.step() router_losses.append(float(loss.detach())) del router_optimizer calibration_positive = [] calibration_negative = [] with torch.inference_mode(): for calibration_index in range(128): surface = train_surfaces[calibration_index] relation = calibration_index % 3 wrong = train_surfaces[(calibration_index + 37) % len(train_surfaces)] query = FactorizedCanonicalQuery( entity=byte_encoder([surface]).to("cuda"), relation_logits=torch.full((1, 3), -12.0, device="cuda"), metadata_logits=torch.tensor([[12.0, -12.0, -12.0, -12.0]], device="cuda"), ) query.relation_logits[0, relation] = 12.0 index = CanonicalRouterIndex( entity=byte_encoder([surface, wrong, surface, surface]).to("cuda"), relation_id=torch.tensor([relation, relation, (relation + 1) % 3, relation], device="cuda"), metadata_id=torch.tensor([CANONICAL, CANONICAL, CANONICAL, HISTORICAL], device="cuda"), valid=torch.ones(4, dtype=torch.bool, device="cuda"), ) scores, _ = router.all_scores(query, index) calibration_positive.append(scores[0, 0]) calibration_negative.extend(scores[0, 1:]) calibration_balanced_accuracy = router.calibrate_acceptance( torch.stack(calibration_positive), torch.stack(calibration_negative) ) for parameter in router.parameters(): parameter.requires_grad_(False) for parameter in package.query_projector.parameters(): parameter.requires_grad_(True) def canonical_vector(entity_id, relation, value, metadata=CANONICAL): with torch.inference_mode(): vector = representation.encode( torch.tensor([entity_id % 24]), torch.tensor([relation]), torch.tensor([value % 36]), torch.tensor([metadata]), )[0] return vector.to("cuda", dtype=torch.float16) value_optimizer = torch.optim.AdamW(package.value_translator.parameters(), lr=2e-3, eps=1e-6) value_losses = [] for _ in range(value_steps): entity_ids = [rng.randrange(24) for _ in range(32)] relations = [rng.randrange(3) for _ in range(32)] values = [rng.randrange(36) for _ in range(32)] canonical = torch.stack([ canonical_vector(entity, relation, value).float() for entity, relation, value in zip(entity_ids, relations, values) ]) translated = package.value_translator(canonical) normalized = F.normalize(translated, dim=-1) targets = torch.tensor(values, device="cuda") loss = ( 1 - F.cosine_similarity( normalized, normalized_lm_values.index_select(0, targets), dim=-1 ).mean() + F.cross_entropy(normalized @ normalized_lm_values.T / 0.07, targets) ) value_optimizer.zero_grad(set_to_none=True) loss.backward() value_optimizer.step() value_losses.append(float(loss.detach())) del value_optimizer with torch.inference_mode(): heldout_value_ids = torch.arange(36, device="cuda") heldout_vectors = torch.stack([ canonical_vector(index % 24, index % 3, index).float() for index in range(36) ]) heldout_value_output = F.normalize( package.value_translator(heldout_vectors), dim=-1 ) value_metrics = { "accuracy": float(( (heldout_value_output @ normalized_lm_values.T).argmax(-1) == heldout_value_ids ).float().mean()), "cosine": float(F.cosine_similarity( heldout_value_output, normalized_lm_values, dim=-1 ).mean()), } rp_preserve = tokenize([ "A patient tailor compared blue ribbons while rain ticked softly against the shop window.", "Two actors rehearsed a harmless joke and rearranged wooden chairs beside the empty stage.", ]) rp_eval = tokenize([ "At dusk, a baker swept flour from the counter while neighbors debated tomorrow's parade.", "A sleepy musician closed the balcony doors and described clouds drifting above the orchard.", ]) with torch.inference_mode(): frozen_rp_preserve = wrapper(**rp_preserve, use_cache=False).logits.detach() frozen_rp_eval = wrapper(**rp_eval, use_cache=False).logits.detach() base_rp_loss = float(wrapper(**rp_eval, labels=rp_eval.input_ids, use_cache=False).loss) train_state_surfaces = train_surfaces[:24] heldout_state_surfaces = heldout_surfaces[:20] train_value_assignment = {surface: index % 36 for index, surface in enumerate(train_state_surfaces)} heldout_value_assignment = {surface: (index * 5 + 3) % 36 for index, surface in enumerate(heldout_state_surfaces)} train_owner_hidden = capture([ TRAIN_LEADS[0] + RELATION_PROMPTS[0].format(entity=surface) for surface in train_state_surfaces ]).mean(0) heldout_owner_hidden = capture([ HELDOUT_LEADS[1] + RELATION_PROMPTS[0].format(entity=surface) for surface in heldout_state_surfaces ]).mean(0) with torch.inference_mode(): owner_queries = package.query_projector( heldout_owner_hidden, entity_anchor=byte_encoder(heldout_state_surfaces).to("cuda"), ) hard_top1 = [] false_positives = { "wrong_entity": [], "wrong_relation": [], "historical": [], "invalidated": [], "irrelevant": [], } for query_index, surface in enumerate(heldout_state_surfaces): wrong_entity = heldout_state_surfaces[(query_index + 1) % len(heldout_state_surfaces)] candidates = [surface, wrong_entity, surface, surface, f"irrelevant {query_index}"] index = CanonicalRouterIndex( entity=byte_encoder(candidates).to("cuda"), relation_id=torch.tensor([0, 0, 1, 0, 2], device="cuda"), metadata_id=torch.tensor([CANONICAL, CANONICAL, CANONICAL, HISTORICAL, CANONICAL], device="cuda"), valid=torch.ones(5, dtype=torch.bool, device="cuda"), ) single_query = FactorizedCanonicalQuery( entity=owner_queries.entity[query_index:query_index + 1], relation_logits=owner_queries.relation_logits[query_index:query_index + 1], metadata_logits=owner_queries.metadata_logits[query_index:query_index + 1], ) scores, _ = router.all_scores(single_query, index) hard_top1.append(int(scores.argmax(-1)) == 0) for label, candidate_index in ( ("wrong_entity", 1), ("wrong_relation", 2), ("historical", 3), ("irrelevant", 4), ): false_positives[label].append( float(scores[0, candidate_index]) >= float(router.acceptance_threshold) ) invalid_index = CanonicalRouterIndex( entity=index.entity[:1], relation_id=index.relation_id[:1], metadata_id=index.metadata_id[:1], valid=torch.zeros(1, dtype=torch.bool, device="cuda"), ) invalid_scores, _ = router.all_scores(single_query, invalid_index) false_positives["invalidated"].append(bool(torch.isfinite(invalid_scores[0, 0]))) router_hard_metrics = { "top1_accuracy": sum(hard_top1) / len(hard_top1), **{ f"{label}_false_positive_rate": sum(values) / len(values) for label, values in false_positives.items() }, } def make_store(entries, slots=None, local_rng=None, metadata=CANONICAL): capacity = slots or max(4, len(entries)) store = CanonicalPStore(CanonicalPConfig( slots=capacity, width=512, dtype=torch.float16, device="cuda", merge_similarity=1.0 )) rows = list(entries) if local_rng: local_rng.shuffle(rows) slot_by_surface = {} for ordinal, (surface, relation, value) in enumerate(rows): slot, _ = store.create( canonical_vector(ordinal, relation, value, metadata), entity_id=ordinal, relation_id=relation, value_id=value, metadata_id=metadata, label=surface, ) slot_by_surface[surface] = slot return store, slot_by_surface def state_inputs(surfaces, lead=TRAIN_LEADS[0], relation=0): return tokenize([ lead + RELATION_PROMPTS[relation].format(entity=surface) for surface in surfaces ]) training_base_logits = {} for lead in TRAIN_LEADS: with torch.inference_mode(): training_base_logits[lead] = wrapper( **state_inputs(train_state_surfaces, lead), use_cache=False ).logits[:, -1].detach() package_optimizer = torch.optim.AdamW(package.parameters(), lr=5e-4, eps=1e-6) causal_losses = [] pre_preservation_ablation = None midpoint_entries = [ (surface, 0, heldout_value_assignment[surface]) for surface in heldout_state_surfaces ] midpoint_store, _ = make_store( midpoint_entries, slots=128, local_rng=random.Random(seed + 800) ) midpoint_inputs = state_inputs(heldout_state_surfaces, HELDOUT_LEADS[1]) midpoint_expected = torch.tensor( [heldout_value_assignment[surface] for surface in heldout_state_surfaces], device="cuda", ) for step in range(causal_steps): surfaces = rng.sample(train_state_surfaces, 8) entries = [(surface, 0, train_value_assignment[surface]) for surface in surfaces] store, _ = make_store(entries, slots=128, local_rng=rng) lead = rng.choice(TRAIN_LEADS) inputs = state_inputs(surfaces, lead) targets = torch.tensor( [value_token_ids[train_value_assignment[surface]] for surface in surfaces], device="cuda", ) output = wrapper( **inputs, p_store=store, query_entity_surfaces=surfaces, use_cache=False ) state_loss = F.cross_entropy(output.logits[:, -1].float(), targets) wrong_entries = [ (rng.choice(train_surfaces[len(train_state_surfaces):]), 0, train_value_assignment[surface]) for surface in surfaces ] wrong_store, _ = make_store(wrong_entries, slots=128) wrong = wrapper( **inputs, p_store=wrong_store, query_entity_surfaces=surfaces, use_cache=False ).logits[:, -1].float() historical_store, _ = make_store(entries, slots=128, metadata=HISTORICAL) historical = wrapper( **inputs, p_store=historical_store, query_entity_surfaces=surfaces, use_cache=False, ).logits[:, -1].float() indices = torch.tensor([train_state_surfaces.index(surface) for surface in surfaces], device="cuda") base_logits = training_base_logits[lead].index_select(0, indices).float() wrong_preserve = F.kl_div( F.log_softmax(base_logits, dim=-1), F.softmax(wrong, dim=-1), reduction="batchmean" ) historical_preserve = F.kl_div( F.log_softmax(base_logits, dim=-1), F.softmax(historical, dim=-1), reduction="batchmean" ) hidden_indices = torch.tensor([ train_state_surfaces.index(surface) for surface in surfaces ], device="cuda") projected = package.query_projector(train_owner_hidden.index_select(0, hidden_indices)) query_loss = ( 1 - F.cosine_similarity( projected.entity, byte_encoder(surfaces).to("cuda"), dim=-1 ).mean() + F.cross_entropy(projected.relation_logits, torch.zeros(8, dtype=torch.long, device="cuda")) ) vectors = torch.stack([ canonical_vector(index, 0, train_value_assignment[surface]).float() for index, surface in enumerate(surfaces) ]) translated = F.normalize(package.value_translator(vectors), dim=-1) value_targets = torch.tensor( [train_value_assignment[surface] for surface in surfaces], device="cuda" ) value_loss = 1 - F.cosine_similarity( translated, normalized_lm_values.index_select(0, value_targets), dim=-1 ).mean() loss = ( state_loss + 0.5 * query_loss + 0.2 * value_loss + 2.0 * wrong_preserve + 2.0 * historical_preserve ) if step >= causal_steps // 2: rp_output = wrapper( **rp_preserve, labels=rp_preserve.input_ids, p_store=store, use_cache=False ) rp_kl = F.kl_div( F.log_softmax(frozen_rp_preserve[:, -1].float(), dim=-1), F.softmax(rp_output.logits[:, -1].float(), dim=-1), reduction="batchmean" ) loss = loss + 0.05 * rp_output.loss.float() + 2.0 * rp_kl package_optimizer.zero_grad(set_to_none=True) loss.backward() torch.nn.utils.clip_grad_norm_(package.parameters(), 1.0) package_optimizer.step() causal_losses.append(float(state_loss.detach())) if step + 1 == causal_steps // 2: with torch.inference_mode(): midpoint_logits = wrapper( **midpoint_inputs, p_store=midpoint_store, query_entity_surfaces=heldout_state_surfaces, use_cache=False, ).logits[:, -1].float() midpoint_rp = wrapper( **rp_eval, labels=rp_eval.input_ids, p_store=midpoint_store, use_cache=False, ) midpoint_rp_kl = F.kl_div( F.log_softmax(frozen_rp_eval[:, -1].float(), dim=-1), F.softmax(midpoint_rp.logits[:, -1].float(), dim=-1), reduction="batchmean", ) pre_preservation_ablation = { "state_loss": float(state_loss.detach()), "state_candidate_accuracy": float(( midpoint_logits[:, value_token_ids].argmax(-1) == midpoint_expected ).float().mean()), "wrong_state_kl": float(wrong_preserve.detach()), "historical_state_kl": float(historical_preserve.detach()), "rp_loss": float(midpoint_rp.loss), "rp_kl": float(midpoint_rp_kl), } del package_optimizer wrapper.eval() def store_bytes(store): tensors = ( store.cache.values, store.cache.valid, store.cache.slot_type, store.cache.confidence, store.cache.importance, store.cache.freshness, store.cache.persistence, store.cache.last_updated, store.cache.source, store.entity_id, store.relation_id, store.value_id, store.canonical_metadata_id, ) return sum(t.numel() * t.element_size() for t in tensors) def index_bytes(index): return sum( tensor.numel() * tensor.element_size() for tensor in (index.entity, index.relation_id, index.metadata_id, index.valid) ) scaling = {} all_distractors = [ surface for surface in train_surfaces + heldout_surfaces if surface not in heldout_state_surfaces ] while len(all_distractors) < 512: all_distractors.append(f"irrelevant entity {len(all_distractors)}") for slot_count in SLOT_SIZES: query_count = min(20, slot_count) query_surfaces = heldout_state_surfaces[:query_count] entries = [ (surface, 0, heldout_value_assignment[surface]) for surface in query_surfaces ] for index in range(slot_count - query_count): entries.append((all_distractors[index], (index + 1) % 3, (index + 7) % 36)) store, slot_map = make_store(entries, slots=slot_count, local_rng=random.Random(seed + slot_count)) inputs = state_inputs(query_surfaces, HELDOUT_LEADS[1]) hidden = capture([ HELDOUT_LEADS[1] + RELATION_PROMPTS[0].format(entity=surface) for surface in query_surfaces ]).mean(0) with torch.inference_mode(): hidden_only_query = package.query_projector(hidden) query = package.query_projector( hidden, entity_anchor=byte_encoder(query_surfaces).to("cuda") ) index = router.build_index(store, byte_encoder, device="cuda") scores, _ = router.all_scores(query, index) expected = torch.tensor([slot_map[surface] for surface in query_surfaces], device="cuda") order = scores.argsort(dim=-1, descending=True) ranks = (order == expected[:, None]).nonzero()[:, 1] + 1 hidden_only_scores, _ = router.all_scores(hidden_only_query, index) hidden_only_order = hidden_only_scores.argsort(dim=-1, descending=True) hidden_only_ranks = ( hidden_only_order == expected[:, None] ).nonzero()[:, 1] + 1 oracle_query = FactorizedCanonicalQuery( entity=byte_encoder(query_surfaces).to("cuda"), relation_logits=torch.tensor([[12.0, -12.0, -12.0]], device="cuda").expand(query_count, -1), metadata_logits=torch.tensor([[12.0, -12.0, -12.0, -12.0]], device="cuda").expand(query_count, -1), ) oracle_scores, _ = router.all_scores(oracle_query, index) oracle_order = oracle_scores.argsort(dim=-1, descending=True) oracle_ranks = (oracle_order == expected[:, None]).nonzero()[:, 1] + 1 route_metrics = { "top1_accuracy": float((ranks == 1).float().mean()), "top2_recall": float((ranks <= 2).float().mean()), "top4_recall": float((ranks <= 4).float().mean()), "mrr": float((1.0 / ranks.float()).mean()), "hidden_only_top1_accuracy": float((hidden_only_ranks == 1).float().mean()), "oracle_query_top1_accuracy": float((oracle_ranks == 1).float().mean()), "oracle_query_top4_recall": float((oracle_ranks <= 4).float().mean()), "oracle_query_mrr": float((1.0 / oracle_ranks.float()).mean()), } logits = wrapper( **inputs, p_store=store, query_entity_surfaces=query_surfaces, use_cache=False, ).logits[:, -1].float() expected_values = torch.tensor( [heldout_value_assignment[surface] for surface in query_surfaces], device="cuda" ) generation_accuracy = float(( logits[:, value_token_ids].argmax(-1) == expected_values ).float().mean()) for _ in range(2): wrapper( **inputs, p_store=store, query_entity_surfaces=query_surfaces, use_cache=False, ) torch.cuda.synchronize() start = time.perf_counter() for _ in range(5): wrapper( **inputs, p_store=store, query_entity_surfaces=query_surfaces, use_cache=False, ) torch.cuda.synchronize() latency = (time.perf_counter() - start) / 5 scaling[str(slot_count)] = { **route_metrics, "state_generation_accuracy": generation_accuracy, "latency_seconds": latency, "active_vram_overhead_bytes": ( _bytes(package.parameters()) + _bytes(router.parameters()) + store_bytes(store) + index_bytes(index) ), } eval_entries = [ (surface, 0, heldout_value_assignment[surface]) for surface in heldout_state_surfaces ] eval_store, eval_slots = make_store(eval_entries, slots=128, local_rng=random.Random(seed + 900)) eval_inputs = state_inputs(heldout_state_surfaces, HELDOUT_LEADS[1]) expected_values = torch.tensor( [heldout_value_assignment[surface] for surface in heldout_state_surfaces], device="cuda" ) expected_tokens = torch.tensor([value_token_ids[int(value)] for value in expected_values], device="cuda") oracle_indices = torch.tensor([eval_slots[surface] for surface in heldout_state_surfaces], device="cuda") with torch.inference_mode(): disabled = wrapper(**eval_inputs, use_cache=False).logits[:, -1].float() oracle = wrapper( **eval_inputs, p_store=eval_store, oracle_indices=oracle_indices, query_entity_surfaces=heldout_state_surfaces, gate_enabled=False, use_cache=False, ).logits[:, -1].float() without_gate = wrapper( **eval_inputs, p_store=eval_store, query_entity_surfaces=heldout_state_surfaces, gate_enabled=False, use_cache=False ).logits[:, -1].float() full = wrapper( **eval_inputs, p_store=eval_store, query_entity_surfaces=heldout_state_surfaces, collect_telemetry=True, use_cache=False ).logits[:, -1].float() full_gate = float(torch.stack([ values[:, -1].float().mean() for values in wrapper.gate_telemetry ]).mean()) def accuracy(logits): return float((logits[:, value_token_ids].argmax(-1) == expected_values).float().mean()) ablations = { "router_only": scaling["128"], "translator_only_oracle_routing": {"state_candidate_accuracy": accuracy(oracle)}, "router_plus_translator_without_gate": {"state_candidate_accuracy": accuracy(without_gate)}, "router_plus_translator_plus_gate": pre_preservation_ablation, "full_system_with_preservation": { "state_candidate_accuracy": accuracy(full), "full_token_accuracy": float((full.argmax(-1) == expected_tokens).float().mean()), "gate_activation": full_gate, }, } def single_condition(surface, value, *, label=None, metadata=CANONICAL, invalidate=False): store, slots = make_store( [(label or surface, 0, value)], slots=128, metadata=metadata ) if invalidate: store.invalidate(next(iter(slots.values()))) return store counter_prompt = state_inputs(["silver key"], HELDOUT_LEADS[1]) alice, bob = 0, 1 conditions = { "disabled": None, "p1_silver_alice": single_condition("silver key", alice), "p2_silver_bob": single_condition("silver key", bob), "p3_gold_alice": single_condition("silver key", alice, label="gold key"), "p4_silver_historical": single_condition("silver key", alice, metadata=HISTORICAL), "p4_silver_invalidated": single_condition("silver key", alice, invalidate=True), } counterfactual = {} with torch.inference_mode(): for label, store in conditions.items(): output = wrapper( **counter_prompt, p_store=store, query_entity_surfaces=["silver key"], collect_telemetry=True, use_cache=False ).logits[:, -1].float() probabilities = F.softmax(output, dim=-1) counterfactual[label] = { "alice_logit": float(output[0, value_token_ids[alice]]), "bob_logit": float(output[0, value_token_ids[bob]]), "alice_probability": float(probabilities[0, value_token_ids[alice]]), "bob_probability": float(probabilities[0, value_token_ids[bob]]), "generated": tokenizer.decode([int(output.argmax(-1))]), "gate": 0.0 if not wrapper.gate_telemetry else float(torch.stack([ values[:, -1].float().mean() for values in wrapper.gate_telemetry ]).mean()), } wrong_store = conditions["p3_gold_alice"] invalid_store = conditions["p4_silver_invalidated"] def greedy_continuations(inputs, store, steps=6): input_ids = inputs.input_ids.clone() attention_mask = inputs.attention_mask.clone() original_length = input_ids.shape[1] for _ in range(steps): output = wrapper( input_ids=input_ids, attention_mask=attention_mask, p_store=store, use_cache=False, ).logits[:, -1] next_token = output.argmax(-1, keepdim=True) input_ids = torch.cat((input_ids, next_token), dim=1) attention_mask = torch.cat(( attention_mask, torch.ones_like(next_token, dtype=attention_mask.dtype), ), dim=1) return [tokenizer.decode(row[original_length:]) for row in input_ids] with torch.inference_mode(): rp_conditions = {} for label, store in ( ("base", None), ("irrelevant", eval_store), ("wrong_entity", wrong_store), ("invalidated", invalid_store), ): output = wrapper( **rp_eval, labels=rp_eval.input_ids, p_store=store, use_cache=False ) kl = F.kl_div( F.log_softmax(frozen_rp_eval[:, -1].float(), dim=-1), F.softmax(output.logits[:, -1].float(), dim=-1), reduction="batchmean" ) rp_conditions[label] = { "loss": float(output.loss), "kl": float(kl), "samples": greedy_continuations(rp_eval, store), } invalid_difference = max( abs(counterfactual["p4_silver_invalidated"][key] - counterfactual["disabled"][key]) for key in ("alice_logit", "bob_logit") ) mutation_store, mutation_slots = make_store( [("silver key", 0, 0)], slots=128 ) mutation_slot = mutation_slots["silver key"] for mutation_index, value in enumerate((1, 2, 3, 4)): mutation_store.modify( mutation_slot, canonical_vector(0, 0, value), entity_id=0, relation_id=0, value_id=value, metadata_id=CANONICAL, source=SlotSource.CORRECTION if mutation_index == 3 else None, ) with torch.inference_mode(): mutation_logits = wrapper( **counter_prompt, p_store=mutation_store, query_entity_surfaces=["silver key"], use_cache=False, ).logits[:, -1].float() mutation_latest_correct = int( mutation_logits[:, value_token_ids].argmax(-1) ) == 4 mutation_store.invalidate(mutation_slot) with torch.inference_mode(): mutation_invalidated = wrapper( **counter_prompt, p_store=mutation_store, query_entity_surfaces=["silver key"], use_cache=False, ).logits[:, -1].float() mutation_disabled = wrapper(**counter_prompt, use_cache=False).logits[:, -1].float() mutation_invalidated_difference = float(( mutation_invalidated - mutation_disabled ).abs().max()) base_gradients = sum(parameter.grad is not None for parameter in base.parameters()) if package_path is not None: package.save(package_path) restored = SplitPTranslatePackage.load(package_path, device="cuda") restored.validate_compatibility( model_id=pythia_model_identifier(base), model_hidden_width=int(base.config.hidden_size), attachment_layers=layers, model_config_sha256=config_checksum(base.config), ) package_roundtrip = max( float((left - right).abs().max()) for left, right in zip(package.state_dict().values(), restored.state_dict().values()) ) del restored else: package_roundtrip = None if router_path is not None: router.save(router_path) restored_router = CanonicalPRouter.load(router_path, device="cuda") router_roundtrip = max( float((left - right).abs().max()) for left, right in zip(router.state_dict().values(), restored_router.state_dict().values()) ) del restored_router else: router_roundtrip = None result = { "attachment_layers": list(layers), "attachment_count": attachment_count, "query_projector": { "loss_first_last": [query_losses[0], query_losses[-1]], "byte_surface_anchor_approach": byte_surface_metrics, "hidden_to_byte_reconstruction_ablation": query_heldout_metrics, "frozen_lexical_anchor_approach": lexical_metrics, "heldout_names": len(heldout_surfaces), "training_names": len(train_surfaces), }, "router": { "loss_first_last": [router_losses[0], router_losses[-1]], "model_hidden_dimensions": 0, "acceptance_threshold": float(router.acceptance_threshold), "calibration_balanced_accuracy": calibration_balanced_accuracy, "hard_negative_metrics": router_hard_metrics, "scaling": scaling, }, "value_translator": { "loss_first_last": [value_losses[0], value_losses[-1]], "oracle_selected_metrics": value_metrics, }, "causal_training_loss_first_last": [causal_losses[0], causal_losses[-1]], "ablations": ablations, "counterfactual": counterfactual, "invalidated_logit_difference": invalid_difference, "mutation_chain": { "latest_state_accuracy": float(mutation_latest_correct), "invalidated_max_logit_difference": mutation_invalidated_difference, "source_tokens_in_recent_kv": 0, }, "natural_rp": { "conditions": rp_conditions, "base_loss": base_rp_loss, "relevant_state_generation_sample": counterfactual["p1_silver_alice"]["generated"], }, "base_parameters_with_grad": base_gradients, "source_tokens_in_recent_kv": 0, "extra_prompt_tokens": 0, "package_parameters": sum(p.numel() for p in package.parameters()), "router_parameters": sum(p.numel() for p in router.parameters()), "package_roundtrip_max_difference": package_roundtrip, "router_roundtrip_max_difference": router_roundtrip, "package_path": str(package_path) if package_path else None, "router_path": str(router_path) if router_path else None, } wrapper.close() del wrapper, base, package, router gc.collect() torch.cuda.empty_cache() return result