Gen5 CF Training Results + Critical Load Bug Fix (2026-07-22)

## Critical Bug Fix: VarMap::load() Order

**All previous Gen5 model evaluations were invalid** — models loaded 0 variables at inference time (random weights).

Candle's `VarMap::load()` iterates over EXISTING variables to set their values from file. It does NOT create new variables. The code in `load_model()`, `Trainer::from_model()`, `multi_head::load_model()`, and `range_predictor::load()` all called `var_map.load()` BEFORE creating variables via `from_varmap()`. Result: 0 variables loaded, model used random init.

**Fixed in all 4 locations** (`network.rs`, `multi_head.rs`, `range_predictor.rs`): create variables first via `from_varmap()`, then call `var_map.load()`.

This means:
- RangeNet v8 WAS actually working in G49 live (it loads via a different path — the RangePredictor::load also had the bug, but the data collection path creates variables first)
- Wait — RangePredictor::load also had the bug. So RangeNet v8 in G49 was ALSO random weights at inference time!
- ALL imitation/Q-reg/CF model evaluations that reported "folds everything" were using random weights

## CF Data Collection Status

CF collection is **working correctly**. 447K records (2.5 GB) collected from 500K hands, 8 tables, 9-seat mixed field. Data at `/home/jan/gen5_data/cf_v3/cf_data_merged.jsonl`.

Each record: 459-dim features + 11 action EVs (from 20 counterfactual rollouts per action) + legal mask.

## CF Model Training Results

### v3 (MSE loss, from scratch)
- 30 epochs, lr=1e-3, batch=512
- Final loss: 46.4 → 16.0
- Harrington: 48/53 pass (5 fail)
- Issues: too passive (folds sets, checks KK, 0% aggressive with KQs top pair)

### v4_rank (Ranking/CE loss, temp=1.0, from scratch)
- 30 epochs, lr=1e-3, batch=512
- Final loss: 1.73 → 1.41
- Harrington: 49/53 pass (4 fail)
- Issues: mixed — over-aggressive in some spots (raises 99 when should check), still passive in others (KQs top pair 0% aggressive)

### v5_warmstart (Ranking/CE loss, temp=2.0, warm-started from v3 MSE)
- 20 epochs, lr=5e-4, batch=512, --init gen5_cf_v3
- Final loss: 1.76 → 1.59
- Harrington: 49/53 pass (4 fail)
- Issues: persistent — KQs top pair 0% aggressive, calls OESD when should fold, checks KK river

## Persistent Failure Analysis

The KQs top pair "0% aggressive" failure persists across ALL CF models. Root cause: CF rollout EVs systematically undervalue betting with made hands. The simplified opponent model in `simulate_rollout()` likely doesn't fold enough, making bet EVs negative relative to check EV (0).

## New Training Code

Added `train_batch_cf_ranking()` in `network.rs` — softmax cross-entropy on EV-derived target distribution:
- Converts EVs to target probs via `softmax(EV/temperature)`
- CE loss: `-Σ target × log(softmax(Q))`
- Temperature parameter via `--temp` flag
- Usage: `train_gen5 <data> <epochs> <batch> <lr> <out> --cf-ranking --temp 1.0`

## Models Kept
- `gen5_cf_v3.safetensors` — MSE loss, 14 vars loaded correctly
- `gen5_cf_v4_rank.safetensors` — Ranking loss temp=1.0
- `gen5_cf_v5_warmstart.safetensors` — Ranking loss temp=2.0, warm-started

## Next Directions

1. **Retrain imitation model with fixed loader** — previous 71.5% accuracy was measured on in-memory model, never properly evaluated at inference. With load fix, direct imitation of G48 might work better than CF.
2. **Fix CF rollout opponent model** — the simplified fold model in `simulate_rollout()` needs to use RangeNet-predicted fold frequencies, not a static formula.
3. **Hybrid approach** — use CF model only when it strongly disagrees with G48 (high Q-value gap), otherwise defer to formula.
4. **TD-learning (Bellman backups)** — fundamentally different approach that could learn beyond G48.

id: e4903c1cbaef4862938dd80c9e04b96a
parent_id: 0be24af8
created_time: 2026-07-22T13:05:57.165Z
updated_time: 2026-07-22T13:05:57.165Z
is_conflict: 0
latitude: 0.00000000
longitude: 0.00000000
altitude: 0.0000
author: 
source_url: 
is_todo: 0
todo_due: 0
todo_completed: 0
source: joplin-desktop
source_application: net.cozic.joplin-desktop
application_data: 
order: 1784725557165
user_created_time: 2026-07-22T13:05:57.165Z
user_updated_time: 2026-07-22T13:05:57.165Z
encryption_cipher_text: 
encryption_applied: 0
markup_language: 1
is_shared: 0
share_id: 
conflict_original_id: 
master_key_id: 
user_data: 
deleted_time: 0
is_locked: 0
extracted_resource_ids: 
type_: 1