Repeated identities and a reconstruction objective can move adaptive cluster commitment toward the generating group count.
Repeated merchant identities each have a stable label drawn from five groups. The model predicts that label while also reconstructing masked identity representations. The experiment checks how many clusters become committed and how broadly they are used.
Seed 0 on gpu: 4 of 4 behavioral checks met. See the measurements below.
Insights
The right number of clusters does not mean the right identities were grouped together. Repeated identities provide consistent label evidence, and the Cluster reconstruction loss updates usage and commitment.
The recorded run ends near five groups. However, committed count is derived by rounding and clamping usage perplexity: these are coupled diagnostics, not independent confirmations of recovery. Incorrect groups can satisfy both gates.
Training and validation reuse observations, with no held-out skill or assignment-agreement requirement. Treat this as evidence about mechanism activation. Demonstrating useful clustering still requires independent predictions, partition recovery, and controls without genuine generating groups.
Setup
Code
"""P020: track adaptive clusters across five repeated-identity labels.Training and validation deliberately reuse observations. Count and usageperplexity diagnose the mechanism; they do not prove partition recovery orheld-out prediction quality."""from collections.abc import Iteratorfrom functools import partialimport lightning.pytorch as litimport torchfrom reporting import reportimport relflow as rffrom relflow.tensorfields.extensions.cluster import EmbedderPROOF_ID ="P020"
Examples
Each generating identity appears 20 times with a stable hidden label. The Cluster field is an input with a reconstructing mask; its displayed identity is not always visible during training.
One identity in the first group
merchant_id: c0-id3label: L0
Repeated observations give this identity consistent evidence for label L0.
A peer identity in the same group
merchant_id: c0-id9label: L0
The identifier differs, but the behavior matches. These two identities belong together in the generator’s partition.
A different group
merchant_id: c4-id8label: L4
This identity belongs to a different generating group. The five groups have ten identities each, for 1,000 total observations. Their label relationship is ground truth; the present proof checks cluster count and usage, not whether these particular identities received the correct learned assignments.
Synthetic data and controls
Code
def records(seed: int) -> Iterator[dict]:"""Repeat each of 50 identities twenty times with one stable regime label.""" rows = [ {"merchant_id": f"c{cluster}-id{identity}", "label": f"L{cluster}"}for cluster inrange(5)for identity inrange(10)for _ inrange(20) ] order = torch.randperm(len(rows), generator=torch.Generator().manual_seed(seed)).tolist()for index in order:yield rows[index]class Trajectory(lit.Callback):"""Inspect Cluster internals; these diagnostics do not establish partition accuracy."""def__init__(self, address: rf.Address) ->None:self.address = addressself.rows: list[dict] = []def on_train_epoch_end(self, trainer: lit.Trainer, pl_module: lit.LightningModule) ->None: embedder = pl_module.nodes[self.address].embedderifnotisinstance(embedder, Embedder):raiseTypeError(f"{self.address} requires a Cluster embedder, got {type(embedder).__name__}") usage = embedder.usage_ema.detach() probabilities = usage / usage.sum().clamp_min(1e-12) bounded = probabilities.clamp_min(1e-12) entropy =-(bounded * bounded.log()).sum()self.rows.append( {"epoch": trainer.current_epoch,"n_committed": int(embedder.committed.sum().item()),"perplexity": float(torch.exp(entropy).item()),"adherence": float(embedder.adherence_ema.item()), } )
Model tree
Figure 1: Merchant ID uses a 50% training mask with reconstruction enabled. Its label is always hidden from model inputs.
How it works
The merchant field uses rf.Cluster(mask=rf.Mask(rate=0.5, reconstruct=True), ...). Its reconstruction loss updates adaptive usage and commitment state. Repetition lets evidence accumulate for an identity. label=rf.Category(mask=True, ...) supplies the supervised task without exposing its answer as an input.
Assignments belong to stable identities. Row-varying sibling context does not directly condition the Cluster reconstruction query. The plain-input control shows what happens when the Cluster reconstruction objective is absent.
The model trains for 30 deterministic epochs. A callback inspects internal Cluster state at each epoch; the gates examine its final five entries.
Training and evaluation
Code
def run(seed: int, steps: int|None, accelerator: str) ->tuple[dict, dict]: lit.seed_everything(seed, workers=True) model = rf.Model( name="event", d_model=32, n_layers=1, n_heads=4, batch_size=64, merchant_id=rf.Cluster(capacity=64, n_clusters=(3, 15), mask=rf.Mask(rate=0.5, reconstruct=True)), label=rf.Category(mask=True, size=5, p_unavailable=0.0), ) model.optimizer =lambda module: torch.optim.AdamW(module.parameters(), lr=3e-3) source = partial(records, seed=seed) data = rf.SyntheticDataModule(model=model, train=source, validate=source, seed=seed) trajectory = Trajectory(rf.Address("event", "merchant_id")) trainer = lit.Trainer( accelerator=accelerator, max_epochs=30, max_steps=steps if steps isnotNoneelse-1, callbacks=[trajectory], logger=False, enable_progress_bar=False, enable_model_summary=False, enable_checkpointing=False, deterministic=True, ) trainer.fit(model=model, datamodule=data) tail = trajectory.rows[-5:] committed = [row["n_committed"] for row in tail] perplexity = [row["perplexity"] for row in tail]return {"trajectory": trajectory.rows,"final_committed": committed,"final_perplexity": perplexity, }, {"Final committed counts remain between 4 and 7": all(4<= value <=7for value in committed),"Final perplexity remains within 1.5 of five": all(abs(value -5) <=1.5for value in perplexity),"Terminal commitment is above the lower bound": committed[-1] !=3,"Terminal commitment is below the upper bound": committed[-1] !=15, }
Evidence
Latest full run
Seed 0, gpu, recorded 2026-09-15T02:24:00.576894+00:00. Outcome: met.
Use independent observations for each split, add held-out downstream skill against a marginal baseline, and require adjusted Rand index (ARI) ≥ 0.80 for partition recovery. Add unique-identity and no-regime controls. Replace internal-state inspection with a public diagnostic when available.
The family requires three passing core seeds and at least ten calibration seeds before its terminal-window thresholds can be promoted.
Reproduce
Run by stable ID from the repository root:
uv run python proofs/run.py P020
Or run the self-contained script directly:
PYTHONPATH=proofs uv run python proofs/cluster/reconstructing_category_labels.py
Add --accelerator gpu for CUDA or --seed 42 for another seeded experiment. --steps 2 checks execution with a short training budget; it is recorded as a smoke run.