minhleduc commited on
Commit
f9e4c79
·
verified ·
1 Parent(s): 16a3555

Mirror laya-typed-decisions-ce-1024 (CE-only, 1024/256) + model card

Browse files
Files changed (7) hide show
  1. README.md +183 -0
  2. config.json +78 -0
  3. model.safetensors +3 -0
  4. model_config.json +18 -0
  5. temperatures.json +24 -0
  6. test_eval.json +99 -0
  7. train_log.json +70 -0
README.md ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ base_model: convaiinnovations/laya
4
+ library_name: pytorch
5
+ pipeline_tag: text-classification
6
+ tags:
7
+ - calibration
8
+ - decision-making
9
+ - typed-decisions
10
+ - non-autoregressive
11
+ - modernbert
12
+ - proper-scoring-rules
13
+ datasets:
14
+ - LocalLLaMA/typed-decisions
15
+ language:
16
+ - en
17
+ metrics:
18
+ - accuracy
19
+ - brier_score
20
+ - nll
21
+ model-index:
22
+ - name: laya-typed-decisions-ce-1024
23
+ results:
24
+ - task:
25
+ type: text-classification
26
+ name: Typed decisions
27
+ dataset:
28
+ type: LocalLLaMA/typed-decisions
29
+ name: LocalLLaMA/typed-decisions
30
+ split: test
31
+ metrics:
32
+ - type: accuracy
33
+ value: 0.7885
34
+ name: Accuracy
35
+ - type: brier_score
36
+ value: 0.0495
37
+ name: Brier (vs soft targets)
38
+ - type: nll
39
+ value: 0.8581
40
+ name: NLL (vs soft targets)
41
+ ---
42
+
43
+ # laya-typed-decisions-ce-1024
44
+
45
+ A ModernBERT-large decision model fine-tuned on `LocalLLaMA/typed-decisions` with **plain cross-entropy** against the teacher's soft targets, at the documented 1024-token context / 256-token option budget.
46
+
47
+ It is the best-performing checkpoint from the reproduction study *Dissecting RLCD*, where I took apart the training method behind TypeSafe's Jev and its open reproduction, Laya. The short version of that study: Laya's RL term is a noise-smoothed cross-entropy gradient, and on this benchmark plain CE matches or beats it on every proper score.
48
+
49
+ **Test-set results (2,000 decisions, 400 cases):**
50
+
51
+ | Metric | Value |
52
+ |---|---|
53
+ | Accuracy (vs hard label) | **0.7885** |
54
+ | Brier (vs soft targets) | **0.0495** |
55
+ | NLL (vs soft targets) | **0.8581** |
56
+ | Soft accuracy | 0.5236 |
57
+ | Mean confidence | 0.6444 |
58
+ | Mean target max | 0.6589 |
59
+ | Score MAE (ordinal questions) | 0.2115 |
60
+ | Fitted temperature (choice / score / noul) | 1.116 / 1.070 / 1.120 |
61
+
62
+ For reference, the `laya-typed-decisions` checkpoint reports 0.766 accuracy and 0.062 Brier; TypeSafe's published Jev 1.13.0 figure is 0.727.
63
+
64
+ ## Model description
65
+
66
+ A bidirectional encoder plus a small transformer head that reads one logit per masked option marker:
67
+
68
+ ```
69
+ [CLS] <type> question: <instr> [SEP] [MASK] opt0 [MASK] opt1 ... [SEP] <state> [SEP]
70
+ |
71
+ ModernBERT-large encoder (bidirectional)
72
+ |
73
+ h += type_emb(qtype)
74
+ |
75
+ 2 x TransformerEncoderLayer (pre-norm)
76
+ |
77
+ gather h at [MASK] positions -> scorer MLP -> 1 logit/option
78
+ ```
79
+
80
+ One input row per typed question. Question types are `choice` (pick one of K named options), `score` (ordinal), and `noul` (binary yes/no). Option count is per-row, not fixed.
81
+
82
+ - Encoder: `answerdotai/ModernBERT-large` (395M)
83
+ - Head: 2 pre-norm transformer layers, dropout 0.1
84
+ - Scorer: LayerNorm, Linear, GELU, Linear(->1)
85
+ - Total: ~421M parameters
86
+ - Sequence budget: 1024 tokens total, 256 for the question + option block
87
+
88
+ The output is a probability distribution over the row's options. For the `score` type, the expected level is `sum i * p_i`.
89
+
90
+ ## Intended use
91
+
92
+ Structured, closed-set probabilistic decisions over short English text: routing, triage, classification with calibrated confidence, and ordinal rating tasks where you control the option set.
93
+
94
+ **Out of scope:** open-ended generation (this model does not generate text), option sets larger than ~255, languages other than English (the base is English; a multilingual Laya variant exists), and any use where the option wording and the state distribution differ sharply from the training workflows.
95
+
96
+ ## How to use
97
+
98
+ This is a custom architecture, not a `transformers` `AutoModel`. Load it with the code from the reproduction repo:
99
+
100
+ ```bash
101
+ git clone https://github.com/LakoreAI/rlcd-reverse-engineering
102
+ cd rlcd-reverse-engineering && uv sync
103
+ ```
104
+
105
+ ```python
106
+ from pathlib import Path
107
+ import torch
108
+ from huggingface_hub import snapshot_download
109
+
110
+ import sys
111
+ sys.path.insert(0, "rlcd-reverse-engineering") # or pip install -e it
112
+
113
+ from src.pipelines.infer import load_model, infer
114
+
115
+ d = snapshot_download("minhleduc/laya-typed-decisions-ce-1024")
116
+ model, cfg, tokenizer = load_model(Path(d) / "model.safetensors", torch.device("cuda"))
117
+
118
+ result = infer(
119
+ Path(d) / "model.safetensors",
120
+ state='{"task": "triage", "ticket": "customer cannot log in after password reset"}',
121
+ question='{"type": "choice", "instructions": "Which queue should this go to?",'
122
+ ' "criteria": {"billing": "payment or invoice", "auth": "login or account access",'
123
+ ' "network": "connectivity"}}',
124
+ )
125
+ print(result["predicted_key"], result["probabilities"])
126
+ ```
127
+
128
+ `load_model` reads `model_config.json` to rebuild the architecture and `temperatures.json` to apply the fitted per-(type, K-bucket) temperature at inference, so the reported probabilities are already calibration-scaled.
129
+
130
+ ## Training data
131
+
132
+ `LocalLLaMA/typed-decisions` (Apache-2.0): 1,200 train cases and 400 test cases across four workflows (agent-trace observability, customer service, invoice processing, security incidents), flattened to ~5,400 training decisions. Targets are the dataset's soft teacher distributions, not the hard labels.
133
+
134
+ ## Training procedure
135
+
136
+ - Initialised from `convaiinnovations/laya`.
137
+ - Loss: soft cross-entropy against the teacher distributions only (no RL term).
138
+ - 4 epochs, effective batch 64 (micro-batch 8 x 4 accumulation on a single 24 GB GPU), AdamW, lr 2.5e-5 encoder / 1e-4 head, weight decay 0.01, cosine decay to 1e-6, gradient clipping 1.0, bf16.
139
+ - No early stopping; the final-epoch weights are evaluated.
140
+ - Post-hoc temperature fitted per (question type, option-count bucket) by NLL on a held-out 10% slice of the training cases.
141
+
142
+ ## Evaluation
143
+
144
+ Full test-set breakdown by question type (2,000 decisions):
145
+
146
+ | Type | n | Accuracy | Brier | NLL | Mean conf. | Mean target max |
147
+ |---|---|---|---|---|---|---|
148
+ | choice | 600 | 0.7550 | 0.0611 | 0.9818 | 0.6194 | 0.6345 |
149
+ | score | 800 | 0.7588 | 0.0511 | 1.0331 | 0.5817 | 0.5929 |
150
+ | noul | 600 | 0.8617 | 0.0356 | 0.5009 | 0.7532 | 0.7714 |
151
+ | overall | 2000 | 0.7885 | 0.0495 | 0.8581 | 0.6444 | 0.6589 |
152
+
153
+ **A calibration caveat that matters here.** On this benchmark the gold hard label is the teacher's argmax on 98.4% of rows, so hard-label ECE is not a valid calibration measure: a model that reproduces the teacher perfectly still scores 0.326 hard-label ECE, and over-sharpening *lowers* it. The raw hard-label ECE of this checkpoint is 0.144 (0.162 after temperature). Judge calibration against the soft targets instead, with Brier and NLL above. The fitted temperatures (all > 1) are the model's own signal that the raw logits were slightly over-sharp before scaling.
154
+
155
+ ## Relation to RLCD
156
+
157
+ This checkpoint is deliberately RL-free. In the accompanying study, adding Laya's RL term (a score-function estimate of a noise-smoothed proper score) did not improve accuracy and made the fitted temperature rise with the training noise scale. CE-only was at least as good on every proper score. See the linked repo for the full ablation, the estimator derivation, and the per-run result files.
158
+
159
+ ## Limitations
160
+
161
+ - Single benchmark; the four workflows are synthetic and teacher-generated.
162
+ - English only.
163
+ - Option sets above ~20 options degrade, because options share a fixed token budget.
164
+ - Accuracy differences of ~1 point are within seed noise on a dataset this size; three seeds gave 0.782 +/- 0.004 for the 512-token variant.
165
+ - The base checkpoint was already fine-tuned by the Laya authors; this model is a further fine-tune on the same benchmark's train split.
166
+
167
+ ## Links
168
+
169
+ - Code, configs, and per-run results: [LakoreAI/rlcd-reverse-engineering](https://github.com/LakoreAI/rlcd-reverse-engineering)
170
+ - All ablation checkpoints and metrics: [minhleduc/rlcd-e2-checkpoints](https://huggingface.co/minhleduc/rlcd-e2-checkpoints)
171
+ - Base model: [convaiinnovations/laya](https://huggingface.co/convaiinnovations/laya)
172
+ - Dataset: [LocalLLaMA/typed-decisions](https://huggingface.co/datasets/LocalLLaMA/typed-decisions)
173
+
174
+ ## Citation
175
+
176
+ ```bibtex
177
+ @misc{leduc2026dissectingrlcd,
178
+ title = {Dissecting RLCD: What Reinforcement Learning Does (and Doesn't) Do for Calibrated Typed Decisions},
179
+ author = {Le Duc Minh},
180
+ year = {2026},
181
+ url = {https://github.com/LakoreAI/rlcd-reverse-engineering}
182
+ }
183
+ ```
config.json ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": {
3
+ "encoder_name": "answerdotai/ModernBERT-large",
4
+ "head_layers": 2,
5
+ "head_dropout": 0.1,
6
+ "num_qtypes": 3,
7
+ "cls_query": false,
8
+ "slot_emb": false,
9
+ "max_len": 1024,
10
+ "head_max_len": 256,
11
+ "k_buckets": [
12
+ 2,
13
+ 5,
14
+ 10
15
+ ]
16
+ },
17
+ "training": {
18
+ "dataset_name": "LocalLLaMA/typed-decisions",
19
+ "dataset_config": "all",
20
+ "calib_fraction": 0.1,
21
+ "seed": 42,
22
+ "max_examples": null,
23
+ "augment_permute": false,
24
+ "ckpt_dir": "checkpoints",
25
+ "result_dir": "results",
26
+ "run_name": "e2_ce_only_1024_seed42",
27
+ "epochs": 4,
28
+ "batch_size": 4,
29
+ "accum_steps": 16,
30
+ "num_workers": 4,
31
+ "pin_memory": true,
32
+ "amp": true,
33
+ "amp_dtype": "bf16",
34
+ "gradient_checkpointing": true,
35
+ "lr": 2.5e-05,
36
+ "lr_head": 0.0001,
37
+ "weight_decay": 0.01,
38
+ "grad_clip": 1.0,
39
+ "log_every": 10,
40
+ "eval_every": 1,
41
+ "ckpt_every": 4,
42
+ "w_rl": 0.0,
43
+ "w_ce": 1.0,
44
+ "num_noise_samples": 4,
45
+ "sigma_start": 0.4,
46
+ "sigma_end": 0.1,
47
+ "anneal_sigma": true,
48
+ "reward_w_spherical": 0.75,
49
+ "reward_w_rps": 1.0,
50
+ "arch": {
51
+ "encoder_name": "answerdotai/ModernBERT-large",
52
+ "head_layers": 2,
53
+ "max_len": 1024,
54
+ "head_max_len": 256
55
+ },
56
+ "init_from": "convaiinnovations/laya",
57
+ "log_grad_diagnostics": true,
58
+ "lr_scheduler": {
59
+ "type": "cosine",
60
+ "t_max": "auto",
61
+ "eta_min": 1e-06
62
+ },
63
+ "early_stopping": {
64
+ "enabled": false
65
+ },
66
+ "save_best": false,
67
+ "best_metric": "raw_ece",
68
+ "best_mode": "min",
69
+ "wandb": {
70
+ "enabled": true,
71
+ "project": "rlcd-reverse-engineering",
72
+ "entity": null,
73
+ "group": "e2-acc",
74
+ "log_artifacts": false
75
+ },
76
+ "resume_from": null
77
+ }
78
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:be8aae6b150491cfe3d8049d69fce35dc06dfe4aac1db1d71a321b19432a9f9f
3
+ size 1684141044
model_config.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "encoder_name": "answerdotai/ModernBERT-large",
3
+ "head_layers": 2,
4
+ "head_dropout": 0.1,
5
+ "num_qtypes": 3,
6
+ "cls_query": false,
7
+ "slot_emb": false,
8
+ "max_len": 1024,
9
+ "head_max_len": 256,
10
+ "k_buckets": [
11
+ 2,
12
+ 5,
13
+ 10
14
+ ],
15
+ "source_checkpoint": "epoch_4.pt",
16
+ "epoch": 4,
17
+ "step": 340
18
+ }
temperatures.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "k_buckets": [
3
+ 2,
4
+ 5,
5
+ 10
6
+ ],
7
+ "temperatures": [
8
+ {
9
+ "qtype": 0,
10
+ "bucket": 1,
11
+ "T": 1.116391658782959
12
+ },
13
+ {
14
+ "qtype": 1,
15
+ "bucket": 1,
16
+ "T": 1.0700936317443848
17
+ },
18
+ {
19
+ "qtype": 2,
20
+ "bucket": 0,
21
+ "T": 1.1198104619979858
22
+ }
23
+ ]
24
+ }
test_eval.json ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "raw": {
3
+ "ece": 0.14405169022083278,
4
+ "brier": 0.049473914223986594,
5
+ "nll": 0.8580627283966169,
6
+ "accuracy": 0.7885,
7
+ "soft_accuracy": 0.5236424660123885,
8
+ "mean_confidence": 0.6444483368843794,
9
+ "mean_target_max": 0.6589462240487337,
10
+ "score_mae": 0.21151374208275228,
11
+ "n": 2000,
12
+ "by_type": {
13
+ "choice": {
14
+ "ece": 0.1381368541220824,
15
+ "brier": 0.0610927829263998,
16
+ "nll": 0.9818144658269982,
17
+ "accuracy": 0.755,
18
+ "soft_accuracy": 0.48078609759608903,
19
+ "mean_confidence": 0.6193696513772011,
20
+ "mean_target_max": 0.6345381752649943,
21
+ "score_mae": null,
22
+ "n": 600
23
+ },
24
+ "score": {
25
+ "ece": 0.1779335317760706,
26
+ "brier": 0.05114634511056351,
27
+ "nll": 1.03313795868773,
28
+ "accuracy": 0.75875,
29
+ "soft_accuracy": 0.4435949847009033,
30
+ "mean_confidence": 0.5816603348776698,
31
+ "mean_target_max": 0.5928848401084542,
32
+ "score_mae": 0.21151374208275228,
33
+ "n": 800
34
+ },
35
+ "noul": {
36
+ "ece": 0.10842230906089145,
37
+ "brier": 0.03562513767280417,
38
+ "nll": 0.5008773505780846,
39
+ "accuracy": 0.8616666666666667,
40
+ "soft_accuracy": 0.6732288095106681,
41
+ "mean_confidence": 0.7532443584005037,
42
+ "mean_target_max": 0.7714361180861791,
43
+ "score_mae": null,
44
+ "n": 600
45
+ }
46
+ }
47
+ },
48
+ "post_temperature": {
49
+ "ece": 0.16220938038825988,
50
+ "brier": 0.04794188590972476,
51
+ "nll": 0.8542706172754988,
52
+ "accuracy": 0.7885,
53
+ "soft_accuracy": 0.5147140698879957,
54
+ "mean_confidence": 0.6262906277328729,
55
+ "mean_target_max": 0.6589462240487337,
56
+ "score_mae": 0.21261174298007973,
57
+ "n": 2000,
58
+ "by_type": {
59
+ "choice": {
60
+ "ece": 0.16171381801366805,
61
+ "brier": 0.058598528968896064,
62
+ "nll": 0.9764881309494376,
63
+ "accuracy": 0.755,
64
+ "soft_accuracy": 0.46792497878273326,
65
+ "mean_confidence": 0.5932861614724,
66
+ "mean_target_max": 0.6345381752649943,
67
+ "score_mae": null,
68
+ "n": 600
69
+ },
70
+ "score": {
71
+ "ece": 0.19320389255881307,
72
+ "brier": 0.04962007356784852,
73
+ "nll": 1.0289345176471398,
74
+ "accuracy": 0.75875,
75
+ "soft_accuracy": 0.4367176624760032,
76
+ "mean_confidence": 0.5665761560201645,
77
+ "mean_target_max": 0.5928848401084542,
78
+ "score_mae": 0.21261174298007973,
79
+ "n": 800
80
+ },
81
+ "noul": {
82
+ "ece": 0.12275225609540938,
83
+ "brier": 0.035047659306388444,
84
+ "nll": 0.49916790310603876,
85
+ "accuracy": 0.8616666666666667,
86
+ "soft_accuracy": 0.6654983708759149,
87
+ "mean_confidence": 0.7389143896102905,
88
+ "mean_target_max": 0.7714361180861791,
89
+ "score_mae": null,
90
+ "n": 600
91
+ }
92
+ }
93
+ },
94
+ "fitted_temperature": {
95
+ "type0_bucket1": 1.116391658782959,
96
+ "type2_bucket0": 1.1198104619979858,
97
+ "type1_bucket1": 1.0700936317443848
98
+ }
99
+ }
train_log.json ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "epoch": 1,
4
+ "step": 85,
5
+ "loss": 0.9641271437353948,
6
+ "sigma": 0.4,
7
+ "epoch_seconds": 228.8010711669922,
8
+ "train_rows": 5400,
9
+ "raw_ece": 0.10835536271333696,
10
+ "raw_brier": 0.07556118707742442,
11
+ "raw_nll": 0.8722028755644957,
12
+ "raw_accuracy": 0.7066666666666667,
13
+ "raw_soft_accuracy": 0.4981412665049235,
14
+ "raw_mean_confidence": 0.5995895755290985,
15
+ "raw_mean_target_max": 0.6725333379705747,
16
+ "raw_score_mae": 0.29329004988539964,
17
+ "raw_n": 600
18
+ },
19
+ {
20
+ "epoch": 2,
21
+ "step": 170,
22
+ "loss": 0.8357182100488275,
23
+ "sigma": 0.30000000000000004,
24
+ "epoch_seconds": 224.5660684108734,
25
+ "train_rows": 5400,
26
+ "raw_ece": 0.16046804825464883,
27
+ "raw_brier": 0.05988674723912672,
28
+ "raw_nll": 0.8413767837701986,
29
+ "raw_accuracy": 0.7716666666666666,
30
+ "raw_soft_accuracy": 0.5137750238180161,
31
+ "raw_mean_confidence": 0.615313962996006,
32
+ "raw_mean_target_max": 0.6725333379705747,
33
+ "raw_score_mae": 0.24656671059007446,
34
+ "raw_n": 600
35
+ },
36
+ {
37
+ "epoch": 3,
38
+ "step": 255,
39
+ "loss": 0.8000329575373554,
40
+ "sigma": 0.2,
41
+ "epoch_seconds": 223.96768260002136,
42
+ "train_rows": 5400,
43
+ "raw_ece": 0.1488726359605789,
44
+ "raw_brier": 0.05451012486705442,
45
+ "raw_nll": 0.8328132717187205,
46
+ "raw_accuracy": 0.78,
47
+ "raw_soft_accuracy": 0.5247553873838235,
48
+ "raw_mean_confidence": 0.6352111848195394,
49
+ "raw_mean_target_max": 0.6725333379705747,
50
+ "raw_score_mae": 0.22168685695699727,
51
+ "raw_n": 600
52
+ },
53
+ {
54
+ "epoch": 4,
55
+ "step": 340,
56
+ "loss": 0.7846576284726753,
57
+ "sigma": 0.09999999999999998,
58
+ "epoch_seconds": 222.44736337661743,
59
+ "train_rows": 5400,
60
+ "raw_ece": 0.13711758901675544,
61
+ "raw_brier": 0.052573612098253716,
62
+ "raw_nll": 0.8299004402291029,
63
+ "raw_accuracy": 0.7766666666666666,
64
+ "raw_soft_accuracy": 0.5293207626231015,
65
+ "raw_mean_confidence": 0.6415973689158757,
66
+ "raw_mean_target_max": 0.6725333379705747,
67
+ "raw_score_mae": 0.21637691374926363,
68
+ "raw_n": 600
69
+ }
70
+ ]