Downloads · 30 days
0
rfi-irfos/dingir-ternary-gnn-poc
dingir-ternary-gnn-poc is a machine learning model from rfi-irfos. Use it for the machine learning task on the model card, and read the license before you ship it in a product. The card lists the license as cc-by-4.0.
This is a research prototype checkpoint, not a production model. It demonstrates that weight-only ternary quantization ({-1, 0, +1} via absmean+STE, BitNet-b1.58-style) can be applied to most of a real, production gra…
Downloads · 30 days
0
Access
Public
Updated Oct 13, 2026
Repo size
19.7 MB
Likes
0
Public
Click a slice to open those files.
.pt19.7 MB · 100%
From the Hugging Face model README
This is a research prototype checkpoint, not a production model. It demonstrates that weight-only ternary quantization ({-1, 0, +1} via absmean+STE, BitNet-b1.58-style) can be applied to most of a real, production graph neural network's parameter mass with limited measured quality loss on link-existence prediction — it is not a speed optimization, not a full ternary architecture, and not the model actually running in production.
DINGIR is a whitebox, explainable world-model and reasoning layer built
by RFI-IRFOS. KindomGNN is its
production graph neural network: a 2-layer, attention-weighted,
residual GCN over DINGIR's live entity graph (countries, sanctioned
entities, disasters, companies, geopolitical events, ~40 node types),
with a DistMult relation-scoring head on top for typed link prediction.
A real, freshly trained (2026-08-30) checkpoint of KindomGNN with
three specific submodules ternarized:
embed — the node embedding table, nn.Embedding(50729, 32),
1,623,328 of this model's 1,641,632 total parameters (98.9%).lin1 — nn.Linear(94, 64), the feature-fusion layer.lin2 — nn.Linear(64, 64), the second GCN layer.Together, the .weight tensors of these three modules cover 99.5% of
total parameter mass (1,633,568 / 1,641,632). Biases on lin1/lin2
(128 values total) and every other submodule — the GAT-style attention
parameters (att_src, att_dst), the relation embedding
(rel_embed), and the softplus relation gate (rel_gate) — remain
ordinary float32. This selection ("Arm D") and its exclusions are not
arbitrary: they reproduce the headline arm of a real, prior 18-run
ternary-quantization sweep over this same architecture (intelligence/ gnn_weight_ternary_experiment.py, 2026-08-29, documented in
intelligence/MEASUREMENTS.md), which found rel_embed/rel_gate
measurably hurt DistMult relation-ranking quality when also ternarized
(mean relation MRR: arm D alone 0.5863, +rel_embed 0.5664, +rel_gate
0.5473).
Quantization mechanism (intelligence/ternary_quant.py, reused
unmodified): per-tensor absmean scale gamma = mean(|w|), threshold
tau * gamma (tau = 0.05 here), weights below threshold round to 0,
the rest round to sign(w) * gamma. Training uses a straight-through
estimator — the forward pass sees the ternarized value, gradients flow
to the underlying float32 parameter unchanged. The stored .pt file
contains the trained float32 parameters, not a packed 2-bit encoding
— ternarization is a forward-pass-time operation, reproduced from the
stored floats via the same tau, not a separate saved format. This is
why the checkpoint is ~6.5MB rather than the ~1.6MB a true packed
2-bit/int8 export would be (see "No fast inference kernel" below for
why that export wasn't worth building for this release).
earlier run)
Trained via ReasoningLayer.build() → arm-D module swap →
train_link_prediction() (both unmodified), on Modal (16GiB/4CPU), 3
seeds, against DINGIR's real, current production graph — 50,729
nodes, 482,850 edges (214,162 real trainable edges after excluding
268,688 tautological EXPOSES edges). Held-out hash-split test set;
message passing restricted to train edges only (topology holdout).
| Seed | test_auc | relation_mrr | best_epoch | included checkpoint |
|---|---|---|---|---|
| 42 | 0.6461 | 0.5618 | 60 | yes (best test_auc) |
| 43 | 0.6330 | 0.5910 | 100 | no |
| 44 | 0.6439 | 0.5420 | 50 | no |
| mean | 0.6410 | 0.5649 | — | — |
All three seeds' real numbers are reported above, not just the winner. Seed 42 (highest test_auc) is the checkpoint distributed with this card; seeds 43/44 were also trained and exported (see "Files" below) but not selected.
DINGIR's real, current production checkpoint (reasoning_layer_gnn.pt,
frozen float32, trained 2026-08-28): test_auc=0.7598,
relation_mrr=0.8706. This fresh ternary run scores meaningfully lower
on both metrics against that number — but that comparison is not
apples-to-apples: the production checkpoint's graph predates a real
+25.6% edge-count jump from SEC EDGAR corporate-fundamentals ingestion
and the subsequent maritime-AIS ingestion, both landed after that
checkpoint was trained. The original (non-ternary) sweep that produced
arm D already documented this exact same gap for its own control arm
(fresh same-graph AUC 0.6429 vs the historical 0.7598) and attributed it
to graph growth/harness differences, not to ternarization. This
checkpoint's gap is consistent with that same, already-documented
effect — not re-derived independently here, and not claimed as new
evidence either way.
| test_auc (mean) | relation_mrr (mean) | trainable edges | nodes | |
|---|---|---|---|---|
| Original sweep, arm D, seeds 42/43/44 | 0.6469 | 0.5863 | 113,737 | 50,861 |
| This fresh run, seeds 42/43/44 | 0.6410 | 0.5649 | 214,162 | 50,729 |
| Δ | -0.0059 | -0.0214 | +100,425 | -132 |
test_auc held essentially flat (within normal seed-to-seed noise);
relation_mrr shows a modest real decline. Two things are named here
honestly rather than smoothed over: (1) the graph grew substantially in
trainable-edge count between the two runs (SEC EDGAR + maritime AIS),
consistent with the companion dataset card's own account of that
growth, yet node count is slightly lower (50,729 vs 50,861) — an open
observation, not independently explained here (possible entity
deduplication/merge changes between the two dates; not investigated
further for this release). (2) No same-graph, same-day non-ternary
control (A_control) was re-run alongside this fresh export — the
comparison above is against a different day's control, the same
honestly-flagged caveat the original sweep's own methodology note
already applied to its own historical-baseline comparison.
KindomGNN's own
neighbor-aggregation step (_propagate()) stays float32 throughout.
Ternarizing that step was a separate, harder investigation ("Stage
2") in the same research session, and — under the real, full 3-loss
training objective this checkpoint also uses — both tested
aggregation-ternarization candidates produced a real, substantial
relation_mrr degradation (~29–40% relative drop vs. control) and a
collapse to near-random AUC (~0.51–0.52) specifically at the graph's
highest-degree hub bucket. That is a real, documented negative
result, not included here, and this checkpoint's comparatively mild
weight-only cost should not be read as evidence it would extend to
aggregation.intelligence/ternary_i8_benchmark.py) a real int8
export path for a ternarized linear layer at DINGIR's actual
production matrix shape (96×64, batch=512): a genuine int8×int8 GEMM
(torch._int_mm) measured ~22x SLOWER than plain float32
nn.Linear on CPU (1,643.1 µs vs 75.6 µs median forward time) — the
opposite of the hoped-for speedup, because PyTorch's generic CPU int8
GEMM does not amortize its own overhead at this GNN's small matrix
sizes (unlike a hand-tuned AVX2 kernel at LLM scale, where a sibling
project in the same codebase measures a real 2–4x win). A plain
float32-forward-pass-compatible int8 storage export does deliver a
real, verified 4.0x memory reduction on weight bytes (1 byte vs 4
bytes per value) with zero additional accuracy cost, but is itself
~21% slower than baseline float32 due to upcast overhead.
Follow-up sweeps of batching and a PyTorch sparse-CSR
"@sparseskip-analogue" (2026-08-30) both made things worse, not
better, at DINGIR's real observed 4.5% weight sparsity. Conclusion,
stated plainly: this checkpoint is evidence that ternary weight
quantization is possible with limited quality loss — it is not a
deployment-ready speedup, and nothing in this release claims
otherwise.reasoning_layer_gnn.pt
is untouched by this work — a completely separate build/train/save
path was used throughout, and this checkpoint has no path back into
production.This is not loadable via ReasoningLayer.load() — it needs the arm-D
module swap applied first, and it needs your own copy of the exact
graph state it was trained against (the embed table is indexed to a
specific node ordering; it is not portable to a different DINGIR graph
snapshot).
from intelligence.graph.evidence_graph import EvidenceGraph
from intelligence.graph.world_merge import merge_world_entities
from intelligence.gnn_weight_ternary_experiment import ARMS, _apply_arm
from intelligence.reasoning_layer import ReasoningLayer
import torch
g = EvidenceGraph().load_all()
merge_world_entities(g)
rl = ReasoningLayer.build(g, seed=42)
_apply_arm(rl, ARMS["D_embed_lin"], tau=0.05) # swaps embed/lin1/lin2
# to TernaryEmbedding/
# TernaryLinear in place
blob = torch.load("ternary_arm_d_seed42.pt", weights_only=False)
rl.model.load_state_dict(blob["model_state"])
rl.model.eval()
blob also carries metrics (this run's own loss/val history and
final test numbers), graph_stats, tau, seed, and
ternarized_modules — a self-contained record of what produced it, so
a consumer does not have to trust this card's prose alone.
ternary_arm_d_seed42.pt (6,574,028 bytes) — the checkpoint this
card describes, seed 42 (best test_auc of the 3 seeds trained).Companion dataset, same project: DINGIR Causal Chain Register (proof-of-concept snapshot) — a whitebox, evidence-graded causal-chain register built on the same underlying DINGIR system. That card's own account of the live entity graph ("a separate, much larger live entity graph ... has since grown further with the SEC fundamentals and maritime AIS ingestion") is the same graph growth this card's own before/after comparison table above is measuring against.
Trained via scripts/modal_ternary_arm_d_export.py in the RFI-IRFOS
kindom repository (not itself published in this release), which
reuses — unmodified — this project's own gnn_weight_ternary_ experiment.py::ARMS/_apply_arm() and
reasoning_layer.py::ReasoningLayer.build()/train_link_prediction().
Full raw per-seed results, including loss curves: datasets/ ternary_arm_d_export.json in that repository.
A research paper examining selective, submodule-level ternary weight quantization in heterogeneous GNN architectures — using this checkpoint and its underlying ablation sweep as the primary evidence base — is in preparation. The metrics on this card reflect the DINGIR graph snapshot as of the training date stated above; the underlying production graph has continued to grow since then, so treat node/edge counts here as a point-in-time snapshot, not current state.
CC BY 4.0, same footing as the companion dataset card. The checkpoint weights are derived entirely from RFI-IRFOS's own DINGIR entity graph (a public-source aggregation — see the companion dataset card's own licence section for the underlying data sources); no personal, client, or confidential data of any kind.