Skip to content

Repository files navigation

NAICS Hyperbolic Embedding System

PyPI Version GitHub Release PyPI Downloads License Documentation Tests Coverage Issues Last Commit Contributors Repo size Top language

The project serves three artifacts over the 2,125 NAICS 2022 codes, each judged only on evidence for its own use (user adjudication Q3, specs/naics-representation-split.md): the hierarchy itself, text→code retrieval, and low-dimensional economic coordinates for downstream models. The trained text model places NAICS codes and activity queries in one space. One LoRA-adapted transformer reads marked fields; masked fusion and one linear projection produce live direction and radius. Text training optimizes query decoding, code geometry and radius jointly. Optional HGCN refinement then uses the explicit parent–child graph.

Architecture

  1. Shared text encoding: the same backbone reads title, description, examples, exclusions and queries. Absent code fields never enter the backbone.
  2. Fusion and projection: masked mean by default, attention or MoE as options, then one Linear(384, d), where d is 8, 16 or 32 (default 16).
  3. Text objective: task cross-entropy, code-to-code soft-target cross-entropy and radial error, with an auxiliary load-balancing term only under MoE.
  4. HGCN refinement: the separate graph curriculum and triplet objective refine the exported code geometry. Adoption is decided on the three evaluation panels.
Marked fields/queries -> shared LoRA backbone -> masked fusion -> Linear(384, d)
    -> live radius and direction -> task + code-to-code + radial terms
    -> earliest best outcome-MRR checkpoint -> tangent table -> optional HGCN
    -> outcome, regressor-seen and regressor-heldout decision

Live Radius and the Objective

For projection v with norm a and direction u, the default parameter-free head computes r = R * tanh(a / R) with R = model.radius_bound (default 8), then maps r u to the unit-curvature Lorentz hyperboloid. Zero v maps to the origin. Text curvature is fixed at 1, with no curvature setting. Training distances use the stable polar form in float32; panel reads reconstruct Lorentz points and compute distances on the CPU in float64. model.geometry also offers Euclidean and spherical heads, which share the encoder and the task and code-to-code terms but have no radial term (geometry arms).

task_loss decodes each training query to its named code targets. Its candidates are every code at the query's level plus every explicit referring code. code_code_loss matches a softmax of negative taxonomy distance over all codes except the anchor and its unary partner. radial_loss softly targets radial_step * (level - 1) while keeping gradients through each radius. Both code-code and radial weights default to 1. Task and code-code logit scales are learned independently, start at 1 and are clamped to [0.01, 100] without weight decay.

There is no text DCL loss, negative miner, false-negative clustering or phase curriculum. The reference uses two streams: every code anchor and every eligible query once per epoch. With 11,039 queries and 128 queries per step, the reference epoch has 87 steps. A detached code cache is refreshed at fit start and epoch end; each step replaces its anchor rows with live embeddings. The training-pairs bundle member stays validated but is unread by text training.

Monitor and Artifacts

After each cache refresh, the outcome validation panel's float64 MRR becomes val/outcome_mrr. It selects the earliest best epoch and controls plateau scheduling and early stopping. The model writes monitor_reads.jsonl and epoch_summary.jsonl beside the checkpoints. The summary contains MRR, three term losses, total loss, both scales and per-level radius mean/SD.

The selected checkpoint is epoch=NNN.ckpt; last.ckpt holds the latest training state. Checkpoints identify objective req11-v1, bundle, encoder, preprocessing, seed and 21 run settings. Old objectives are refused before model loading; there is no weights-only migration. See the training guide for the exact contracts and resume rules.

Quick Start

git clone https://github.com/lowmason/naics-embedder.git
cd naics-embedder
uv sync
uv run naics-embedder data all
uv run naics-embedder train --config conf/config.yaml

data all prints the immutable manifest path. Put it in the gitignored conf/local.yaml (conf/local.example.yaml shows the form), which names this machine's two manifests and nothing else; commands read it after conf/config.yaml and before key=value overrides. The mandatory gate validates the bundle before model or data-loader construction. --skip-validation only skips advisory checks. Retired data relations, data distances and data triplets commands build nothing and exit 1.

