Applying the Word2Vec → BERT leap to basketball: learning contextual NBA player embeddings — where a player's representation depends on lineup context — from a self-attention transformer trained on ~7.2M possession-level outcomes across 30 seasons (1996-97 → 2025-26), warm-started from anonymized LLM-generated scouting reports.
Reviewing the project? Start with notebooks/model_report_v11.ipynb — a
plain-language report on the current model: what it learned, how it was
tuned, how well it measures, and whether its player lists pass a basketball
smell test. (Executed copies aren't checked in; an HTML render accompanies
this repo when it's handed off, or run the notebook to regenerate it.)
Prior work like NBA2Vec treats players as static vectors (mean-pooled, context-free). But basketball is fundamentally contextual — a player's impact depends on who else is on the court. Unicorn models player-player interactions through self-attention over 10-player lineups (offense slots 0-4, defense 5-9), producing representations that capture how a player operates in a specific lineup and game state.
- Composed embeddings:
base_player + delta_season— a per-player archetype vector (2,862 players) plus a low-rank per-season delta (14,581 player-seasons, 64-dim bottleneck) - Transformer encoder: 8 layers, 8 heads, d_model=384, over 10 player tokens with side embeddings; mean pooling split by offense/defense
- Joint objectives: masked-player identity (contrastive + tied auxiliary classification) + 5-class distributional possession outcome (Bayesian-smoothed lineup targets) + a possession-points head
- New in v11: two players hidden per training play instead of one, and a reserved 96-of-384 slice of each embedding dedicated to identity at reduced gradient strength — player recognition improves sharply at almost no cost to lineup ranking
- LLM-seeded initialization: anonymized play-style descriptions embedded as the base-vector warm start (leakage-controlled: evaluated models only see knowledge available at their training cutoff)
- One recipe, three data cutoffs: every candidate trains at a pre-season cutoff, a mid-season cutoff, and a full-data cutoff with 14% of five-man units withheld — matching the three ways it would actually be deployed
Honest scoreboard, kept in docs/EXPERIMENTS.md (curated findings record) and
graded by pre-registered criteria (docs/TRAINING_SPEC_V11.md). The current
model picks game winners at 63.9% from the ten starters alone (guessing the home
team: 54.7%), agrees with defensive impact statistics at +0.38 where earlier
generations were near zero, and is the first whose held-out lineup rankings
are separated above a team-identity-only baseline — it knows more than
which jersey is which. On the headline task, ranking 1,758 five-man
combinations withheld from training, it ties the previous design (rank
agreement 0.287 vs 0.296 — not a distinguishable difference); the redesign
was kept for its recognition, defense, and game-prediction gains. Known
weakness, and the next target: the learned identity readout does not yet
transfer to a season the model never trained on. The 2026-27 season-preview
notebook (lineup fit for the offseason's moves, including dropping LeBron's
2019-20 assist-title season into the 2026-27 Sixers) is in progress.
train_transformer.py+nba_dataset_v10.py— model and data pipelinescripts/ingest/— raw NBA Stats → certified possessions (data_v10/)scripts/eval_v10/— evaluation suite with model-free baselines and testsscripts/v11/— the three-cutoff training diets and the exam harnessnotebooks/model_report_v11.ipynb— the readable model report (start here)notebooks/season_preview_2026_27.ipynb— the 2026-27 preview (in progress)notebooks/master_eval_v10.ipynb— dense multi-run audit notebook (internal)runs/— all evaluation artifacts, gitignored and regenerabledocs/— living specs and the curated findings record
See CLAUDE.md for run commands and repo conventions.