CUDA uses bf16-mixed for the backbone; fusion, projection, geometry and losses remain float32. CPU and MPS use 32-true. The text Trainer uses one device.

uv run naics-embedder train --ckpt-path last
uv run naics-embedder tools visualize   --summary checkpoints/reference/epoch_summary.jsonl

Resume only last, with the same experiment directory, bundle, encoder, preprocessing, seed and settings. A supplementary check compares saved constructor hyperparameters with the current configuration: LoRA rank, alpha and dropout, plus expert count, top-k, hidden dimension and load-balancing coefficient when MoE fusion is active. Missing required values are refused. The arm identity retains its 21 run_settings keys. An early-stopped run exits 1 with early stopping ended the run at epoch k; a spent epoch budget trains no further epochs. Changing the budget or other settings requires a fresh run directory. The code cache is rebuilt, and both JSONL files continue from the restored epoch.

Export and Radius Verification

Export the earliest highest-MRR checkpoint identified by the monitor. This example uses epoch 1:

uv run naics-embedder tools export-table --checkpoint checkpoints/reference/epoch=001.ckpt   --output data/reference/table.parquet
uv run naics-embedder tools radius-report --checkpoint checkpoints/reference/epoch=001.ckpt   --table data/reference/table.parquet --output data/reference/radius_report.json

The table has code, index, level, and the arm's coordinates e0 through e{d-1} (bounded tangents in the hyperbolic arm) in codebook order. Provenance binds it to the checkpoint and preprocessing identities. The radius report checks live gradients, per-level spread, sector radii, manifold validity, distance precision and nonzero gradients for the three terms and both scales. A failed criterion writes the report and exits 1; the report does not read an evaluation panel.

Three-Panel Campaign

Train ten seeds with the same reference settings, then run tools sweep over their complete run directories. It checks every seed before its first export or decision read. Each seed contributes outcome validation and the regressor panel's seen and held-out regimes at level 6; the arm record carries the monitor reads that selected its checkpoint.

Fix reference margins with tools margins --multiple 3 before candidate monitor or decision reads. tools decide applies Req 5's paired resampling, non-inferiority, superiority and tie order. The panel test splits stay sealed. See the reference campaign for complete commands.

The economic artifact is decided on its own panels, growth_seen and growth_heldout, against the reference covariates+ancestors (Req 24). tools growth-margins fixes each panel's δ from a read that scores no candidate, before any candidate is read. tools decide then reads 97.5 % superiority over the two panels, and only a candidate adopted over the reference is eligible. See tools growth-margins.

Graph Refinement and Structural Diagnostics

HGCN retains its four-phase graph curriculum, triplet objective and curvature utilities. Set its bundle manifest as graph.supervision_manifest_path in conf/local.yaml, then run:

uv run python -m naics_embedder.graph_model.hgcn

See HGCN training for input artifacts and graph configuration. HGCN structural statistics remain descriptive. tools diagnostics reports Req 6's sector separation, within-sector rank correlation, ancestor MAP, LCA-graded NDCG, distance/D* Pearson correlation and parent retrieval without unary pairs. They neither select the text checkpoint nor replace a three-panel decision.

structural-spearman-v1 validates symmetric distance matrices, averages mirrored values in CPU float64 and uses strict upper-triangle pairs with average ranks for exact ties. Undefined results have an explicit status and JSON null. Historical unversioned Spearman fields are legacy-ordinal-rank-v0 and are not directly comparable. See the metric contract.

Development

The project pins Python 3.12 for its locked environment. Tests use fixture bundles and tiny models; they do not perform the real training or selection campaign.

uv run pytest -n auto -q
uv run ruff check src/ tests/
./scripts/format_code.sh --check --all
uv run mkdocs build --strict

The suite collects 3,342 tests in 105 unit files and two integration files. Actual skip counts depend on local data and hardware capabilities, including MPS. Coverage is measured separately, not inferred from collection counts. See tests/README.md for test contracts and CLAUDE.md for project conventions.

Releases

Packages

Contributors

Languages