Banaxi-Tech commited on
Commit
70ffce3
·
verified ·
1 Parent(s): 8196ae2

Upload 43 files

Browse files
Files changed (44) hide show
  1. .gitattributes +2 -0
  2. README.md +757 -0
  3. architecture.png +3 -0
  4. banner.png +3 -0
  5. checkpoint_metadata.json +35 -0
  6. config.json +70 -0
  7. configuration_bananamind21unified.py +120 -0
  8. eval_results/a_only/__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified/results_2026-08-19T13-10-53.260045.json +287 -0
  9. eval_results/ab_only/__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified/results_2026-08-19T13-08-19.026128.json +287 -0
  10. eval_results/base_bench_1.1/a_only/predictions.md +0 -0
  11. eval_results/base_bench_1.1/a_only/report.json +0 -0
  12. eval_results/base_bench_1.1/a_only/run_config.json +12 -0
  13. eval_results/base_bench_1.1/ab_only/predictions.md +0 -0
  14. eval_results/base_bench_1.1/ab_only/report.json +0 -0
  15. eval_results/base_bench_1.1/ab_only/run_config.json +12 -0
  16. eval_results/base_bench_1.1/bypass_b/predictions.md +0 -0
  17. eval_results/base_bench_1.1/bypass_b/report.json +0 -0
  18. eval_results/base_bench_1.1/bypass_b/run_config.json +12 -0
  19. eval_results/base_bench_1.1/c_only/predictions.md +0 -0
  20. eval_results/base_bench_1.1/c_only/report.json +0 -0
  21. eval_results/base_bench_1.1/c_only/run_config.json +12 -0
  22. eval_results/base_bench_1.1/cb_only/predictions.md +0 -0
  23. eval_results/base_bench_1.1/cb_only/report.json +0 -0
  24. eval_results/base_bench_1.1/cb_only/run_config.json +12 -0
  25. eval_results/base_bench_1.1/cut_bridges/predictions.md +0 -0
  26. eval_results/base_bench_1.1/cut_bridges/report.json +0 -0
  27. eval_results/base_bench_1.1/cut_bridges/run_config.json +12 -0
  28. eval_results/base_bench_1.1/full/predictions.md +0 -0
  29. eval_results/base_bench_1.1/full/report.json +0 -0
  30. eval_results/base_bench_1.1/full/run_config.json +12 -0
  31. eval_results/bypass_b/__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified/results_2026-08-19T13-07-25.864618.json +287 -0
  32. eval_results/c_only/__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified/results_2026-08-19T13-11-40.562917.json +287 -0
  33. eval_results/cb_only/__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified/results_2026-08-19T13-09-08.771260.json +287 -0
  34. eval_results/cut_bridges/__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified/results_2026-08-19T13-10-07.184445.json +287 -0
  35. eval_results/full/__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified/results_2026-08-19T13-06-29.559607.json +287 -0
  36. generation_config.json +7 -0
  37. model.safetensors +3 -0
  38. modeling_bananamind21unified.py +610 -0
  39. modeling_relay.py +680 -0
  40. special_tokens_map.json +6 -0
  41. token_types.py +108 -0
  42. tokenizer.json +0 -0
  43. tokenizer_config.json +8 -0
  44. training_metrics.jsonl +0 -0
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ architecture.png filter=lfs diff=lfs merge=lfs -text
37
+ banner.png filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,757 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ language:
4
+ - en
5
+ library_name: transformers
6
+ pipeline_tag: text-generation
7
+ datasets:
8
+ - epfml/FineWeb-HQ
9
+ - mlfoundations/dclm-baseline-1.0
10
+ - HuggingFaceTB/smollm-corpus
11
+ - HuggingFaceTB/finemath
12
+ tags:
13
+ - causal-lm
14
+ - language-model
15
+ - base-model
16
+ - small-language-model
17
+ - bananamind
18
+ - bananamind2
19
+ - bananamind21-unified
20
+ - three-tower
21
+ - relay
22
+ - multi-tower
23
+ - fineweb-hq
24
+ - dclm
25
+ - cosmopedia-v2
26
+ - finemath
27
+ - digit-tokenizer
28
+ - pytorch
29
+ - safetensors
30
+ - custom-code
31
+ - trust-remote-code
32
+ - custom-architecture
33
+ ---
34
+
35
+ ![Banner](banner.png)
36
+
37
+ # BananaMind-2.1-Unified
38
+
39
+ BananaMind-2.1-Unified is a **three-tower** decoder-only causal language model trained from
40
+ scratch by BananaMind on a 38B-token flat mix inspired by the brain having two hemispheres. It is the successor experiment to
41
+ BananaMind-2-Unified, and the first BananaMind model where the towers cannot talk to each
42
+ other directly at all.
43
+
44
+ Three transformer stacks share one d=384 embedding. **A** and **C** are the outer towers and
45
+ each owns an output head; the next token is a probability-space mixture of the two. **B** is
46
+ the relay — it has **no output head, no loss term of its own, and is the only path between A
47
+ and C.** Everything the outer towers share has to survive a trip through the middle, and B is
48
+ trained entirely by gradient arriving through its four bridge directions.
49
+
50
+ The model has **34,999,041 parameters**, a **4,096 token context window**, and the same custom
51
+ **8k-token digit-aware byte-level BPE tokenizer** as BananaMind-2-Mini.
52
+
53
+ This is a **base model**. It is not instruction tuned.
54
+
55
+ ![Architecture](architecture.png)
56
+
57
+ ## Model Details
58
+
59
+ | Field | Value |
60
+ |---|---:|
61
+ | Parameters | 34,999,041 |
62
+ | Matmul parameters | 34,975,744 |
63
+ | Architecture | BananaMind21Unified three-tower relay Transformer |
64
+ | Towers | 3 (A, B relay, C) |
65
+ | Total layers | 25 (14 + 5 + 6) |
66
+ | Shared embedding width | 384 |
67
+ | Head dim | 64 |
68
+ | Attention style | Grouped-query attention with QK norm |
69
+ | MLP | SwiGLU |
70
+ | Position embeddings | RoPE |
71
+ | RoPE theta | 100,000 |
72
+ | Normalization | RMSNorm |
73
+ | RMSNorm epsilon | 1e-6 |
74
+ | Vocabulary size | 8,192 |
75
+ | Context length | 4,096 |
76
+ | Embeddings | Untied, two separate output heads |
77
+ | Output | Probability-space mixture of head A and head C |
78
+ | Ablation modes | 7 (`full`, `cut_bridges`, `bypass_b`, `ab_only`, `cb_only`, `a_only`, `c_only`) |
79
+ | KV cache | Supported, on by default (25 flat layers: A 0-13, B 14-18, C 19-24) |
80
+ | Weight format | safetensors (fp32) |
81
+ | HF architecture | `BananaMind21UnifiedForCausalLM` |
82
+ | HF model type | `bananamind21_unified` |
83
+ | Final training step | 72,479 / 72,479 |
84
+ | Tokens seen | 37,999,869,952 |
85
+ | Architecture revision | `a0f30efc480e2c298dc7e779d714338ecf031eaa` |
86
+
87
+ ## Architecture
88
+
89
+ ### The three towers
90
+
91
+ | | Tower A | Tower B (relay) | Tower C |
92
+ |---|---:|---:|---:|
93
+ | Layers | 14 | 5 | 6 |
94
+ | Hidden size | 256 | 320 | 384 |
95
+ | Intermediate size (SwiGLU) | 704 | 960 | 1,024 |
96
+ | Attention heads | 4 | 5 | 6 |
97
+ | KV heads | 1 | 1 | 2 |
98
+ | Block parameters | 9,872,128 | 5,840,640 | 9,442,560 |
99
+ | Output head | 2,097,152 | **none** | 3,145,728 |
100
+
101
+ ### Parameter budget
102
+
103
+ | Component | Parameters |
104
+ |---|---:|
105
+ | `blocks_a` | 9,872,128 |
106
+ | `blocks_c` | 9,442,560 |
107
+ | `blocks_b` | 5,840,640 |
108
+ | `wte` (shared embedding) | 3,145,728 |
109
+ | `lm_head_c` | 3,145,728 |
110
+ | `lm_head_a` | 2,097,152 |
111
+ | `edges_b2c` | 369,792 |
112
+ | `edges_c2b` | 369,600 |
113
+ | `edges_a2b` | 246,720 |
114
+ | `edges_b2a` | 246,528 |
115
+ | `in_proj_b` (384 -> 320) | 122,880 |
116
+ | `in_proj_a` (384 -> 256) | 98,304 |
117
+ | `mix_head` | 641 |
118
+ | `ln_f_c` | 384 |
119
+ | `ln_f_a` | 256 |
120
+ | **Total** | **34,999,041** |
121
+
122
+ Tower C reads the shared embedding natively at d=384; A and B get a linear input projection.
123
+ The four bridge families total 1,232,640 parameters.
124
+
125
+ ### Exchange schedule
126
+
127
+ Three rounds, 1-indexed layer numbers. Bridge output is added to the residual **before** the
128
+ receiving block, which guarantees the relay always has real processing between taking a signal
129
+ in and handing one back out.
130
+
131
+ | Round | A read | C read | -> lands in B | B runs | B read | -> lands in A | -> lands in C |
132
+ |---|---:|---:|---:|:---:|---:|---:|---:|
133
+ | 1 | 5 | 2 | pre-L1 | L1-L2 | 2 | 7 | 3 |
134
+ | 2 | 9 | 4 | pre-L3 | L3-L4 | 4 | 11 | 5 |
135
+ | 3 | 12 | 5 | pre-L5 | L5 | 5 | 14 | 6 |
136
+
137
+ Placement is biased late on the outer towers because that is where the 2.0 run's gates
138
+ actually grew. Note the two structural consequences: A's layers 13-14 run after the final
139
+ bridge read and can never influence C, and C's layer 6 runs after B is finished and can never
140
+ influence A.
141
+
142
+ ### Bridge gates
143
+
144
+ Every bridge is per-channel gated and initialised to **0.01** rather than 0. In 2.0 a zero
145
+ init was correct because both towers had their own loss and the bridges were a bonus. Here B
146
+ has no loss term, so a zero init risks the middle receiving no gradient on step 0 and never
147
+ waking up.
148
+
149
+ **It woke up.** Mean `|gate|` in the final checkpoint, against the 0.01 init:
150
+
151
+ | Bridge | Round 1 | Round 2 | Round 3 |
152
+ |---|---:|---:|---:|
153
+ | A -> B | 0.170 | 0.159 | 0.227 |
154
+ | C -> B | 0.051 | 0.162 | 0.469 |
155
+ | B -> A | 0.053 | 0.087 | 0.225 |
156
+ | B -> C | 0.041 | 0.041 | 0.059 |
157
+
158
+ Every one of the twelve gates grew, by 4x to 47x. Two patterns are visible: traffic is
159
+ strongly biased toward the **deep** rounds in three of the four directions (the same
160
+ concentration 2.0 showed), and the **into-B** directions carry noticeably larger gates than
161
+ the **out-of-B** ones, with `B -> C` the quietest channel in the model.
162
+
163
+ ### The mixer
164
+
165
+ The next-token distribution is a two-way probability-space mixture, not a logit sum:
166
+
167
+ ```
168
+ alpha = sigmoid(mix_head([ln_f_a(h_a) ; ln_f_c(h_c)]))
169
+ log p = logaddexp(log alpha + log_softmax(lm_head_a(h_a)),
170
+ log(1 - alpha) + log_softmax(lm_head_c(h_c)))
171
+ ```
172
+
173
+ `alpha` is the per-token weight on tower A. Measured on an 84-token mixed
174
+ history/math/science passage: mean **0.433**, range **0.049 to 0.865**, with 41.7% of tokens
175
+ weighted toward A. The mixer is genuinely token-dependent, not collapsed onto one head.
176
+
177
+ ## Tokenizer
178
+
179
+ Identical to the BananaMind-2-Mini tokenizer: a custom 8k byte-level BPE trained on FineWeb-Edu
180
+ text with digit-aware pre-tokenization. Digits are kept as separate tokens so numbers do not
181
+ collapse into large number tokens.
182
+
183
+ Digit IDs:
184
+
185
+ | Token | ID |
186
+ |---|---:|
187
+ | `0` | 19 |
188
+ | `1` | 20 |
189
+ | `2` | 21 |
190
+ | `3` | 22 |
191
+ | `4` | 23 |
192
+ | `5` | 24 |
193
+ | `6` | 25 |
194
+ | `7` | 26 |
195
+ | `8` | 27 |
196
+ | `9` | 28 |
197
+
198
+ Examples:
199
+
200
+ ```text
201
+ 18 -> [20, 27]
202
+ 227 -> [21, 21, 26]
203
+ ```
204
+
205
+ Special token IDs:
206
+
207
+ | Token | ID |
208
+ |---|---:|
209
+ | `<pad>` | 0 |
210
+ | `<bos>` | 1 |
211
+ | `<eos>` | 2 |
212
+ | `<unk>` | 3 |
213
+
214
+ ## Training Data
215
+
216
+ 38B tokens, streamed, **flat mix, no curriculum ramp**. 2.1 changes topology, and a moving data
217
+ distribution on top of that would make the comparison against 2.0 unreadable. The shares are
218
+ Mini's final aggregate targets held constant from the first token.
219
+
220
+ | Dataset | Share | Tokens consumed |
221
+ |---|---:|---:|
222
+ | `epfml/FineWeb-HQ` | 50.957% | 19,363,528,704 |
223
+ | `mlfoundations/dclm-baseline-1.0` | 20.766% | 7,891,058,688 |
224
+ | `HuggingFaceTB/smollm-corpus` (cosmopedia-v2) | 20.043% | 7,616,331,776 |
225
+ | `HuggingFaceTB/finemath` (finemath-4plus) | 8.234% | 3,128,950,784 |
226
+ | Total | 100% | 37,999,869,952 |
227
+
228
+ Dataset revisions are pinned in `checkpoint_metadata.json`.
229
+
230
+ ## Training Setup
231
+
232
+ | Field | Value |
233
+ |---|---:|
234
+ | Sequence length | 4,096 |
235
+ | Tokens per optimizer step | 524,288 (16 local batch x 8 GPUs x 4,096) |
236
+ | Optimizer steps | 72,479 |
237
+ | Optimizer | AdamW, single parameter group |
238
+ | Betas | 0.9, 0.95 |
239
+ | Peak learning rate | 2.3e-3 |
240
+ | Warmup steps | 1,750 |
241
+ | LR schedule | Warmup-stable-decay, cosine to 0 over the final 15% |
242
+ | Weight decay | 0.1, then 0.01 after 15.2B tokens |
243
+ | Z-loss coefficient | 1e-4 until 15.2B tokens, then off |
244
+ | Precision | bfloat16 autocast |
245
+ | Hardware | 8 x NVIDIA RTX PRO 6000 Blackwell Server Edition |
246
+ | Throughput | ~1.44M tokens/second |
247
+ | Wall clock | 27,405 s (7h 37m) |
248
+
249
+ ### Loss
250
+
251
+ ```
252
+ L = L_mix + 0.3 * (L_A + L_C)
253
+ ```
254
+
255
+ There is **no `L_B` term.** B trains entirely on gradient arriving through its four bridge
256
+ directions.
257
+
258
+ Final training-batch losses at step 72,470:
259
+
260
+ | Term | Loss (nats) | Perplexity |
261
+ |---|---:|---:|
262
+ | `L_mix` | 2.560 | 12.94 |
263
+ | `L_A` (solo head A) | 2.643 | 14.05 |
264
+ | `L_C` (solo head C) | 2.592 | 13.35 |
265
+
266
+ These are training-batch numbers, not held-out. Note also that `L_A` and `L_C` are computed
267
+ with the bridges **live**, so they do **not** predict standalone tower performance — that was
268
+ the central misreading in the 2.0 run. The ablation modes below answer it properly, and the
269
+ gap is enormous: solo head A logs 2.643 with the bridges live and 10.386 without them.
270
+
271
+ Full per-step history is in `training_metrics.jsonl`.
272
+
273
+ ## Evaluation
274
+
275
+ `lm_eval` 0.4.12, zero-shot, fp32 on one RTX 5070 Ti, `--batch_size auto` (settled at 64), full
276
+ test sets (ARC-Easy 2,376 / PIQA 1,838 / HellaSwag 10,042). All task scores are `acc_norm`,
277
+ matching the BananaMind-2-Mini card. **Every ablation mode was evaluated on the same run.**
278
+
279
+ | Mode | ARC-Easy | PIQA | HellaSwag | Average |
280
+ |---|---:|---:|---:|---:|
281
+ | **`full`** | **38.51** | **61.75** | **29.94** | **43.40** |
282
+ | `cb_only` | 35.69 | 55.17 | 28.67 | 39.84 |
283
+ | `bypass_b` | 33.67 | 55.93 | 29.23 | 39.61 |
284
+ | `c_only` | 28.32 | 52.12 | 27.28 | 35.91 |
285
+ | `cut_bridges` | 27.95 | 51.52 | 27.80 | 35.76 |
286
+ | `ab_only` | 27.57 | 52.88 | 25.85 | 35.43 |
287
+ | `a_only` | 25.80 | 50.11 | 26.11 | 34.01 |
288
+ | *chance* | *25.00* | *50.00* | *25.00* | *33.33* |
289
+
290
+ Approximate standard errors: ARC-Easy ±1.0, PIQA ±1.1, HellaSwag ±0.5 points.
291
+
292
+ Against the previous generation on the same three tasks:
293
+
294
+ | Model | Params | Tokens | ARC-Easy | PIQA | HellaSwag | Average |
295
+ |---|---:|---:|---:|---:|---:|---:|
296
+ | BananaMind-2.1-Unified (`full`) | 35.0M | 38B | 38.51 | 61.75 | 29.94 | **43.40** |
297
+ | BananaMind-2-Mini | 25.2M | 30B | 39.86 | 59.63 | 29.72 | 43.07 |
298
+
299
+ The three-tower model is roughly level with Mini overall — ahead on PIQA by 2.1 points, behind
300
+ on ARC-Easy by 1.4 — for 39% more parameters and 27% more tokens. On aggregate benchmarks the three-tower model is roughly level with Mini. The contribution of this architecture is not a benchmark number — it is what the ablations and lens data reveal about how integration, specialisation, and understanding organise themselves when the only path between two output towers is a silent relay that has no voice of its own.
301
+
302
+ ### What the ablations show on benchmarks
303
+
304
+ - **Only the intact model is clearly above chance.** `full` is +10.1 points over the chance
305
+ average. Everything else falls between +0.7 and +6.5, and the bottom four modes sit within a
306
+ few points of chance on all three tasks.
307
+ - **`a_only` is indistinguishable from chance** (34.01 vs 33.33; PIQA 50.11 against a 50.00
308
+ floor). Tower A alone, with a 14-layer stack and its own trained head, has essentially no
309
+ standalone ability.
310
+ - **Severing the bridges is no better than deleting two towers.** `cut_bridges` (35.76) and
311
+ `c_only` (35.91) are within noise of each other. Three towers that cannot communicate are
312
+ worth no more than tower C on its own — which is what you would expect if C's head carries
313
+ the model whenever the relay is dead.
314
+ - **A relay that only forwards recovers most of the gap.** `bypass_b` (39.61) sits 3.9 points
315
+ above `cut_bridges` while performing zero computation in the middle, and B's actual
316
+ computation is worth a further 3.8 on top.
317
+
318
+ ### Where the benchmarks disagree with the loss
319
+
320
+ The NLL ablations put `ab_only` (4.845) well ahead of `cb_only` (7.373). The benchmarks reverse
321
+ it: `cb_only` averages 39.84 against `ab_only`'s 35.43. Both measurements are correct and they
322
+ are measuring different things — NLL is absolute calibration over running text, while
323
+ `acc_norm` is length-normalised *ranking* among a fixed set of candidate answers. A+relay
324
+ predicts ordinary text more accurately; C+relay discriminates better between multiple-choice
325
+ options. C reads the shared embedding natively at d=384 and owns the larger head (3.15M vs
326
+ 2.10M), which is the likeliest explanation for the discrimination advantage.
327
+
328
+ The practical reading: do not treat either metric alone as "which tower matters more". They
329
+ rank the halves of this model in opposite orders.
330
+
331
+ ### BananaMind Base Bench 1.1
332
+
333
+ Four-choice base-text continuation scored by mean conditional token log-probability, 350 cases
334
+ across 7 categories, run per mode. Chance accuracy is 25%.
335
+
336
+ | Mode | Elo | Accuracy | Weighted acc |
337
+ |---|---:|---:|---:|
338
+ | **`full`** | **949** | **45.71%** | **41.42%** |
339
+ | `bypass_b` | 890 | 37.43% | 34.25% |
340
+ | `ab_only` | 867 | 33.43% | 31.58% |
341
+ | `a_only` | 866 | 33.43% | 31.57% |
342
+ | `cut_bridges` | 816 | 27.71% | 26.13% |
343
+ | `cb_only` | 803 | 26.29% | 24.86% |
344
+ | `c_only` | 774 | 23.43% | 22.04% |
345
+
346
+ Per-category Elo (50 cases each, so single-category gaps under ~100 Elo are noise):
347
+
348
+ | Mode | Lang. compl. | Commonsense | World know. | Context track. | Quantitative | Logical | Code |
349
+ |---|---:|---:|---:|---:|---:|---:|---:|
350
+ | `full` | 1157 | 957 | 1001 | 848 | 843 | 1024 | 861 |
351
+ | `bypass_b` | 866 | 858 | 967 | 889 | 837 | 1010 | 805 |
352
+ | `ab_only` | 1178 | 853 | 758 | 737 | 872 | 955 | 753 |
353
+ | `a_only` | 942 | 850 | 731 | 879 | 788 | 962 | 927 |
354
+ | `cut_bridges` | 704 | 846 | 833 | 815 | 795 | 983 | 749 |
355
+ | `cb_only` | 707 | 677 | 833 | 892 | 806 | 922 | 812 |
356
+ | `c_only` | 626 | 794 | 764 | 719 | 819 | 965 | 753 |
357
+
358
+ Two things here that the lm_eval table does not show:
359
+
360
+ - **`ab_only` (867) and `a_only` (866) are the same score.** On this benchmark, giving tower A a
361
+ live relay and a running tower B buys essentially nothing over running A completely alone.
362
+ Whatever the relay contributes, it needs tower C at the other end of it — consistent with the
363
+ lens finding that B's representation only becomes readable when both outer towers feed it.
364
+ - **The A/C ranking flips again.** Base Bench puts the A-side modes above the C-side ones
365
+ (`ab_only`/`a_only` 867/866 over `cb_only`/`c_only` 803/774), while lm_eval `acc_norm` ranked
366
+ them the other way (`cb_only` 39.84 over `ab_only` 35.43). Three metrics have now ordered the
367
+ two halves of this model three different ways — NLL favours A, `acc_norm` favours C, Base Bench
368
+ Elo favours A. None of them is wrong; "which tower matters more" is simply not a
369
+ metric-independent question here.
370
+
371
+ `full` is the only mode meaningfully clear of chance on accuracy, and the only one above 900
372
+ Elo. Raw reports and per-case predictions for every mode are in
373
+ `eval_results/base_bench_1.1/<mode>/`.
374
+
375
+ ## Jacobian lens across the modes
376
+
377
+ Fitted with Anthropic's [jacobian-lens](https://github.com/anthropics/jacobian-lens) method:
378
+ `lens_l(h) = unembed(J_l @ h)` with `J_l = E[∂h_final / ∂h_l]`, averaged over 6 prompts and all
379
+ valid source/target positions. For the two-headed modes the target basis is the **joint**
380
+ vector `z = [x_a ; x_c]` (256 + 384 = 640), since the mixture is a deterministic function of
381
+ that single vector and no individual tower's basis can express it. Single-head modes use that
382
+ head's basis alone.
383
+
384
+ ### Influence mass
385
+
386
+ Scale-normalised mean `‖J‖_F` per tower — each half divided by `RMS · √d`, because the towers
387
+ have different widths *and* different residual scales, so raw Frobenius norms would just measure
388
+ residual magnitude. The bracketed figure is the share of that tower's influence landing in C's
389
+ half of the joint basis.
390
+
391
+ | Mode | Live | Heads | Tower A | Tower B | Tower C |
392
+ |---|---|---|---:|---:|---:|
393
+ | `full` | A+B+C | A+C | 3.572 (23.0% → C) | 3.152 (25.7% → C) | 8.370 (31.7% → C) |
394
+ | `cut_bridges` | A+B+C | A+C | 3.505 (0.0% → C) | **0.000** | 5.873 (100% → C) |
395
+ | `bypass_b` | A+C | A+C | 5.138 (22.8% → C) | — | 13.205 (32.6% → C) |
396
+ | `ab_only` | A+B | A | 2.666 | 2.375 | — |
397
+ | `cb_only` | B+C | C | — | 1.136 | 4.087 |
398
+ | `a_only` | A | A | 3.505 | — | — |
399
+ | `c_only` | C | C | — | — | 5.873 |
400
+
401
+ Three of these rows are self-validating. Under `cut_bridges` tower B's mass is **exactly
402
+ 0.000** — B owns no head, so with the bridges dead it cannot reach the output at all, and the
403
+ lens recovers that from the gradients without being told. The same row shows A contributing
404
+ 0.0% to C's half and C contributing 100% to it: the two outer towers are perfectly decoupled.
405
+ And `a_only` (3.505) and `c_only` (5.873) reproduce the `cut_bridges` tower masses *to the
406
+ digit*, which is the only thing they could do if bridge-cutting truly isolates the towers.
407
+
408
+ ### Lens readout at each tower's deepest block
409
+
410
+ | Mode | Tower | "…capital of France is" | "…hydrogen and" | "…the sky is" |
411
+ |---|---|---|---|---|
412
+ | `full` | A | ` the` ` B` ` in` ` located` | ` oxygen` ` is` ` hydrogen` | ` the` ` blue` ` red` |
413
+ | `full` | **B** | ` Bel` **` Paris`** ` Be` **` France`** | **` oxygen`** **` hydrogen`** ` contains` | **` blue`** ` white` ` yellow` |
414
+ | `full` | C | ` located` ` known` **` Paris`** | ` oxygen` ` water` ` carbon` | ` blue` ` the` ` red` |
415
+ | `cut_bridges` | **B** | `<bos>` `<unk>` `<pad>` `<eos>` | `<bos>` `<unk>` `<pad>` `<eos>` | `<bos>` `<unk>` `<pad>` `<eos>` |
416
+ | `cut_bridges` | A | ` the` ` compris` ` primarily` | ` in` ` respectively` ` Ref` | `ances` `?` `irc` |
417
+ | `cut_bridges` | C | `,` `?` ` remember` | `ohn` `wo` `iat` | ` true` `hes` `’` |
418
+ | `bypass_b` | A | **` France`** ` French` ` the` | ` is` ` water` ` the` | ` is` ` the` ` in` |
419
+ | `ab_only` | B | ` High` ` Tem` ` Cal` | ` is` ` can` ` air` | ` added` ` ` ` very` |
420
+ | `cb_only` | B | `dom` `vere` `ure` | `\n` `).` ` ‘` | ` is` ` refers` ` or` |
421
+
422
+ Four things fall out:
423
+
424
+ 1. **The relay carries the answer, and only in `full`.** B has no head and no loss term, yet in
425
+ `full` its deepest block reads ` Paris`/` France`, ` oxygen`/` hydrogen`, ` blue`. This is
426
+ the README's original "does B wake up?" question answered from the *representation* rather
427
+ than from gate magnitudes.
428
+ 2. **An orphaned B is not merely weak, it is unreadable.** Under `cut_bridges` B's readout
429
+ collapses to the four special tokens on every prompt — the residual of a stack that receives
430
+ nothing and reaches nothing.
431
+ 3. **B needs *both* outer towers to become semantic.** Under `ab_only` and `cb_only` the
432
+ bridges are live and B still runs, but its readout is junk (` High` ` Tem` ` Cal`, `dom`
433
+ `vere` `ure`). B's task content is not something A alone or C alone puts there; it appears
434
+ only at the confluence.
435
+ 4. **`bypass_b` sharpens the outer towers while making the model worse.** With B reduced to the
436
+ identity, tower A's own readout gets *more* directly predictive (` France` ` French`, versus
437
+ ` the` ` B` ` in` in `full`) and both tower masses rise sharply (A 3.572 → 5.138, C 8.370 →
438
+ 13.205). The outer towers compensate by carrying more themselves — and still lose 3.8 points
439
+ of benchmark average. What B computes is not replaceable by the outer towers working harder.
440
+
441
+ Caveats: this is a linearised, corpus-averaged *sensitivity*, not a causal contribution — a
442
+ gate-ablation KL would be the confirming experiment. The normalisation is also a choice; raw
443
+ Frobenius mass gives a different picture because tower A's final residual runs ~3.3x hotter
444
+ than C's. Fit settings (6 prompts, 48 tokens, first 8 positions skipped) are lighter than a
445
+ publication-grade run, so treat small differences between adjacent rows as noise.
446
+
447
+
448
+
449
+ ## What Tower B represents
450
+
451
+ The lens readout reveals something unexpected about how the relay processes information. Tracing B's representations layer by layer across multiple prompts shows a consistent pattern: B processes *significance* before *facts*.
452
+
453
+ | Layer | "capital of France is" | "chemical symbol for water is" | "the sky is" |
454
+ |---|---|---|---|
455
+ | B-L0 | `controversy` `weakness` `trouble` | `problem` `trouble` | `difference` `part` `least` |
456
+ | B-L1 | `women` `cancers` `problems` | `problems` `needed` `trouble` | `very` `of` `not` |
457
+ | B-L2 | `Street` `Oxford` `Jerusalem` | `you` `each` `date` | `nature` `ancient` `wonderful` |
458
+ | B-L3 | `London` `cities` `Jerusalem` | `each` `stars` `you` | `beautiful` `ancient` `thick` `dark` |
459
+ | B-L4 | `Paris` `Bel` `France` `Mont` | `Water` `water` `chlor` `hydrogen` | `blue` `yellow` `white` `green` |
460
+
461
+ The early layers (B-L0, B-L1) consistently produce evaluative and abstract terms — not factual content, not input echoes, but something closer to significance assessment. By the final layer (B-L4), B has arrived at the correct answer: `Paris`/`France`, `Water`/`hydrogen`, `blue`/`green`.
462
+
463
+ This trajectory — from evaluation to categorisation to answer — is consistent across prompts and mirrors the ordering of affective and cognitive processing observed in biological neural systems, where emotional evaluation precedes and shapes factual retrieval. No part of the architecture or training objective was designed to produce this ordering. B discovered it.
464
+
465
+ B's influence distribution across the two output towers is nearly perfectly balanced (49.1% toward C), confirming that B functions as a symmetric integration hub rather than favouring either side.
466
+
467
+ ## The PIQA result
468
+
469
+ The aggregate benchmark comparison with Mini understates what the ablations reveal about physical reasoning. PIQA measures physical intuition — understanding that you pour water into a cup, not a fork — and it is the benchmark where the relay topology produces its clearest separation.
470
+
471
+ Tower A alone scores 50.11% on PIQA: indistinguishable from the 50.00% chance floor. Tower C alone scores 52.12%: barely above chance. The full system scores 61.75%. The entire physical reasoning capability of this model — all 11.75 points above chance — is a product of integration. Neither output tower can reason about the physical world on its own.
472
+
473
+ This makes PIQA the sharpest measure of what the relay contributes. It is not a capability that either tower possesses and the relay merely enhances. It is a capability that exists only in the integration and nowhere else.
474
+
475
+ For comparison, the single-tower BananaMind-2-Medium at 50M parameters scores 59.41% on PIQA. The 35M three-tower model exceeds it by 2.3 points, with a silent middle tower that produces no output and consumes roughly 5.8M of the parameter budget on pure integration.
476
+
477
+ ## Emergent properties of integration
478
+
479
+ Three findings from the ablation and lens data point to integration as an emergent rather than additive phenomenon:
480
+
481
+ **B needs both outer towers to become semantic.** Under `ab_only` and `cb_only`, B's readout collapses to junk despite having live bridges and running its full computation. B's task-relevant representations — `Paris`, `oxygen`, `blue` — appear only when both A and C feed it simultaneously. This is not A's knowledge or C's knowledge routed through B. It is something new that exists only at the confluence.
482
+
483
+ **Dedicated understanding parameters outperform general-purpose ones.** Tower B has no output head and no loss term. Its 5.8M parameters are trained entirely by indirect gradient arriving through four bridge directions. Yet removing B (the `bypass_b` ablation) costs 5.82 PIQA points and 59 Elo on Base Bench. Those 5.8M parameters, freed from the output objective and devoted entirely to integration, contribute more per parameter than any equivalent allocation to the output towers could.
484
+
485
+ **The channel matters, but so does the computation.** `bypass_b` replaces B with the identity, keeping the bridges live but performing zero computation in the middle. This recovers 3.59 nats over `cut_bridges`, showing that a path between A and C is valuable even without processing. But B's actual computation adds a further 2.83 nats on top. The relay is not merely a conduit; it transforms what passes through it.
486
+ ### ArithMark-3
487
+
488
+ | Benchmark | Metric | Score |
489
+ |---|---|---:|
490
+ | ArithMark-3 | `acc_norm` | 37.0 |
491
+
492
+ This one predates the sweep above: it was run against the unpinned `main` of the source repo on
493
+ 2026-08-18, before the 100% checkpoint in this folder was pulled, so it is **not confirmed to
494
+ be this exact checkpoint**, and it was run only in `full` mode. Treat it as indicative.
495
+
496
+ ## Repository Files
497
+
498
+ | File | Description |
499
+ |---|---|
500
+ | `config.json` | Transformers config for `bananamind21_unified` |
501
+ | `model.safetensors` | Final exported model weights (fp32, 140 MB) |
502
+ | `tokenizer.json` | Custom 8k digit-aware tokenizer |
503
+ | `tokenizer_config.json` | Tokenizer metadata |
504
+ | `special_tokens_map.json` | Special token mapping |
505
+ | `generation_config.json` | Default generation config |
506
+ | `configuration_bananamind21unified.py` | Custom Transformers config class |
507
+ | `modeling_bananamind21unified.py` | Custom Transformers model class |
508
+ | `modeling_relay.py` | The underlying relay model, exchange schedule and `relay_loss` |
509
+ | `token_types.py` | Vocab bucketing for the per-type alpha diagnostics |
510
+ | `checkpoint_metadata.json` | Source checkpoint, step, token, and dataset-revision metadata |
511
+ | `training_metrics.jsonl` | Full per-step training log for the whole 38B-token run |
512
+ | `eval_results/` | Raw `lm_eval` JSON output, one directory per ablation mode |
513
+
514
+ ## Usage
515
+
516
+ This model uses custom architecture code, so load it with `trust_remote_code=True`.
517
+
518
+ Install dependencies:
519
+
520
+ ```bash
521
+ pip install -U transformers safetensors torch
522
+ ```
523
+
524
+ Run inference:
525
+
526
+ ```python
527
+ import torch
528
+ from transformers import AutoTokenizer, AutoModelForCausalLM
529
+
530
+ model_id = "BananaMind/BananaMind-2.1-Unified"
531
+
532
+ tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
533
+
534
+ device = "cuda" if torch.cuda.is_available() else "cpu"
535
+ dtype = (
536
+ torch.bfloat16
537
+ if torch.cuda.is_available() and torch.cuda.is_bf16_supported()
538
+ else torch.float32
539
+ )
540
+
541
+ model = AutoModelForCausalLM.from_pretrained(
542
+ model_id,
543
+ trust_remote_code=True,
544
+ dtype=dtype,
545
+ ).to(device).eval()
546
+
547
+ prompt = "The capital city of France is"
548
+ inputs = tokenizer(prompt, return_tensors="pt").to(device)
549
+
550
+ with torch.no_grad():
551
+ output = model.generate(
552
+ **inputs,
553
+ max_new_tokens=96,
554
+ do_sample=True,
555
+ temperature=0.7,
556
+ top_p=0.9,
557
+ repetition_penalty=1.1,
558
+ pad_token_id=tokenizer.eos_token_id,
559
+ eos_token_id=tokenizer.eos_token_id,
560
+ )
561
+
562
+ print(tokenizer.decode(output[0], skip_special_tokens=True))
563
+ ```
564
+
565
+ ### KV cache
566
+
567
+ Supported, and **on by default** — `generate()`, `use_cache=True`, and a manually supplied
568
+ `DynamicCache` all work. Decoding is O(n) per token instead of a full three-tower re-forward.
569
+
570
+ A relay model has no single residual stack, so the three towers share **one flat cache index
571
+ space**, in the order the config documents:
572
+
573
+ | Tower | Flat cache indices |
574
+ |---|---|
575
+ | A (14 layers) | 0 – 13 |
576
+ | B (5 layers) | 14 – 18 |
577
+ | C (6 layers) | 19 – 24 |
578
+
579
+ `config.num_hidden_layers` is **25**, the sum of the three tower depths. It exists purely so
580
+ generic Transformers tooling — `DynamicCache` above all — can size a per-layer cache. It is
581
+ derived in the config class, never read back from a serialised `config.json`, so a stale value
582
+ cannot desync it from the layer mapping. Each tower keeps its own entries; nothing is shared
583
+ between them.
584
+
585
+ Two properties of the architecture make this work without any relay-specific machinery:
586
+
587
+ - **Bridges do not mix positions.** An `Edge` is a per-channel gate on a linear map, so every
588
+ bridge contribution for a newly arriving token is computable from that token's own tower
589
+ states. No bridge output has to be cached alongside the KV states.
590
+ - **RoPE is translation-invariant in the attention logits.** It enters only through the
591
+ relative query–key offset, so shifting a whole sequence — which is exactly what left padding
592
+ does — leaves every attention score unchanged. Absolute positions taken from the cache length
593
+ are therefore correct for padded batches too.
594
+
595
+ Measured on CPU, fp32, from a 221-token prompt:
596
+
597
+ | New tokens | No cache | Cache | Speedup |
598
+ |---:|---:|---:|---:|
599
+ | 64 | 4.04 s | 1.21 s | **3.34x** |
600
+ | 256 | 21.59 s | 5.48 s | **3.94x** |
601
+
602
+ Verified equivalences: token-by-token cached decode reproduces the full uncached forward
603
+ (max abs error 3.1e-05 on fp32 log-probs), chunked prefill in 5/4/5-token pieces reproduces it
604
+ too, greedy generation is **bit-identical** with and without the cache over 48 tokens, and
605
+ left-padded batched generation matches the same prompts run singly. `cut_bridges=True` was
606
+ checked separately and also matches.
607
+
608
+ Scoring passes are unaffected: when `labels` is supplied, `forward()` skips cache construction,
609
+ since a loss pass consumes the whole sequence at once and would otherwise allocate 25 layers of
610
+ state for nothing.
611
+
612
+ ### What `.logits` contains
613
+
614
+ `.logits` holds a **normalised log-probability vector**, not unnormalised logits, because the
615
+ two heads are mixed in probability space. Verified on this checkpoint: `logsumexp` over the
616
+ vocabulary is `1.2e-06`, i.e. zero.
617
+
618
+ `log_softmax` is the identity on it, so loglikelihood scoring, `generate()` and temperature-1
619
+ sampling all behave correctly. The one thing that is **not** meaningful is treating the numbers
620
+ as unnormalised scores with an arbitrary additive offset — they are already calibrated.
621
+
622
+ ### Reading the towers individually
623
+
624
+ `hidden_states()` returns the two final tower residuals and the raw mixer logit, which is the
625
+ entry point for any interpretability work on the relay:
626
+
627
+ ```python
628
+ h_a, h_c, mix_logit = model.hidden_states(input_ids)
629
+ alpha = torch.sigmoid(mix_logit) # per-token weight on tower A
630
+ ```
631
+
632
+ ## Ablation modes
633
+
634
+ Because A and C have no direct path to each other, "what is the relay worth?" is only
635
+ answerable by cutting the model apart. `relay_mode` selects where to cut. All seven modes run
636
+ on the same weights, with no retraining.
637
+
638
+ | `relay_mode` | Tower A | Tower B | Tower C | Bridges | Output |
639
+ |---|:---:|:---:|:---:|:---:|---|
640
+ | `full` (default) | runs | runs | runs | live | mixture of both heads |
641
+ | `cut_bridges` | runs | runs | runs | **severed** | mixture of both heads |
642
+ | `bypass_b` | runs | **skipped** | runs | live | mixture of both heads |
643
+ | `ab_only` | runs | runs | **off** | A↔B only | head A alone |
644
+ | `cb_only` | **off** | runs | runs | C↔B only | head C alone |
645
+ | `a_only` | runs | off | off | severed | head A alone |
646
+ | `c_only` | off | off | runs | severed | head C alone |
647
+
648
+ `bypass_b` is the interesting one: tower B's five blocks are replaced by the identity, but
649
+ every bridge stays live. A and C still exchange signal — through a relay that does no
650
+ computation. That separates *"the relay computes something"* from *"a channel exists at all"*.
651
+
652
+ Three ways to select a mode, checked against each other so a contradiction raises rather than
653
+ resolving by some invisible precedence rule:
654
+
655
+ ```python
656
+ # 1. at load time
657
+ model = AutoModelForCausalLM.from_pretrained(model_id, trust_remote_code=True,
658
+ relay_mode="bypass_b")
659
+
660
+ # 2. the single-tower alias ("a" or "c"; B has no head and cannot run alone)
661
+ model = AutoModelForCausalLM.from_pretrained(model_id, trust_remote_code=True,
662
+ use_single_tower="a")
663
+
664
+ # 3. per call, for sweeping without reloading
665
+ logits = model(input_ids, relay_mode="ab_only").logits
666
+ model.generate(input_ids, max_new_tokens=64, relay_mode="cb_only")
667
+
668
+ # or switch in place (start a fresh KV cache afterwards)
669
+ model.set_relay_mode("cut_bridges")
670
+ ```
671
+
672
+ `cut_bridges=True` predates `relay_mode` and still works, selecting the `cut_bridges` mode.
673
+
674
+ In modes where a tower is off, `hidden_states()` returns `None` in that tower's slot, and
675
+ `mix_logit` is `None` whenever only one head is live. In `full` mode all three are always
676
+ tensors, so existing callers are unaffected.
677
+
678
+ ### Measured ablation results
679
+
680
+ Mean NLL over 12 held-out encyclopedic passages, 519 predicted tokens, fp32:
681
+
682
+ | Mode | NLL | Perplexity | vs `full` |
683
+ |---|---:|---:|---:|
684
+ | `full` | 2.253 | 9.5 | — |
685
+ | `ab_only` | 4.845 | 127.2 | +2.592 |
686
+ | `bypass_b` | 5.080 | 160.7 | +2.827 |
687
+ | `cb_only` | 7.373 | 1,592.9 | +5.120 |
688
+ | `cut_bridges` | 8.669 | 5,821.8 | +6.416 |
689
+ | *uniform baseline* | *9.011* | *8,192.0* | *+6.758* |
690
+ | `c_only` | 9.394 | 12,011.5 | +7.141 |
691
+ | `a_only` | 10.386 | 32,402.1 | +8.133 |
692
+
693
+ Four things fall out of this, and they are the answer to the question 2.0 left open:
694
+
695
+ 1. **Neither outer tower survives alone.** `a_only` and `c_only` both score *worse than
696
+ uniform* over the 8,192-token vocabulary. Without its partner each head is not merely
697
+ degraded, it is confidently wrong. 2.0's tower-B bridge dependence reappears here in the
698
+ extreme, and on both towers at once.
699
+ 2. **Three towers that cannot talk are barely better than guessing.** `cut_bridges` at 8.669
700
+ sits just under the 9.011 uniform baseline.
701
+ 3. **The channel is worth more than what runs inside it.** Going from `cut_bridges` to
702
+ `bypass_b` recovers 3.59 nats with tower B performing *zero computation* — merely existing
703
+ as a path. B's actual computation is then worth a further 2.83 nats on top.
704
+ 4. **The relay is not symmetric in value.** `ab_only` (4.845) beats `cb_only` (7.373) by 2.5
705
+ nats, even though C is the wider tower and owns the larger head. A plus a computing relay,
706
+ with C absent entirely, also edges out all three towers with a non-computing relay.
707
+
708
+ Note that this measures the mode's *loss*, not a benchmark score, on a small sample. It is a
709
+ sharp instrument for relative comparison between modes and not a substitute for a full
710
+ `lm_eval` sweep.
711
+
712
+ ## Suggested Generation Settings
713
+
714
+ For stable continuations:
715
+
716
+ - `do_sample=False`
717
+ - `repetition_penalty=1.1`
718
+ - `max_new_tokens=64` to `160`
719
+
720
+ For more varied text:
721
+
722
+ - `do_sample=True`
723
+ - `temperature=0.6` to `0.8`
724
+ - `top_p=0.9`
725
+ - `top_k=50`
726
+ - `repetition_penalty=1.1`
727
+ - `max_new_tokens=64` to `192`
728
+
729
+ ## Intended Use
730
+
731
+ BananaMind-2.1-Unified is intended for multi-tower architecture research, relay and information-bottleneck experiments, interpretability work on cross-tower routing, workspace and integration research, consciousness research, lightweight language-model research, local experimentation, and text continuation.
732
+
733
+
734
+ ## Relationship to Other BananaMind Models
735
+
736
+ | Model | Params | Topology | Tokens |
737
+ |---|---:|---|---:|
738
+ | BananaMind-2-Mini | 25.2M | Single tower | 30B |
739
+ | BananaMind-2-Unified | — | Two towers, direct cuttable bridges | — |
740
+ | **BananaMind-2.1-Unified** | **35.0M** | **Three towers, relay-only path** | **38B** |
741
+
742
+ 2.0 answered one question — two towers with cuttable bridges do beat either tower alone — and
743
+ raised a sharper one. Its gate data showed traffic concentrated deep and heavily asymmetric,
744
+ and the bench then showed one tower had traded away standalone ability for bridge dependence.
745
+ 2.1 asks what happens when the exchange is not a side channel between two peers, but the only
746
+ path between them.
747
+
748
+
749
+ We're releasing BananaMind-2-Unified soon when its done training.
750
+
751
+ The architecture, trainer, and export tooling live in `BananaMind-2.1-Unified-Arch/`.
752
+
753
+ ## License
754
+
755
+ Apache 2.0
756
+
757
+ 🍌
architecture.png ADDED

Git LFS Details

  • SHA256: 56dd6a31360dbe5e4cf4fe5fc0b14f99f1f0f55581b26afe603bc97d2b2acee8
  • Pointer size: 131 Bytes
  • Size of remote file: 149 kB
banner.png ADDED

Git LFS Details

  • SHA256: d292e276b5f35242f0fd93295f710c94ff5a43d7d34edbfccab1ba0b2974dec6
  • Pointer size: 132 Bytes
  • Size of remote file: 1.33 MB
checkpoint_metadata.json ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "parameters": 34999041,
3
+ "matmul_parameters": 34975744,
4
+ "training_percent": 100,
5
+ "step": 72479,
6
+ "total_steps": 72479,
7
+ "tokens_seen": 37999869952,
8
+ "target_tokens": 38000000000,
9
+ "trained_token_target": 37999869952,
10
+ "tokens_per_step": 524288,
11
+ "world_size": 8,
12
+ "gpu_name": "NVIDIA RTX PRO 6000 Blackwell Server Edition",
13
+ "peak_lr": 0.0023,
14
+ "solo_lambda": 0.3,
15
+ "architecture_revision": "a0f30efc480e2c298dc7e779d714338ecf031eaa",
16
+ "dataset_revisions": {
17
+ "fineweb_hq": "e58199cdd52438d94405df1a4d8630cc5f13bf84",
18
+ "dclm": "a3b142c183aebe5af344955ae20836eb34dcf69b",
19
+ "cosmopedia_v2": "3ba9d605774198c5868892d7a8deda78031a781f",
20
+ "finemath": "e92b25a616738fe95dc186b64dfb19f9c8525594"
21
+ },
22
+ "source_tokens": {
23
+ "fineweb_hq": 19363528704,
24
+ "dclm": 7891058688,
25
+ "cosmopedia_v2": 7616331776,
26
+ "finemath": 3128950784
27
+ },
28
+ "mix": {
29
+ "fineweb_hq": 0.50957,
30
+ "dclm": 0.20766,
31
+ "cosmopedia_v2": 0.20043,
32
+ "finemath": 0.08234
33
+ },
34
+ "elapsed_seconds": 27405.331552505493
35
+ }
config.json ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "BananaMind21UnifiedForCausalLM"
4
+ ],
5
+ "model_type": "bananamind21_unified",
6
+ "auto_map": {
7
+ "AutoConfig": "configuration_bananamind21unified.BananaMind21UnifiedConfig",
8
+ "AutoModelForCausalLM": "modeling_bananamind21unified.BananaMind21UnifiedForCausalLM"
9
+ },
10
+ "vocab_size": 8192,
11
+ "head_dim": 64,
12
+ "max_position_embeddings": 4096,
13
+ "rope_theta": 100000.0,
14
+ "rms_norm_eps": 1e-06,
15
+ "embed_width": 384,
16
+ "hidden_size_a": 256,
17
+ "num_hidden_layers_a": 14,
18
+ "num_attention_heads_a": 4,
19
+ "num_key_value_heads_a": 1,
20
+ "intermediate_size_a": 704,
21
+ "hidden_size_b": 320,
22
+ "num_hidden_layers_b": 5,
23
+ "num_attention_heads_b": 5,
24
+ "num_key_value_heads_b": 1,
25
+ "intermediate_size_b": 960,
26
+ "hidden_size_c": 384,
27
+ "num_hidden_layers_c": 6,
28
+ "num_attention_heads_c": 6,
29
+ "num_key_value_heads_c": 2,
30
+ "intermediate_size_c": 1024,
31
+ "a_read": [
32
+ 5,
33
+ 9,
34
+ 12
35
+ ],
36
+ "a_land": [
37
+ 7,
38
+ 11,
39
+ 14
40
+ ],
41
+ "c_read": [
42
+ 2,
43
+ 4,
44
+ 5
45
+ ],
46
+ "c_land": [
47
+ 3,
48
+ 5,
49
+ 6
50
+ ],
51
+ "b_land": [
52
+ 1,
53
+ 3,
54
+ 5
55
+ ],
56
+ "b_read": [
57
+ 2,
58
+ 4,
59
+ 5
60
+ ],
61
+ "gate_init": 0.01,
62
+ "cut_bridges": false,
63
+ "hidden_size": 384,
64
+ "tie_word_embeddings": false,
65
+ "bos_token_id": 1,
66
+ "eos_token_id": 2,
67
+ "pad_token_id": 0,
68
+ "torch_dtype": "float32",
69
+ "_name_or_path": "Banaxi-Tech/unified-2.1-test"
70
+ }
configuration_bananamind21unified.py ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import PretrainedConfig
2
+
3
+
4
+ class BananaMind21UnifiedConfig(PretrainedConfig):
5
+ """BananaMind 2.1 Unified: three towers, a relay middle, one token out.
6
+
7
+ A and C are the outer towers and each owns an output head. B is the relay:
8
+ no head, no solo loss, and the only path between A and C.
9
+ """
10
+
11
+ model_type = "bananamind21_unified"
12
+
13
+ def __init__(
14
+ self,
15
+ vocab_size=8192,
16
+ head_dim=64,
17
+ max_position_embeddings=4096,
18
+ rope_theta=100000.0,
19
+ rms_norm_eps=1e-6,
20
+ embed_width=384,
21
+ hidden_size_a=256,
22
+ num_hidden_layers_a=14,
23
+ num_attention_heads_a=4,
24
+ num_key_value_heads_a=1,
25
+ intermediate_size_a=704,
26
+ hidden_size_b=320,
27
+ num_hidden_layers_b=5,
28
+ num_attention_heads_b=5,
29
+ num_key_value_heads_b=1,
30
+ intermediate_size_b=960,
31
+ hidden_size_c=384,
32
+ num_hidden_layers_c=6,
33
+ num_attention_heads_c=6,
34
+ num_key_value_heads_c=2,
35
+ intermediate_size_c=1024,
36
+ a_read=(5, 9, 12),
37
+ a_land=(7, 11, 14),
38
+ c_read=(2, 4, 5),
39
+ c_land=(3, 5, 6),
40
+ b_land=(1, 3, 5),
41
+ b_read=(2, 4, 5),
42
+ gate_init=0.01,
43
+ cut_bridges=False,
44
+ relay_mode=None,
45
+ use_single_tower=None,
46
+ use_cache=True,
47
+ tie_word_embeddings=False,
48
+ **kwargs,
49
+ ):
50
+ self.vocab_size = vocab_size
51
+ self.head_dim = head_dim
52
+ self.max_position_embeddings = max_position_embeddings
53
+ self.rope_theta = rope_theta
54
+ self.rms_norm_eps = rms_norm_eps
55
+ self.embed_width = embed_width
56
+
57
+ self.hidden_size_a = hidden_size_a
58
+ self.num_hidden_layers_a = num_hidden_layers_a
59
+ self.num_attention_heads_a = num_attention_heads_a
60
+ self.num_key_value_heads_a = num_key_value_heads_a
61
+ self.intermediate_size_a = intermediate_size_a
62
+
63
+ self.hidden_size_b = hidden_size_b
64
+ self.num_hidden_layers_b = num_hidden_layers_b
65
+ self.num_attention_heads_b = num_attention_heads_b
66
+ self.num_key_value_heads_b = num_key_value_heads_b
67
+ self.intermediate_size_b = intermediate_size_b
68
+
69
+ self.hidden_size_c = hidden_size_c
70
+ self.num_hidden_layers_c = num_hidden_layers_c
71
+ self.num_attention_heads_c = num_attention_heads_c
72
+ self.num_key_value_heads_c = num_key_value_heads_c
73
+ self.intermediate_size_c = intermediate_size_c
74
+
75
+ self.a_read = list(a_read)
76
+ self.a_land = list(a_land)
77
+ self.c_read = list(c_read)
78
+ self.c_land = list(c_land)
79
+ self.b_land = list(b_land)
80
+ self.b_read = list(b_read)
81
+ self.gate_init = gate_init
82
+
83
+ # Ablation controls. `relay_mode` is the general switch - see
84
+ # `RELAY_MODES` in the modeling file for the full list:
85
+ #
86
+ # full three towers, all bridges, both heads mixed (default)
87
+ # cut_bridges every bridge severed; A and C run standalone
88
+ # bypass_b B's blocks skipped, bridges still live
89
+ # ab_only tower C off; A and B run; head A alone
90
+ # cb_only tower A off; C and B run; head C alone
91
+ # a_only tower A alone, no bridges
92
+ # c_only tower C alone, no bridges
93
+ #
94
+ # `use_single_tower="a"` / `"c"` is an alias for `a_only` / `c_only`, and
95
+ # `cut_bridges=True` predates both and still selects `cut_bridges`.
96
+ # Setting two of them to different modes is an error rather than a
97
+ # silent precedence rule.
98
+ self.cut_bridges = cut_bridges
99
+ self.relay_mode = relay_mode
100
+ self.use_single_tower = use_single_tower
101
+ self.use_cache = use_cache
102
+
103
+ # `hidden_size` is what generic HF tooling looks for
104
+ self.hidden_size = hidden_size_c
105
+
106
+ # Total attention layers over all three towers. There is no single
107
+ # "number of layers" in a relay model, but the KV cache needs one flat
108
+ # index space, and generic HF tooling - `DynamicCache` above all - sizes
109
+ # itself from `num_hidden_layers`. The flat order is A, then B, then C:
110
+ #
111
+ # A -> 0 .. n_a-1 B -> n_a .. n_a+n_b-1 C -> n_a+n_b ..
112
+ #
113
+ # `BananaMind21UnifiedForCausalLM` assigns the matching `layer_idx` to
114
+ # every block, so the two must stay consistent. Derived, never read
115
+ # from a serialised config, so a stale value cannot desync the mapping.
116
+ kwargs.pop("num_hidden_layers", None)
117
+ self.num_hidden_layers = (
118
+ num_hidden_layers_a + num_hidden_layers_b + num_hidden_layers_c
119
+ )
120
+ super().__init__(tie_word_embeddings=tie_word_embeddings, **kwargs)
eval_results/a_only/__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified/results_2026-08-19T13-10-53.260045.json ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "results": {
3
+ "arc_easy": {
4
+ "name": "arc_easy",
5
+ "alias": "arc_easy",
6
+ "sample_len": 2376,
7
+ "acc,none": 0.2521043771043771,
8
+ "acc_stderr,none": 0.00891002416321825,
9
+ "acc_norm,none": 0.257996632996633,
10
+ "acc_norm_stderr,none": 0.00897797000520329
11
+ },
12
+ "piqa": {
13
+ "name": "piqa",
14
+ "alias": "piqa",
15
+ "sample_len": 1838,
16
+ "acc,none": 0.5331882480957563,
17
+ "acc_stderr,none": 0.011640096923563308,
18
+ "acc_norm,none": 0.501088139281828,
19
+ "acc_norm_stderr,none": 0.011665796539540774
20
+ },
21
+ "hellaswag": {
22
+ "name": "hellaswag",
23
+ "alias": "hellaswag",
24
+ "sample_len": 10042,
25
+ "acc,none": 0.2577175861382195,
26
+ "acc_stderr,none": 0.004364838000336011,
27
+ "acc_norm,none": 0.26110336586337385,
28
+ "acc_norm_stderr,none": 0.0043833847840387945
29
+ }
30
+ },
31
+ "group_subtasks": {},
32
+ "configs": {
33
+ "arc_easy": {
34
+ "task": "arc_easy",
35
+ "dataset_path": "allenai/ai2_arc",
36
+ "dataset_name": "ARC-Easy",
37
+ "training_split": "train",
38
+ "validation_split": "validation",
39
+ "test_split": "test",
40
+ "doc_to_text": "Question: {{question}}\nAnswer:",
41
+ "doc_to_target": "{{choices.label.index(answerKey)}}",
42
+ "unsafe_code": false,
43
+ "doc_to_choice": "{{choices.text}}",
44
+ "description": "",
45
+ "target_delimiter": " ",
46
+ "fewshot_delimiter": "\n\n",
47
+ "fewshot_config": {
48
+ "sampler": "default",
49
+ "split": null,
50
+ "process_docs": null,
51
+ "fewshot_indices": null,
52
+ "samples": null,
53
+ "doc_to_text": "Question: {{question}}\nAnswer:",
54
+ "doc_to_choice": "{{choices.text}}",
55
+ "doc_to_target": "{{choices.label.index(answerKey)}}",
56
+ "gen_prefix": null,
57
+ "fewshot_delimiter": "\n\n",
58
+ "target_delimiter": " "
59
+ },
60
+ "num_fewshot": 0,
61
+ "metric_list": [
62
+ {
63
+ "metric": "acc",
64
+ "aggregation": "mean",
65
+ "higher_is_better": true
66
+ },
67
+ {
68
+ "metric": "acc_norm",
69
+ "aggregation": "mean",
70
+ "higher_is_better": true
71
+ }
72
+ ],
73
+ "output_type": "multiple_choice",
74
+ "repeats": 1,
75
+ "should_decontaminate": true,
76
+ "doc_to_decontamination_query": "Question: {{question}}\nAnswer:",
77
+ "metadata": {
78
+ "version": 1.0,
79
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
80
+ "trust_remote_code": true,
81
+ "dtype": "float32",
82
+ "use_cache": false,
83
+ "relay_mode": "a_only",
84
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/arc/arc_easy.yaml"
85
+ }
86
+ },
87
+ "hellaswag": {
88
+ "task": "hellaswag",
89
+ "dataset_path": "Rowan/hellaswag",
90
+ "training_split": "train",
91
+ "validation_split": "validation",
92
+ "process_docs": "def process_docs(dataset: datasets.Dataset) -> datasets.Dataset:\n def _process_doc(doc):\n ctx = doc[\"ctx_a\"] + \" \" + doc[\"ctx_b\"].capitalize()\n out_doc = {\n \"query\": preprocess(doc[\"activity_label\"] + \": \" + ctx),\n \"choices\": [preprocess(ending) for ending in doc[\"endings\"]],\n \"gold\": int(doc[\"label\"]),\n }\n return out_doc\n\n return dataset.map(_process_doc)\n",
93
+ "doc_to_text": "{{query}}",
94
+ "doc_to_target": "{{label}}",
95
+ "unsafe_code": false,
96
+ "doc_to_choice": "choices",
97
+ "description": "",
98
+ "target_delimiter": " ",
99
+ "fewshot_delimiter": "\n\n",
100
+ "fewshot_config": {
101
+ "sampler": "default",
102
+ "split": null,
103
+ "process_docs": "<function process_docs at 0x7f75196e7950>",
104
+ "fewshot_indices": null,
105
+ "samples": null,
106
+ "doc_to_text": "{{query}}",
107
+ "doc_to_choice": "choices",
108
+ "doc_to_target": "{{label}}",
109
+ "gen_prefix": null,
110
+ "fewshot_delimiter": "\n\n",
111
+ "target_delimiter": " "
112
+ },
113
+ "num_fewshot": 0,
114
+ "metric_list": [
115
+ {
116
+ "metric": "acc",
117
+ "aggregation": "mean",
118
+ "higher_is_better": true
119
+ },
120
+ {
121
+ "metric": "acc_norm",
122
+ "aggregation": "mean",
123
+ "higher_is_better": true
124
+ }
125
+ ],
126
+ "output_type": "multiple_choice",
127
+ "repeats": 1,
128
+ "should_decontaminate": false,
129
+ "metadata": {
130
+ "version": 1.0,
131
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
132
+ "trust_remote_code": true,
133
+ "dtype": "float32",
134
+ "use_cache": false,
135
+ "relay_mode": "a_only",
136
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/hellaswag/hellaswag.yaml"
137
+ }
138
+ },
139
+ "piqa": {
140
+ "task": "piqa",
141
+ "dataset_path": "baber/piqa",
142
+ "training_split": "train",
143
+ "validation_split": "validation",
144
+ "doc_to_text": "Question: {{goal}}\nAnswer:",
145
+ "doc_to_target": "label",
146
+ "unsafe_code": false,
147
+ "doc_to_choice": "{{[sol1, sol2]}}",
148
+ "description": "",
149
+ "target_delimiter": " ",
150
+ "fewshot_delimiter": "\n\n",
151
+ "fewshot_config": {
152
+ "sampler": "default",
153
+ "split": null,
154
+ "process_docs": null,
155
+ "fewshot_indices": null,
156
+ "samples": null,
157
+ "doc_to_text": "Question: {{goal}}\nAnswer:",
158
+ "doc_to_choice": "{{[sol1, sol2]}}",
159
+ "doc_to_target": "label",
160
+ "gen_prefix": null,
161
+ "fewshot_delimiter": "\n\n",
162
+ "target_delimiter": " "
163
+ },
164
+ "num_fewshot": 0,
165
+ "metric_list": [
166
+ {
167
+ "metric": "acc",
168
+ "aggregation": "mean",
169
+ "higher_is_better": true
170
+ },
171
+ {
172
+ "metric": "acc_norm",
173
+ "aggregation": "mean",
174
+ "higher_is_better": true
175
+ }
176
+ ],
177
+ "output_type": "multiple_choice",
178
+ "repeats": 1,
179
+ "should_decontaminate": true,
180
+ "doc_to_decontamination_query": "goal",
181
+ "metadata": {
182
+ "version": 1.0,
183
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
184
+ "trust_remote_code": true,
185
+ "dtype": "float32",
186
+ "use_cache": false,
187
+ "relay_mode": "a_only",
188
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/piqa/piqa.yaml"
189
+ }
190
+ }
191
+ },
192
+ "versions": {
193
+ "arc_easy": 1.0,
194
+ "hellaswag": 1.0,
195
+ "piqa": 1.0
196
+ },
197
+ "n-shot": {
198
+ "arc_easy": 0,
199
+ "hellaswag": 0,
200
+ "piqa": 0
201
+ },
202
+ "higher_is_better": {
203
+ "arc_easy": {
204
+ "acc": true,
205
+ "acc_norm": true
206
+ },
207
+ "hellaswag": {
208
+ "acc": true,
209
+ "acc_norm": true
210
+ },
211
+ "piqa": {
212
+ "acc": true,
213
+ "acc_norm": true
214
+ }
215
+ },
216
+ "n-samples": {
217
+ "arc_easy": {
218
+ "original": 2376,
219
+ "effective": 2376
220
+ },
221
+ "piqa": {
222
+ "original": 1838,
223
+ "effective": 1838
224
+ },
225
+ "hellaswag": {
226
+ "original": 10042,
227
+ "effective": 10042
228
+ }
229
+ },
230
+ "config": {
231
+ "model": "hf",
232
+ "model_args": {
233
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
234
+ "trust_remote_code": true,
235
+ "dtype": "float32",
236
+ "use_cache": false,
237
+ "relay_mode": "a_only"
238
+ },
239
+ "model_num_parameters": 34999041,
240
+ "model_dtype": "torch.float32",
241
+ "model_revision": "main",
242
+ "model_sha": "",
243
+ "batch_size": "auto",
244
+ "batch_sizes": [
245
+ 64
246
+ ],
247
+ "device": "cuda:0",
248
+ "use_cache": null,
249
+ "limit": null,
250
+ "bootstrap_iters": 100000,
251
+ "gen_kwargs": {},
252
+ "random_seed": 0,
253
+ "numpy_seed": 1234,
254
+ "torch_seed": 1234,
255
+ "fewshot_seed": 1234
256
+ },
257
+ "git_hash": null,
258
+ "date": 1787137810.9721441,
259
+ "pretty_env_info": "PyTorch version: 2.11.0+cu130\nIs debug build: False\nCUDA used to build PyTorch: 13.0\nROCM used to build PyTorch: N/A\n\nOS: Arch Linux (x86_64)\nGCC version: (GCC) 16.2.1 20260810\nClang version: 22.1.8\nCMake version: version 4.4.2\nLibc version: glibc-2.44\n\nPython version: 3.14.7 (main, Aug 10 2026, 07:46:56) [GCC 16.1.1 20260728] (64-bit runtime)\nPython platform: Linux-7.1.8-arch1-3-x86_64-with-glibc2.44\nIs CUDA available: True\nCUDA runtime version: 13.3.73\nCUDA_MODULE_LOADING set to: \nGPU models and configuration: GPU 0: NVIDIA GeForce RTX 5070 Ti\nNvidia driver version: Could not collect\ncuDNN version: Probably one of the following:\n/usr/lib/libcudnn.so.9.25.0\n/usr/lib/libcudnn_adv.so.9.25.0\n/usr/lib/libcudnn_cnn.so.9.25.0\n/usr/lib/libcudnn_engines_precompiled.so.9.25.0\n/usr/lib/libcudnn_engines_runtime_compiled.so.9.25.0\n/usr/lib/libcudnn_engines_tensor_ir.so.9.25.0\n/usr/lib/libcudnn_ext.so.9.25.0\n/usr/lib/libcudnn_graph.so.9.25.0\n/usr/lib/libcudnn_heuristic.so.9.25.0\n/usr/lib/libcudnn_ops.so.9.25.0\nIs XPU available: False\nHIP runtime version: N/A\nMIOpen runtime version: N/A\nIs XNNPACK available: True\nCaching allocator config: N/A\n\nCPU:\nArchitecture: x86_64\nCPU op-mode(s): 32-bit, 64-bit\nAddress sizes: 39 bits physical, 48 bits virtual\nByte Order: Little Endian\nCPU(s): 24\nOn-line CPU(s) list: 0-23\nVendor ID: GenuineIntel\nModel name: 12th Gen Intel(R) Core(TM) i9-12900KF\nCPU family: 6\nModel: 151\nThread(s) per core: 2\nCore(s) per socket: 16\nSocket(s): 1\nStepping: 2\nMicrocode version: 0x3e\nCPU(s) scaling MHz: 18%\nCPU max MHz: 5200.0000\nCPU min MHz: 800.0000\nBogoMIPS: 6374.40\nFlags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect user_shstk avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi vnmi umip pku ospke waitpkg gfni vaes vpclmulqdq rdpid movdiri movdir64b fsrm md_clear serialize arch_lbr ibt flush_l1d arch_capabilities\nVirtualization: VT-x\nL1d cache: 640 KiB (16 instances)\nL1i cache: 768 KiB (16 instances)\nL2 cache: 14 MiB (10 instances)\nL3 cache: 30 MiB (1 instance)\nNUMA node(s): 1\nNUMA node0 CPU(s): 0-23\nVulnerability Gather data sampling: Not affected\nVulnerability Ghostwrite: Not affected\nVulnerability Indirect target selection: Not affected\nVulnerability Itlb multihit: Not affected\nVulnerability L1tf: Not affected\nVulnerability Mds: Not affected\nVulnerability Meltdown: Not affected\nVulnerability Mmio stale data: Not affected\nVulnerability Old microcode: Not affected\nVulnerability Reg file data sampling: Mitigation; Clear Register File\nVulnerability Retbleed: Not affected\nVulnerability Spec rstack overflow: Not affected\nVulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl\nVulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization\nVulnerability Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; PBRSB-eIBRS SW sequence; BHI BHI_DIS_S\nVulnerability Srbds: Not affected\nVulnerability Tsa: Not affected\nVulnerability Tsx async abort: Not affected\nVulnerability Vmscape: Mitigation; IBPB before exit to userspace\n\nVersions of relevant libraries:\n[pip3] numpy==2.5.2\n[pip3] nvidia-cublas==13.1.0.3\n[pip3] nvidia-cuda-cupti==13.0.85\n[pip3] nvidia-cuda-nvrtc==13.0.88\n[pip3] nvidia-cuda-runtime==13.0.96\n[pip3] nvidia-cudnn-cu13==9.19.0.56\n[pip3] nvidia-cufft==12.0.0.61\n[pip3] nvidia-curand==10.4.0.35\n[pip3] nvidia-cusolver==12.0.4.66\n[pip3] nvidia-cusparse==12.6.3.3\n[pip3] nvidia-cusparselt-cu13==0.8.0\n[pip3] nvidia-nccl-cu13==2.28.9\n[pip3] nvidia-nvjitlink==13.0.88\n[pip3] nvidia-nvtx==13.0.85\n[pip3] segmentation_models_pytorch==0.5.0\n[pip3] torch==2.11.0\n[pip3] torchao==0.17.0\n[pip3] torchaudio==2.11.0\n[pip3] torchcodec==0.16.0\n[pip3] torchvision==0.26.0\n[pip3] triton==3.6.0\n[conda] Could not collect",
260
+ "transformers_version": "5.7.0",
261
+ "lm_eval_version": "0.4.12",
262
+ "upper_git_hash": null,
263
+ "tokenizer_pad_token": [
264
+ "<|pad|>",
265
+ "0"
266
+ ],
267
+ "tokenizer_eos_token": [
268
+ "<|eos|>",
269
+ "2"
270
+ ],
271
+ "tokenizer_bos_token": [
272
+ "<|bos|>",
273
+ "1"
274
+ ],
275
+ "eot_token_id": 2,
276
+ "max_length": 4096,
277
+ "task_hashes": {},
278
+ "model_source": "hf",
279
+ "model_name": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
280
+ "model_name_sanitized": "__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified",
281
+ "system_instruction": null,
282
+ "system_instruction_sha": null,
283
+ "fewshot_as_multiturn": null,
284
+ "chat_template": null,
285
+ "chat_template_sha": null,
286
+ "total_evaluation_time_seconds": "44.84569375999854"
287
+ }
eval_results/ab_only/__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified/results_2026-08-19T13-08-19.026128.json ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "results": {
3
+ "arc_easy": {
4
+ "name": "arc_easy",
5
+ "alias": "arc_easy",
6
+ "sample_len": 2376,
7
+ "acc,none": 0.26304713804713803,
8
+ "acc_stderr,none": 0.009034514898865944,
9
+ "acc_norm,none": 0.2756734006734007,
10
+ "acc_norm_stderr,none": 0.009169229476542745
11
+ },
12
+ "piqa": {
13
+ "name": "piqa",
14
+ "alias": "piqa",
15
+ "sample_len": 1838,
16
+ "acc,none": 0.5397170837867247,
17
+ "acc_stderr,none": 0.011628961491718543,
18
+ "acc_norm,none": 0.528835690968444,
19
+ "acc_norm_stderr,none": 0.011646407809944788
20
+ },
21
+ "hellaswag": {
22
+ "name": "hellaswag",
23
+ "alias": "hellaswag",
24
+ "sample_len": 10042,
25
+ "acc,none": 0.25721967735510853,
26
+ "acc_stderr,none": 0.004362081806560604,
27
+ "acc_norm,none": 0.25851424019119695,
28
+ "acc_norm_stderr,none": 0.004369232540126326
29
+ }
30
+ },
31
+ "group_subtasks": {},
32
+ "configs": {
33
+ "arc_easy": {
34
+ "task": "arc_easy",
35
+ "dataset_path": "allenai/ai2_arc",
36
+ "dataset_name": "ARC-Easy",
37
+ "training_split": "train",
38
+ "validation_split": "validation",
39
+ "test_split": "test",
40
+ "doc_to_text": "Question: {{question}}\nAnswer:",
41
+ "doc_to_target": "{{choices.label.index(answerKey)}}",
42
+ "unsafe_code": false,
43
+ "doc_to_choice": "{{choices.text}}",
44
+ "description": "",
45
+ "target_delimiter": " ",
46
+ "fewshot_delimiter": "\n\n",
47
+ "fewshot_config": {
48
+ "sampler": "default",
49
+ "split": null,
50
+ "process_docs": null,
51
+ "fewshot_indices": null,
52
+ "samples": null,
53
+ "doc_to_text": "Question: {{question}}\nAnswer:",
54
+ "doc_to_choice": "{{choices.text}}",
55
+ "doc_to_target": "{{choices.label.index(answerKey)}}",
56
+ "gen_prefix": null,
57
+ "fewshot_delimiter": "\n\n",
58
+ "target_delimiter": " "
59
+ },
60
+ "num_fewshot": 0,
61
+ "metric_list": [
62
+ {
63
+ "metric": "acc",
64
+ "aggregation": "mean",
65
+ "higher_is_better": true
66
+ },
67
+ {
68
+ "metric": "acc_norm",
69
+ "aggregation": "mean",
70
+ "higher_is_better": true
71
+ }
72
+ ],
73
+ "output_type": "multiple_choice",
74
+ "repeats": 1,
75
+ "should_decontaminate": true,
76
+ "doc_to_decontamination_query": "Question: {{question}}\nAnswer:",
77
+ "metadata": {
78
+ "version": 1.0,
79
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
80
+ "trust_remote_code": true,
81
+ "dtype": "float32",
82
+ "use_cache": false,
83
+ "relay_mode": "ab_only",
84
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/arc/arc_easy.yaml"
85
+ }
86
+ },
87
+ "hellaswag": {
88
+ "task": "hellaswag",
89
+ "dataset_path": "Rowan/hellaswag",
90
+ "training_split": "train",
91
+ "validation_split": "validation",
92
+ "process_docs": "def process_docs(dataset: datasets.Dataset) -> datasets.Dataset:\n def _process_doc(doc):\n ctx = doc[\"ctx_a\"] + \" \" + doc[\"ctx_b\"].capitalize()\n out_doc = {\n \"query\": preprocess(doc[\"activity_label\"] + \": \" + ctx),\n \"choices\": [preprocess(ending) for ending in doc[\"endings\"]],\n \"gold\": int(doc[\"label\"]),\n }\n return out_doc\n\n return dataset.map(_process_doc)\n",
93
+ "doc_to_text": "{{query}}",
94
+ "doc_to_target": "{{label}}",
95
+ "unsafe_code": false,
96
+ "doc_to_choice": "choices",
97
+ "description": "",
98
+ "target_delimiter": " ",
99
+ "fewshot_delimiter": "\n\n",
100
+ "fewshot_config": {
101
+ "sampler": "default",
102
+ "split": null,
103
+ "process_docs": "<function process_docs at 0x7f4831777950>",
104
+ "fewshot_indices": null,
105
+ "samples": null,
106
+ "doc_to_text": "{{query}}",
107
+ "doc_to_choice": "choices",
108
+ "doc_to_target": "{{label}}",
109
+ "gen_prefix": null,
110
+ "fewshot_delimiter": "\n\n",
111
+ "target_delimiter": " "
112
+ },
113
+ "num_fewshot": 0,
114
+ "metric_list": [
115
+ {
116
+ "metric": "acc",
117
+ "aggregation": "mean",
118
+ "higher_is_better": true
119
+ },
120
+ {
121
+ "metric": "acc_norm",
122
+ "aggregation": "mean",
123
+ "higher_is_better": true
124
+ }
125
+ ],
126
+ "output_type": "multiple_choice",
127
+ "repeats": 1,
128
+ "should_decontaminate": false,
129
+ "metadata": {
130
+ "version": 1.0,
131
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
132
+ "trust_remote_code": true,
133
+ "dtype": "float32",
134
+ "use_cache": false,
135
+ "relay_mode": "ab_only",
136
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/hellaswag/hellaswag.yaml"
137
+ }
138
+ },
139
+ "piqa": {
140
+ "task": "piqa",
141
+ "dataset_path": "baber/piqa",
142
+ "training_split": "train",
143
+ "validation_split": "validation",
144
+ "doc_to_text": "Question: {{goal}}\nAnswer:",
145
+ "doc_to_target": "label",
146
+ "unsafe_code": false,
147
+ "doc_to_choice": "{{[sol1, sol2]}}",
148
+ "description": "",
149
+ "target_delimiter": " ",
150
+ "fewshot_delimiter": "\n\n",
151
+ "fewshot_config": {
152
+ "sampler": "default",
153
+ "split": null,
154
+ "process_docs": null,
155
+ "fewshot_indices": null,
156
+ "samples": null,
157
+ "doc_to_text": "Question: {{goal}}\nAnswer:",
158
+ "doc_to_choice": "{{[sol1, sol2]}}",
159
+ "doc_to_target": "label",
160
+ "gen_prefix": null,
161
+ "fewshot_delimiter": "\n\n",
162
+ "target_delimiter": " "
163
+ },
164
+ "num_fewshot": 0,
165
+ "metric_list": [
166
+ {
167
+ "metric": "acc",
168
+ "aggregation": "mean",
169
+ "higher_is_better": true
170
+ },
171
+ {
172
+ "metric": "acc_norm",
173
+ "aggregation": "mean",
174
+ "higher_is_better": true
175
+ }
176
+ ],
177
+ "output_type": "multiple_choice",
178
+ "repeats": 1,
179
+ "should_decontaminate": true,
180
+ "doc_to_decontamination_query": "goal",
181
+ "metadata": {
182
+ "version": 1.0,
183
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
184
+ "trust_remote_code": true,
185
+ "dtype": "float32",
186
+ "use_cache": false,
187
+ "relay_mode": "ab_only",
188
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/piqa/piqa.yaml"
189
+ }
190
+ }
191
+ },
192
+ "versions": {
193
+ "arc_easy": 1.0,
194
+ "hellaswag": 1.0,
195
+ "piqa": 1.0
196
+ },
197
+ "n-shot": {
198
+ "arc_easy": 0,
199
+ "hellaswag": 0,
200
+ "piqa": 0
201
+ },
202
+ "higher_is_better": {
203
+ "arc_easy": {
204
+ "acc": true,
205
+ "acc_norm": true
206
+ },
207
+ "hellaswag": {
208
+ "acc": true,
209
+ "acc_norm": true
210
+ },
211
+ "piqa": {
212
+ "acc": true,
213
+ "acc_norm": true
214
+ }
215
+ },
216
+ "n-samples": {
217
+ "arc_easy": {
218
+ "original": 2376,
219
+ "effective": 2376
220
+ },
221
+ "piqa": {
222
+ "original": 1838,
223
+ "effective": 1838
224
+ },
225
+ "hellaswag": {
226
+ "original": 10042,
227
+ "effective": 10042
228
+ }
229
+ },
230
+ "config": {
231
+ "model": "hf",
232
+ "model_args": {
233
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
234
+ "trust_remote_code": true,
235
+ "dtype": "float32",
236
+ "use_cache": false,
237
+ "relay_mode": "ab_only"
238
+ },
239
+ "model_num_parameters": 34999041,
240
+ "model_dtype": "torch.float32",
241
+ "model_revision": "main",
242
+ "model_sha": "",
243
+ "batch_size": "auto",
244
+ "batch_sizes": [
245
+ 64
246
+ ],
247
+ "device": "cuda:0",
248
+ "use_cache": null,
249
+ "limit": null,
250
+ "bootstrap_iters": 100000,
251
+ "gen_kwargs": {},
252
+ "random_seed": 0,
253
+ "numpy_seed": 1234,
254
+ "torch_seed": 1234,
255
+ "fewshot_seed": 1234
256
+ },
257
+ "git_hash": null,
258
+ "date": 1787137649.6364806,
259
+ "pretty_env_info": "PyTorch version: 2.11.0+cu130\nIs debug build: False\nCUDA used to build PyTorch: 13.0\nROCM used to build PyTorch: N/A\n\nOS: Arch Linux (x86_64)\nGCC version: (GCC) 16.2.1 20260810\nClang version: 22.1.8\nCMake version: version 4.4.2\nLibc version: glibc-2.44\n\nPython version: 3.14.7 (main, Aug 10 2026, 07:46:56) [GCC 16.1.1 20260728] (64-bit runtime)\nPython platform: Linux-7.1.8-arch1-3-x86_64-with-glibc2.44\nIs CUDA available: True\nCUDA runtime version: 13.3.73\nCUDA_MODULE_LOADING set to: \nGPU models and configuration: GPU 0: NVIDIA GeForce RTX 5070 Ti\nNvidia driver version: Could not collect\ncuDNN version: Probably one of the following:\n/usr/lib/libcudnn.so.9.25.0\n/usr/lib/libcudnn_adv.so.9.25.0\n/usr/lib/libcudnn_cnn.so.9.25.0\n/usr/lib/libcudnn_engines_precompiled.so.9.25.0\n/usr/lib/libcudnn_engines_runtime_compiled.so.9.25.0\n/usr/lib/libcudnn_engines_tensor_ir.so.9.25.0\n/usr/lib/libcudnn_ext.so.9.25.0\n/usr/lib/libcudnn_graph.so.9.25.0\n/usr/lib/libcudnn_heuristic.so.9.25.0\n/usr/lib/libcudnn_ops.so.9.25.0\nIs XPU available: False\nHIP runtime version: N/A\nMIOpen runtime version: N/A\nIs XNNPACK available: True\nCaching allocator config: N/A\n\nCPU:\nArchitecture: x86_64\nCPU op-mode(s): 32-bit, 64-bit\nAddress sizes: 39 bits physical, 48 bits virtual\nByte Order: Little Endian\nCPU(s): 24\nOn-line CPU(s) list: 0-23\nVendor ID: GenuineIntel\nModel name: 12th Gen Intel(R) Core(TM) i9-12900KF\nCPU family: 6\nModel: 151\nThread(s) per core: 2\nCore(s) per socket: 16\nSocket(s): 1\nStepping: 2\nMicrocode version: 0x3e\nCPU(s) scaling MHz: 22%\nCPU max MHz: 5200.0000\nCPU min MHz: 800.0000\nBogoMIPS: 6374.40\nFlags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect user_shstk avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi vnmi umip pku ospke waitpkg gfni vaes vpclmulqdq rdpid movdiri movdir64b fsrm md_clear serialize arch_lbr ibt flush_l1d arch_capabilities\nVirtualization: VT-x\nL1d cache: 640 KiB (16 instances)\nL1i cache: 768 KiB (16 instances)\nL2 cache: 14 MiB (10 instances)\nL3 cache: 30 MiB (1 instance)\nNUMA node(s): 1\nNUMA node0 CPU(s): 0-23\nVulnerability Gather data sampling: Not affected\nVulnerability Ghostwrite: Not affected\nVulnerability Indirect target selection: Not affected\nVulnerability Itlb multihit: Not affected\nVulnerability L1tf: Not affected\nVulnerability Mds: Not affected\nVulnerability Meltdown: Not affected\nVulnerability Mmio stale data: Not affected\nVulnerability Old microcode: Not affected\nVulnerability Reg file data sampling: Mitigation; Clear Register File\nVulnerability Retbleed: Not affected\nVulnerability Spec rstack overflow: Not affected\nVulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl\nVulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization\nVulnerability Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; PBRSB-eIBRS SW sequence; BHI BHI_DIS_S\nVulnerability Srbds: Not affected\nVulnerability Tsa: Not affected\nVulnerability Tsx async abort: Not affected\nVulnerability Vmscape: Mitigation; IBPB before exit to userspace\n\nVersions of relevant libraries:\n[pip3] numpy==2.5.2\n[pip3] nvidia-cublas==13.1.0.3\n[pip3] nvidia-cuda-cupti==13.0.85\n[pip3] nvidia-cuda-nvrtc==13.0.88\n[pip3] nvidia-cuda-runtime==13.0.96\n[pip3] nvidia-cudnn-cu13==9.19.0.56\n[pip3] nvidia-cufft==12.0.0.61\n[pip3] nvidia-curand==10.4.0.35\n[pip3] nvidia-cusolver==12.0.4.66\n[pip3] nvidia-cusparse==12.6.3.3\n[pip3] nvidia-cusparselt-cu13==0.8.0\n[pip3] nvidia-nccl-cu13==2.28.9\n[pip3] nvidia-nvjitlink==13.0.88\n[pip3] nvidia-nvtx==13.0.85\n[pip3] segmentation_models_pytorch==0.5.0\n[pip3] torch==2.11.0\n[pip3] torchao==0.17.0\n[pip3] torchaudio==2.11.0\n[pip3] torchcodec==0.16.0\n[pip3] torchvision==0.26.0\n[pip3] triton==3.6.0\n[conda] Could not collect",
260
+ "transformers_version": "5.7.0",
261
+ "lm_eval_version": "0.4.12",
262
+ "upper_git_hash": null,
263
+ "tokenizer_pad_token": [
264
+ "<|pad|>",
265
+ "0"
266
+ ],
267
+ "tokenizer_eos_token": [
268
+ "<|eos|>",
269
+ "2"
270
+ ],
271
+ "tokenizer_bos_token": [
272
+ "<|bos|>",
273
+ "1"
274
+ ],
275
+ "eot_token_id": 2,
276
+ "max_length": 4096,
277
+ "task_hashes": {},
278
+ "model_source": "hf",
279
+ "model_name": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
280
+ "model_name_sanitized": "__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified",
281
+ "system_instruction": null,
282
+ "system_instruction_sha": null,
283
+ "fewshot_as_multiturn": null,
284
+ "chat_template": null,
285
+ "chat_template_sha": null,
286
+ "total_evaluation_time_seconds": "51.955665409972426"
287
+ }
eval_results/base_bench_1.1/a_only/predictions.md ADDED
The diff for this file is too large to render. See raw diff
 
eval_results/base_bench_1.1/a_only/report.json ADDED
The diff for this file is too large to render. See raw diff
 
eval_results/base_bench_1.1/a_only/run_config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "benchmark": "BananaMind Base Bench 1.1",
3
+ "model": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
4
+ "tokenizer": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
5
+ "model_revision": "main",
6
+ "dataset_id": "BananaMind/BananaMind-Base-Bench-1.1",
7
+ "dataset_revision": "main",
8
+ "dataset_sha256": "2f563bb46df778ca494fa20f994a8d3045d4c51fbbffeee433764e2813abea21",
9
+ "score_mode": "mean_logprob",
10
+ "add_bos": false,
11
+ "max_context": null
12
+ }
eval_results/base_bench_1.1/ab_only/predictions.md ADDED
The diff for this file is too large to render. See raw diff
 
eval_results/base_bench_1.1/ab_only/report.json ADDED
The diff for this file is too large to render. See raw diff
 
eval_results/base_bench_1.1/ab_only/run_config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "benchmark": "BananaMind Base Bench 1.1",
3
+ "model": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
4
+ "tokenizer": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
5
+ "model_revision": "main",
6
+ "dataset_id": "BananaMind/BananaMind-Base-Bench-1.1",
7
+ "dataset_revision": "main",
8
+ "dataset_sha256": "2f563bb46df778ca494fa20f994a8d3045d4c51fbbffeee433764e2813abea21",
9
+ "score_mode": "mean_logprob",
10
+ "add_bos": false,
11
+ "max_context": null
12
+ }
eval_results/base_bench_1.1/bypass_b/predictions.md ADDED
The diff for this file is too large to render. See raw diff
 
eval_results/base_bench_1.1/bypass_b/report.json ADDED
The diff for this file is too large to render. See raw diff
 
eval_results/base_bench_1.1/bypass_b/run_config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "benchmark": "BananaMind Base Bench 1.1",
3
+ "model": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
4
+ "tokenizer": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
5
+ "model_revision": "main",
6
+ "dataset_id": "BananaMind/BananaMind-Base-Bench-1.1",
7
+ "dataset_revision": "main",
8
+ "dataset_sha256": "2f563bb46df778ca494fa20f994a8d3045d4c51fbbffeee433764e2813abea21",
9
+ "score_mode": "mean_logprob",
10
+ "add_bos": false,
11
+ "max_context": null
12
+ }
eval_results/base_bench_1.1/c_only/predictions.md ADDED
The diff for this file is too large to render. See raw diff
 
eval_results/base_bench_1.1/c_only/report.json ADDED
The diff for this file is too large to render. See raw diff
 
eval_results/base_bench_1.1/c_only/run_config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "benchmark": "BananaMind Base Bench 1.1",
3
+ "model": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
4
+ "tokenizer": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
5
+ "model_revision": "main",
6
+ "dataset_id": "BananaMind/BananaMind-Base-Bench-1.1",
7
+ "dataset_revision": "main",
8
+ "dataset_sha256": "2f563bb46df778ca494fa20f994a8d3045d4c51fbbffeee433764e2813abea21",
9
+ "score_mode": "mean_logprob",
10
+ "add_bos": false,
11
+ "max_context": null
12
+ }
eval_results/base_bench_1.1/cb_only/predictions.md ADDED
The diff for this file is too large to render. See raw diff
 
eval_results/base_bench_1.1/cb_only/report.json ADDED
The diff for this file is too large to render. See raw diff
 
eval_results/base_bench_1.1/cb_only/run_config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "benchmark": "BananaMind Base Bench 1.1",
3
+ "model": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
4
+ "tokenizer": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
5
+ "model_revision": "main",
6
+ "dataset_id": "BananaMind/BananaMind-Base-Bench-1.1",
7
+ "dataset_revision": "main",
8
+ "dataset_sha256": "2f563bb46df778ca494fa20f994a8d3045d4c51fbbffeee433764e2813abea21",
9
+ "score_mode": "mean_logprob",
10
+ "add_bos": false,
11
+ "max_context": null
12
+ }
eval_results/base_bench_1.1/cut_bridges/predictions.md ADDED
The diff for this file is too large to render. See raw diff
 
eval_results/base_bench_1.1/cut_bridges/report.json ADDED
The diff for this file is too large to render. See raw diff
 
eval_results/base_bench_1.1/cut_bridges/run_config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "benchmark": "BananaMind Base Bench 1.1",
3
+ "model": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
4
+ "tokenizer": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
5
+ "model_revision": "main",
6
+ "dataset_id": "BananaMind/BananaMind-Base-Bench-1.1",
7
+ "dataset_revision": "main",
8
+ "dataset_sha256": "2f563bb46df778ca494fa20f994a8d3045d4c51fbbffeee433764e2813abea21",
9
+ "score_mode": "mean_logprob",
10
+ "add_bos": false,
11
+ "max_context": null
12
+ }
eval_results/base_bench_1.1/full/predictions.md ADDED
The diff for this file is too large to render. See raw diff
 
eval_results/base_bench_1.1/full/report.json ADDED
The diff for this file is too large to render. See raw diff
 
eval_results/base_bench_1.1/full/run_config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "benchmark": "BananaMind Base Bench 1.1",
3
+ "model": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
4
+ "tokenizer": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
5
+ "model_revision": "main",
6
+ "dataset_id": "BananaMind/BananaMind-Base-Bench-1.1",
7
+ "dataset_revision": "main",
8
+ "dataset_sha256": "2f563bb46df778ca494fa20f994a8d3045d4c51fbbffeee433764e2813abea21",
9
+ "score_mode": "mean_logprob",
10
+ "add_bos": false,
11
+ "max_context": null
12
+ }
eval_results/bypass_b/__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified/results_2026-08-19T13-07-25.864618.json ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "results": {
3
+ "arc_easy": {
4
+ "name": "arc_easy",
5
+ "alias": "arc_easy",
6
+ "sample_len": 2376,
7
+ "acc,none": 0.3345959595959596,
8
+ "acc_stderr,none": 0.009682137724327718,
9
+ "acc_norm,none": 0.3367003367003367,
10
+ "acc_norm_stderr,none": 0.009697166595752359
11
+ },
12
+ "piqa": {
13
+ "name": "piqa",
14
+ "alias": "piqa",
15
+ "sample_len": 1838,
16
+ "acc,none": 0.5707290533188248,
17
+ "acc_stderr,none": 0.01154851547125808,
18
+ "acc_norm,none": 0.55930359085963,
19
+ "acc_norm_stderr,none": 0.011583478090656981
20
+ },
21
+ "hellaswag": {
22
+ "name": "hellaswag",
23
+ "alias": "hellaswag",
24
+ "sample_len": 10042,
25
+ "acc,none": 0.276638119896435,
26
+ "acc_stderr,none": 0.004464217420693715,
27
+ "acc_norm,none": 0.2922724556861183,
28
+ "acc_norm_stderr,none": 0.004538773493746909
29
+ }
30
+ },
31
+ "group_subtasks": {},
32
+ "configs": {
33
+ "arc_easy": {
34
+ "task": "arc_easy",
35
+ "dataset_path": "allenai/ai2_arc",
36
+ "dataset_name": "ARC-Easy",
37
+ "training_split": "train",
38
+ "validation_split": "validation",
39
+ "test_split": "test",
40
+ "doc_to_text": "Question: {{question}}\nAnswer:",
41
+ "doc_to_target": "{{choices.label.index(answerKey)}}",
42
+ "unsafe_code": false,
43
+ "doc_to_choice": "{{choices.text}}",
44
+ "description": "",
45
+ "target_delimiter": " ",
46
+ "fewshot_delimiter": "\n\n",
47
+ "fewshot_config": {
48
+ "sampler": "default",
49
+ "split": null,
50
+ "process_docs": null,
51
+ "fewshot_indices": null,
52
+ "samples": null,
53
+ "doc_to_text": "Question: {{question}}\nAnswer:",
54
+ "doc_to_choice": "{{choices.text}}",
55
+ "doc_to_target": "{{choices.label.index(answerKey)}}",
56
+ "gen_prefix": null,
57
+ "fewshot_delimiter": "\n\n",
58
+ "target_delimiter": " "
59
+ },
60
+ "num_fewshot": 0,
61
+ "metric_list": [
62
+ {
63
+ "metric": "acc",
64
+ "aggregation": "mean",
65
+ "higher_is_better": true
66
+ },
67
+ {
68
+ "metric": "acc_norm",
69
+ "aggregation": "mean",
70
+ "higher_is_better": true
71
+ }
72
+ ],
73
+ "output_type": "multiple_choice",
74
+ "repeats": 1,
75
+ "should_decontaminate": true,
76
+ "doc_to_decontamination_query": "Question: {{question}}\nAnswer:",
77
+ "metadata": {
78
+ "version": 1.0,
79
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
80
+ "trust_remote_code": true,
81
+ "dtype": "float32",
82
+ "use_cache": false,
83
+ "relay_mode": "bypass_b",
84
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/arc/arc_easy.yaml"
85
+ }
86
+ },
87
+ "hellaswag": {
88
+ "task": "hellaswag",
89
+ "dataset_path": "Rowan/hellaswag",
90
+ "training_split": "train",
91
+ "validation_split": "validation",
92
+ "process_docs": "def process_docs(dataset: datasets.Dataset) -> datasets.Dataset:\n def _process_doc(doc):\n ctx = doc[\"ctx_a\"] + \" \" + doc[\"ctx_b\"].capitalize()\n out_doc = {\n \"query\": preprocess(doc[\"activity_label\"] + \": \" + ctx),\n \"choices\": [preprocess(ending) for ending in doc[\"endings\"]],\n \"gold\": int(doc[\"label\"]),\n }\n return out_doc\n\n return dataset.map(_process_doc)\n",
93
+ "doc_to_text": "{{query}}",
94
+ "doc_to_target": "{{label}}",
95
+ "unsafe_code": false,
96
+ "doc_to_choice": "choices",
97
+ "description": "",
98
+ "target_delimiter": " ",
99
+ "fewshot_delimiter": "\n\n",
100
+ "fewshot_config": {
101
+ "sampler": "default",
102
+ "split": null,
103
+ "process_docs": "<function process_docs at 0x7fefeb1f7950>",
104
+ "fewshot_indices": null,
105
+ "samples": null,
106
+ "doc_to_text": "{{query}}",
107
+ "doc_to_choice": "choices",
108
+ "doc_to_target": "{{label}}",
109
+ "gen_prefix": null,
110
+ "fewshot_delimiter": "\n\n",
111
+ "target_delimiter": " "
112
+ },
113
+ "num_fewshot": 0,
114
+ "metric_list": [
115
+ {
116
+ "metric": "acc",
117
+ "aggregation": "mean",
118
+ "higher_is_better": true
119
+ },
120
+ {
121
+ "metric": "acc_norm",
122
+ "aggregation": "mean",
123
+ "higher_is_better": true
124
+ }
125
+ ],
126
+ "output_type": "multiple_choice",
127
+ "repeats": 1,
128
+ "should_decontaminate": false,
129
+ "metadata": {
130
+ "version": 1.0,
131
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
132
+ "trust_remote_code": true,
133
+ "dtype": "float32",
134
+ "use_cache": false,
135
+ "relay_mode": "bypass_b",
136
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/hellaswag/hellaswag.yaml"
137
+ }
138
+ },
139
+ "piqa": {
140
+ "task": "piqa",
141
+ "dataset_path": "baber/piqa",
142
+ "training_split": "train",
143
+ "validation_split": "validation",
144
+ "doc_to_text": "Question: {{goal}}\nAnswer:",
145
+ "doc_to_target": "label",
146
+ "unsafe_code": false,
147
+ "doc_to_choice": "{{[sol1, sol2]}}",
148
+ "description": "",
149
+ "target_delimiter": " ",
150
+ "fewshot_delimiter": "\n\n",
151
+ "fewshot_config": {
152
+ "sampler": "default",
153
+ "split": null,
154
+ "process_docs": null,
155
+ "fewshot_indices": null,
156
+ "samples": null,
157
+ "doc_to_text": "Question: {{goal}}\nAnswer:",
158
+ "doc_to_choice": "{{[sol1, sol2]}}",
159
+ "doc_to_target": "label",
160
+ "gen_prefix": null,
161
+ "fewshot_delimiter": "\n\n",
162
+ "target_delimiter": " "
163
+ },
164
+ "num_fewshot": 0,
165
+ "metric_list": [
166
+ {
167
+ "metric": "acc",
168
+ "aggregation": "mean",
169
+ "higher_is_better": true
170
+ },
171
+ {
172
+ "metric": "acc_norm",
173
+ "aggregation": "mean",
174
+ "higher_is_better": true
175
+ }
176
+ ],
177
+ "output_type": "multiple_choice",
178
+ "repeats": 1,
179
+ "should_decontaminate": true,
180
+ "doc_to_decontamination_query": "goal",
181
+ "metadata": {
182
+ "version": 1.0,
183
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
184
+ "trust_remote_code": true,
185
+ "dtype": "float32",
186
+ "use_cache": false,
187
+ "relay_mode": "bypass_b",
188
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/piqa/piqa.yaml"
189
+ }
190
+ }
191
+ },
192
+ "versions": {
193
+ "arc_easy": 1.0,
194
+ "hellaswag": 1.0,
195
+ "piqa": 1.0
196
+ },
197
+ "n-shot": {
198
+ "arc_easy": 0,
199
+ "hellaswag": 0,
200
+ "piqa": 0
201
+ },
202
+ "higher_is_better": {
203
+ "arc_easy": {
204
+ "acc": true,
205
+ "acc_norm": true
206
+ },
207
+ "hellaswag": {
208
+ "acc": true,
209
+ "acc_norm": true
210
+ },
211
+ "piqa": {
212
+ "acc": true,
213
+ "acc_norm": true
214
+ }
215
+ },
216
+ "n-samples": {
217
+ "arc_easy": {
218
+ "original": 2376,
219
+ "effective": 2376
220
+ },
221
+ "piqa": {
222
+ "original": 1838,
223
+ "effective": 1838
224
+ },
225
+ "hellaswag": {
226
+ "original": 10042,
227
+ "effective": 10042
228
+ }
229
+ },
230
+ "config": {
231
+ "model": "hf",
232
+ "model_args": {
233
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
234
+ "trust_remote_code": true,
235
+ "dtype": "float32",
236
+ "use_cache": false,
237
+ "relay_mode": "bypass_b"
238
+ },
239
+ "model_num_parameters": 34999041,
240
+ "model_dtype": "torch.float32",
241
+ "model_revision": "main",
242
+ "model_sha": "",
243
+ "batch_size": "auto",
244
+ "batch_sizes": [
245
+ 64
246
+ ],
247
+ "device": "cuda:0",
248
+ "use_cache": null,
249
+ "limit": null,
250
+ "bootstrap_iters": 100000,
251
+ "gen_kwargs": {},
252
+ "random_seed": 0,
253
+ "numpy_seed": 1234,
254
+ "torch_seed": 1234,
255
+ "fewshot_seed": 1234
256
+ },
257
+ "git_hash": null,
258
+ "date": 1787137593.3229036,
259
+ "pretty_env_info": "PyTorch version: 2.11.0+cu130\nIs debug build: False\nCUDA used to build PyTorch: 13.0\nROCM used to build PyTorch: N/A\n\nOS: Arch Linux (x86_64)\nGCC version: (GCC) 16.2.1 20260810\nClang version: 22.1.8\nCMake version: version 4.4.2\nLibc version: glibc-2.44\n\nPython version: 3.14.7 (main, Aug 10 2026, 07:46:56) [GCC 16.1.1 20260728] (64-bit runtime)\nPython platform: Linux-7.1.8-arch1-3-x86_64-with-glibc2.44\nIs CUDA available: True\nCUDA runtime version: 13.3.73\nCUDA_MODULE_LOADING set to: \nGPU models and configuration: GPU 0: NVIDIA GeForce RTX 5070 Ti\nNvidia driver version: Could not collect\ncuDNN version: Probably one of the following:\n/usr/lib/libcudnn.so.9.25.0\n/usr/lib/libcudnn_adv.so.9.25.0\n/usr/lib/libcudnn_cnn.so.9.25.0\n/usr/lib/libcudnn_engines_precompiled.so.9.25.0\n/usr/lib/libcudnn_engines_runtime_compiled.so.9.25.0\n/usr/lib/libcudnn_engines_tensor_ir.so.9.25.0\n/usr/lib/libcudnn_ext.so.9.25.0\n/usr/lib/libcudnn_graph.so.9.25.0\n/usr/lib/libcudnn_heuristic.so.9.25.0\n/usr/lib/libcudnn_ops.so.9.25.0\nIs XPU available: False\nHIP runtime version: N/A\nMIOpen runtime version: N/A\nIs XNNPACK available: True\nCaching allocator config: N/A\n\nCPU:\nArchitecture: x86_64\nCPU op-mode(s): 32-bit, 64-bit\nAddress sizes: 39 bits physical, 48 bits virtual\nByte Order: Little Endian\nCPU(s): 24\nOn-line CPU(s) list: 0-23\nVendor ID: GenuineIntel\nModel name: 12th Gen Intel(R) Core(TM) i9-12900KF\nCPU family: 6\nModel: 151\nThread(s) per core: 2\nCore(s) per socket: 16\nSocket(s): 1\nStepping: 2\nMicrocode version: 0x3e\nCPU(s) scaling MHz: 18%\nCPU max MHz: 5200.0000\nCPU min MHz: 800.0000\nBogoMIPS: 6374.40\nFlags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect user_shstk avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi vnmi umip pku ospke waitpkg gfni vaes vpclmulqdq rdpid movdiri movdir64b fsrm md_clear serialize arch_lbr ibt flush_l1d arch_capabilities\nVirtualization: VT-x\nL1d cache: 640 KiB (16 instances)\nL1i cache: 768 KiB (16 instances)\nL2 cache: 14 MiB (10 instances)\nL3 cache: 30 MiB (1 instance)\nNUMA node(s): 1\nNUMA node0 CPU(s): 0-23\nVulnerability Gather data sampling: Not affected\nVulnerability Ghostwrite: Not affected\nVulnerability Indirect target selection: Not affected\nVulnerability Itlb multihit: Not affected\nVulnerability L1tf: Not affected\nVulnerability Mds: Not affected\nVulnerability Meltdown: Not affected\nVulnerability Mmio stale data: Not affected\nVulnerability Old microcode: Not affected\nVulnerability Reg file data sampling: Mitigation; Clear Register File\nVulnerability Retbleed: Not affected\nVulnerability Spec rstack overflow: Not affected\nVulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl\nVulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization\nVulnerability Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; PBRSB-eIBRS SW sequence; BHI BHI_DIS_S\nVulnerability Srbds: Not affected\nVulnerability Tsa: Not affected\nVulnerability Tsx async abort: Not affected\nVulnerability Vmscape: Mitigation; IBPB before exit to userspace\n\nVersions of relevant libraries:\n[pip3] numpy==2.5.2\n[pip3] nvidia-cublas==13.1.0.3\n[pip3] nvidia-cuda-cupti==13.0.85\n[pip3] nvidia-cuda-nvrtc==13.0.88\n[pip3] nvidia-cuda-runtime==13.0.96\n[pip3] nvidia-cudnn-cu13==9.19.0.56\n[pip3] nvidia-cufft==12.0.0.61\n[pip3] nvidia-curand==10.4.0.35\n[pip3] nvidia-cusolver==12.0.4.66\n[pip3] nvidia-cusparse==12.6.3.3\n[pip3] nvidia-cusparselt-cu13==0.8.0\n[pip3] nvidia-nccl-cu13==2.28.9\n[pip3] nvidia-nvjitlink==13.0.88\n[pip3] nvidia-nvtx==13.0.85\n[pip3] segmentation_models_pytorch==0.5.0\n[pip3] torch==2.11.0\n[pip3] torchao==0.17.0\n[pip3] torchaudio==2.11.0\n[pip3] torchcodec==0.16.0\n[pip3] torchvision==0.26.0\n[pip3] triton==3.6.0\n[conda] Could not collect",
260
+ "transformers_version": "5.7.0",
261
+ "lm_eval_version": "0.4.12",
262
+ "upper_git_hash": null,
263
+ "tokenizer_pad_token": [
264
+ "<|pad|>",
265
+ "0"
266
+ ],
267
+ "tokenizer_eos_token": [
268
+ "<|eos|>",
269
+ "2"
270
+ ],
271
+ "tokenizer_bos_token": [
272
+ "<|bos|>",
273
+ "1"
274
+ ],
275
+ "eot_token_id": 2,
276
+ "max_length": 4096,
277
+ "task_hashes": {},
278
+ "model_source": "hf",
279
+ "model_name": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
280
+ "model_name_sanitized": "__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified",
281
+ "system_instruction": null,
282
+ "system_instruction_sha": null,
283
+ "fewshot_as_multiturn": null,
284
+ "chat_template": null,
285
+ "chat_template_sha": null,
286
+ "total_evaluation_time_seconds": "55.09879929400631"
287
+ }
eval_results/c_only/__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified/results_2026-08-19T13-11-40.562917.json ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "results": {
3
+ "arc_easy": {
4
+ "name": "arc_easy",
5
+ "alias": "arc_easy",
6
+ "sample_len": 2376,
7
+ "acc,none": 0.27104377104377103,
8
+ "acc_stderr,none": 0.009120919741760646,
9
+ "acc_norm,none": 0.28324915824915825,
10
+ "acc_norm_stderr,none": 0.009245632200075576
11
+ },
12
+ "piqa": {
13
+ "name": "piqa",
14
+ "alias": "piqa",
15
+ "sample_len": 1838,
16
+ "acc,none": 0.544613710554951,
17
+ "acc_stderr,none": 0.011619292444156876,
18
+ "acc_norm,none": 0.5212187159956474,
19
+ "acc_norm_stderr,none": 0.011655314732288771
20
+ },
21
+ "hellaswag": {
22
+ "name": "hellaswag",
23
+ "alias": "hellaswag",
24
+ "sample_len": 10042,
25
+ "acc,none": 0.2640908185620394,
26
+ "acc_stderr,none": 0.0043994691682725275,
27
+ "acc_norm,none": 0.2727544313881697,
28
+ "acc_norm_stderr,none": 0.004444654076551038
29
+ }
30
+ },
31
+ "group_subtasks": {},
32
+ "configs": {
33
+ "arc_easy": {
34
+ "task": "arc_easy",
35
+ "dataset_path": "allenai/ai2_arc",
36
+ "dataset_name": "ARC-Easy",
37
+ "training_split": "train",
38
+ "validation_split": "validation",
39
+ "test_split": "test",
40
+ "doc_to_text": "Question: {{question}}\nAnswer:",
41
+ "doc_to_target": "{{choices.label.index(answerKey)}}",
42
+ "unsafe_code": false,
43
+ "doc_to_choice": "{{choices.text}}",
44
+ "description": "",
45
+ "target_delimiter": " ",
46
+ "fewshot_delimiter": "\n\n",
47
+ "fewshot_config": {
48
+ "sampler": "default",
49
+ "split": null,
50
+ "process_docs": null,
51
+ "fewshot_indices": null,
52
+ "samples": null,
53
+ "doc_to_text": "Question: {{question}}\nAnswer:",
54
+ "doc_to_choice": "{{choices.text}}",
55
+ "doc_to_target": "{{choices.label.index(answerKey)}}",
56
+ "gen_prefix": null,
57
+ "fewshot_delimiter": "\n\n",
58
+ "target_delimiter": " "
59
+ },
60
+ "num_fewshot": 0,
61
+ "metric_list": [
62
+ {
63
+ "metric": "acc",
64
+ "aggregation": "mean",
65
+ "higher_is_better": true
66
+ },
67
+ {
68
+ "metric": "acc_norm",
69
+ "aggregation": "mean",
70
+ "higher_is_better": true
71
+ }
72
+ ],
73
+ "output_type": "multiple_choice",
74
+ "repeats": 1,
75
+ "should_decontaminate": true,
76
+ "doc_to_decontamination_query": "Question: {{question}}\nAnswer:",
77
+ "metadata": {
78
+ "version": 1.0,
79
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
80
+ "trust_remote_code": true,
81
+ "dtype": "float32",
82
+ "use_cache": false,
83
+ "relay_mode": "c_only",
84
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/arc/arc_easy.yaml"
85
+ }
86
+ },
87
+ "hellaswag": {
88
+ "task": "hellaswag",
89
+ "dataset_path": "Rowan/hellaswag",
90
+ "training_split": "train",
91
+ "validation_split": "validation",
92
+ "process_docs": "def process_docs(dataset: datasets.Dataset) -> datasets.Dataset:\n def _process_doc(doc):\n ctx = doc[\"ctx_a\"] + \" \" + doc[\"ctx_b\"].capitalize()\n out_doc = {\n \"query\": preprocess(doc[\"activity_label\"] + \": \" + ctx),\n \"choices\": [preprocess(ending) for ending in doc[\"endings\"]],\n \"gold\": int(doc[\"label\"]),\n }\n return out_doc\n\n return dataset.map(_process_doc)\n",
93
+ "doc_to_text": "{{query}}",
94
+ "doc_to_target": "{{label}}",
95
+ "unsafe_code": false,
96
+ "doc_to_choice": "choices",
97
+ "description": "",
98
+ "target_delimiter": " ",
99
+ "fewshot_delimiter": "\n\n",
100
+ "fewshot_config": {
101
+ "sampler": "default",
102
+ "split": null,
103
+ "process_docs": "<function process_docs at 0x7f91773f3950>",
104
+ "fewshot_indices": null,
105
+ "samples": null,
106
+ "doc_to_text": "{{query}}",
107
+ "doc_to_choice": "choices",
108
+ "doc_to_target": "{{label}}",
109
+ "gen_prefix": null,
110
+ "fewshot_delimiter": "\n\n",
111
+ "target_delimiter": " "
112
+ },
113
+ "num_fewshot": 0,
114
+ "metric_list": [
115
+ {
116
+ "metric": "acc",
117
+ "aggregation": "mean",
118
+ "higher_is_better": true
119
+ },
120
+ {
121
+ "metric": "acc_norm",
122
+ "aggregation": "mean",
123
+ "higher_is_better": true
124
+ }
125
+ ],
126
+ "output_type": "multiple_choice",
127
+ "repeats": 1,
128
+ "should_decontaminate": false,
129
+ "metadata": {
130
+ "version": 1.0,
131
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
132
+ "trust_remote_code": true,
133
+ "dtype": "float32",
134
+ "use_cache": false,
135
+ "relay_mode": "c_only",
136
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/hellaswag/hellaswag.yaml"
137
+ }
138
+ },
139
+ "piqa": {
140
+ "task": "piqa",
141
+ "dataset_path": "baber/piqa",
142
+ "training_split": "train",
143
+ "validation_split": "validation",
144
+ "doc_to_text": "Question: {{goal}}\nAnswer:",
145
+ "doc_to_target": "label",
146
+ "unsafe_code": false,
147
+ "doc_to_choice": "{{[sol1, sol2]}}",
148
+ "description": "",
149
+ "target_delimiter": " ",
150
+ "fewshot_delimiter": "\n\n",
151
+ "fewshot_config": {
152
+ "sampler": "default",
153
+ "split": null,
154
+ "process_docs": null,
155
+ "fewshot_indices": null,
156
+ "samples": null,
157
+ "doc_to_text": "Question: {{goal}}\nAnswer:",
158
+ "doc_to_choice": "{{[sol1, sol2]}}",
159
+ "doc_to_target": "label",
160
+ "gen_prefix": null,
161
+ "fewshot_delimiter": "\n\n",
162
+ "target_delimiter": " "
163
+ },
164
+ "num_fewshot": 0,
165
+ "metric_list": [
166
+ {
167
+ "metric": "acc",
168
+ "aggregation": "mean",
169
+ "higher_is_better": true
170
+ },
171
+ {
172
+ "metric": "acc_norm",
173
+ "aggregation": "mean",
174
+ "higher_is_better": true
175
+ }
176
+ ],
177
+ "output_type": "multiple_choice",
178
+ "repeats": 1,
179
+ "should_decontaminate": true,
180
+ "doc_to_decontamination_query": "goal",
181
+ "metadata": {
182
+ "version": 1.0,
183
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
184
+ "trust_remote_code": true,
185
+ "dtype": "float32",
186
+ "use_cache": false,
187
+ "relay_mode": "c_only",
188
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/piqa/piqa.yaml"
189
+ }
190
+ }
191
+ },
192
+ "versions": {
193
+ "arc_easy": 1.0,
194
+ "hellaswag": 1.0,
195
+ "piqa": 1.0
196
+ },
197
+ "n-shot": {
198
+ "arc_easy": 0,
199
+ "hellaswag": 0,
200
+ "piqa": 0
201
+ },
202
+ "higher_is_better": {
203
+ "arc_easy": {
204
+ "acc": true,
205
+ "acc_norm": true
206
+ },
207
+ "hellaswag": {
208
+ "acc": true,
209
+ "acc_norm": true
210
+ },
211
+ "piqa": {
212
+ "acc": true,
213
+ "acc_norm": true
214
+ }
215
+ },
216
+ "n-samples": {
217
+ "arc_easy": {
218
+ "original": 2376,
219
+ "effective": 2376
220
+ },
221
+ "piqa": {
222
+ "original": 1838,
223
+ "effective": 1838
224
+ },
225
+ "hellaswag": {
226
+ "original": 10042,
227
+ "effective": 10042
228
+ }
229
+ },
230
+ "config": {
231
+ "model": "hf",
232
+ "model_args": {
233
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
234
+ "trust_remote_code": true,
235
+ "dtype": "float32",
236
+ "use_cache": false,
237
+ "relay_mode": "c_only"
238
+ },
239
+ "model_num_parameters": 34999041,
240
+ "model_dtype": "torch.float32",
241
+ "model_revision": "main",
242
+ "model_sha": "",
243
+ "batch_size": "auto",
244
+ "batch_sizes": [
245
+ 64
246
+ ],
247
+ "device": "cuda:0",
248
+ "use_cache": null,
249
+ "limit": null,
250
+ "bootstrap_iters": 100000,
251
+ "gen_kwargs": {},
252
+ "random_seed": 0,
253
+ "numpy_seed": 1234,
254
+ "torch_seed": 1234,
255
+ "fewshot_seed": 1234
256
+ },
257
+ "git_hash": null,
258
+ "date": 1787137857.061881,
259
+ "pretty_env_info": "PyTorch version: 2.11.0+cu130\nIs debug build: False\nCUDA used to build PyTorch: 13.0\nROCM used to build PyTorch: N/A\n\nOS: Arch Linux (x86_64)\nGCC version: (GCC) 16.2.1 20260810\nClang version: 22.1.8\nCMake version: version 4.4.2\nLibc version: glibc-2.44\n\nPython version: 3.14.7 (main, Aug 10 2026, 07:46:56) [GCC 16.1.1 20260728] (64-bit runtime)\nPython platform: Linux-7.1.8-arch1-3-x86_64-with-glibc2.44\nIs CUDA available: True\nCUDA runtime version: 13.3.73\nCUDA_MODULE_LOADING set to: \nGPU models and configuration: GPU 0: NVIDIA GeForce RTX 5070 Ti\nNvidia driver version: Could not collect\ncuDNN version: Probably one of the following:\n/usr/lib/libcudnn.so.9.25.0\n/usr/lib/libcudnn_adv.so.9.25.0\n/usr/lib/libcudnn_cnn.so.9.25.0\n/usr/lib/libcudnn_engines_precompiled.so.9.25.0\n/usr/lib/libcudnn_engines_runtime_compiled.so.9.25.0\n/usr/lib/libcudnn_engines_tensor_ir.so.9.25.0\n/usr/lib/libcudnn_ext.so.9.25.0\n/usr/lib/libcudnn_graph.so.9.25.0\n/usr/lib/libcudnn_heuristic.so.9.25.0\n/usr/lib/libcudnn_ops.so.9.25.0\nIs XPU available: False\nHIP runtime version: N/A\nMIOpen runtime version: N/A\nIs XNNPACK available: True\nCaching allocator config: N/A\n\nCPU:\nArchitecture: x86_64\nCPU op-mode(s): 32-bit, 64-bit\nAddress sizes: 39 bits physical, 48 bits virtual\nByte Order: Little Endian\nCPU(s): 24\nOn-line CPU(s) list: 0-23\nVendor ID: GenuineIntel\nModel name: 12th Gen Intel(R) Core(TM) i9-12900KF\nCPU family: 6\nModel: 151\nThread(s) per core: 2\nCore(s) per socket: 16\nSocket(s): 1\nStepping: 2\nMicrocode version: 0x3e\nCPU(s) scaling MHz: 33%\nCPU max MHz: 5200.0000\nCPU min MHz: 800.0000\nBogoMIPS: 6374.40\nFlags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect user_shstk avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi vnmi umip pku ospke waitpkg gfni vaes vpclmulqdq rdpid movdiri movdir64b fsrm md_clear serialize arch_lbr ibt flush_l1d arch_capabilities\nVirtualization: VT-x\nL1d cache: 640 KiB (16 instances)\nL1i cache: 768 KiB (16 instances)\nL2 cache: 14 MiB (10 instances)\nL3 cache: 30 MiB (1 instance)\nNUMA node(s): 1\nNUMA node0 CPU(s): 0-23\nVulnerability Gather data sampling: Not affected\nVulnerability Ghostwrite: Not affected\nVulnerability Indirect target selection: Not affected\nVulnerability Itlb multihit: Not affected\nVulnerability L1tf: Not affected\nVulnerability Mds: Not affected\nVulnerability Meltdown: Not affected\nVulnerability Mmio stale data: Not affected\nVulnerability Old microcode: Not affected\nVulnerability Reg file data sampling: Mitigation; Clear Register File\nVulnerability Retbleed: Not affected\nVulnerability Spec rstack overflow: Not affected\nVulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl\nVulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization\nVulnerability Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; PBRSB-eIBRS SW sequence; BHI BHI_DIS_S\nVulnerability Srbds: Not affected\nVulnerability Tsa: Not affected\nVulnerability Tsx async abort: Not affected\nVulnerability Vmscape: Mitigation; IBPB before exit to userspace\n\nVersions of relevant libraries:\n[pip3] numpy==2.5.2\n[pip3] nvidia-cublas==13.1.0.3\n[pip3] nvidia-cuda-cupti==13.0.85\n[pip3] nvidia-cuda-nvrtc==13.0.88\n[pip3] nvidia-cuda-runtime==13.0.96\n[pip3] nvidia-cudnn-cu13==9.19.0.56\n[pip3] nvidia-cufft==12.0.0.61\n[pip3] nvidia-curand==10.4.0.35\n[pip3] nvidia-cusolver==12.0.4.66\n[pip3] nvidia-cusparse==12.6.3.3\n[pip3] nvidia-cusparselt-cu13==0.8.0\n[pip3] nvidia-nccl-cu13==2.28.9\n[pip3] nvidia-nvjitlink==13.0.88\n[pip3] nvidia-nvtx==13.0.85\n[pip3] segmentation_models_pytorch==0.5.0\n[pip3] torch==2.11.0\n[pip3] torchao==0.17.0\n[pip3] torchaudio==2.11.0\n[pip3] torchcodec==0.16.0\n[pip3] torchvision==0.26.0\n[pip3] triton==3.6.0\n[conda] Could not collect",
260
+ "transformers_version": "5.7.0",
261
+ "lm_eval_version": "0.4.12",
262
+ "upper_git_hash": null,
263
+ "tokenizer_pad_token": [
264
+ "<|pad|>",
265
+ "0"
266
+ ],
267
+ "tokenizer_eos_token": [
268
+ "<|eos|>",
269
+ "2"
270
+ ],
271
+ "tokenizer_bos_token": [
272
+ "<|bos|>",
273
+ "1"
274
+ ],
275
+ "eot_token_id": 2,
276
+ "max_length": 4096,
277
+ "task_hashes": {},
278
+ "model_source": "hf",
279
+ "model_name": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
280
+ "model_name_sanitized": "__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified",
281
+ "system_instruction": null,
282
+ "system_instruction_sha": null,
283
+ "fewshot_as_multiturn": null,
284
+ "chat_template": null,
285
+ "chat_template_sha": null,
286
+ "total_evaluation_time_seconds": "46.08944170398172"
287
+ }
eval_results/cb_only/__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified/results_2026-08-19T13-09-08.771260.json ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "results": {
3
+ "arc_easy": {
4
+ "name": "arc_easy",
5
+ "alias": "arc_easy",
6
+ "sample_len": 2376,
7
+ "acc,none": 0.35395622895622897,
8
+ "acc_stderr,none": 0.009812370644174563,
9
+ "acc_norm,none": 0.3569023569023569,
10
+ "acc_norm_stderr,none": 0.009830630210347113
11
+ },
12
+ "piqa": {
13
+ "name": "piqa",
14
+ "alias": "piqa",
15
+ "sample_len": 1838,
16
+ "acc,none": 0.5658324265505985,
17
+ "acc_stderr,none": 0.011564264866016225,
18
+ "acc_norm,none": 0.5516866158868335,
19
+ "acc_norm_stderr,none": 0.011603326108334476
20
+ },
21
+ "hellaswag": {
22
+ "name": "hellaswag",
23
+ "alias": "hellaswag",
24
+ "sample_len": 10042,
25
+ "acc,none": 0.26946823341963755,
26
+ "acc_stderr,none": 0.0044277679963018075,
27
+ "acc_norm,none": 0.28669587731527585,
28
+ "acc_norm_stderr,none": 0.004512940497463054
29
+ }
30
+ },
31
+ "group_subtasks": {},
32
+ "configs": {
33
+ "arc_easy": {
34
+ "task": "arc_easy",
35
+ "dataset_path": "allenai/ai2_arc",
36
+ "dataset_name": "ARC-Easy",
37
+ "training_split": "train",
38
+ "validation_split": "validation",
39
+ "test_split": "test",
40
+ "doc_to_text": "Question: {{question}}\nAnswer:",
41
+ "doc_to_target": "{{choices.label.index(answerKey)}}",
42
+ "unsafe_code": false,
43
+ "doc_to_choice": "{{choices.text}}",
44
+ "description": "",
45
+ "target_delimiter": " ",
46
+ "fewshot_delimiter": "\n\n",
47
+ "fewshot_config": {
48
+ "sampler": "default",
49
+ "split": null,
50
+ "process_docs": null,
51
+ "fewshot_indices": null,
52
+ "samples": null,
53
+ "doc_to_text": "Question: {{question}}\nAnswer:",
54
+ "doc_to_choice": "{{choices.text}}",
55
+ "doc_to_target": "{{choices.label.index(answerKey)}}",
56
+ "gen_prefix": null,
57
+ "fewshot_delimiter": "\n\n",
58
+ "target_delimiter": " "
59
+ },
60
+ "num_fewshot": 0,
61
+ "metric_list": [
62
+ {
63
+ "metric": "acc",
64
+ "aggregation": "mean",
65
+ "higher_is_better": true
66
+ },
67
+ {
68
+ "metric": "acc_norm",
69
+ "aggregation": "mean",
70
+ "higher_is_better": true
71
+ }
72
+ ],
73
+ "output_type": "multiple_choice",
74
+ "repeats": 1,
75
+ "should_decontaminate": true,
76
+ "doc_to_decontamination_query": "Question: {{question}}\nAnswer:",
77
+ "metadata": {
78
+ "version": 1.0,
79
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
80
+ "trust_remote_code": true,
81
+ "dtype": "float32",
82
+ "use_cache": false,
83
+ "relay_mode": "cb_only",
84
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/arc/arc_easy.yaml"
85
+ }
86
+ },
87
+ "hellaswag": {
88
+ "task": "hellaswag",
89
+ "dataset_path": "Rowan/hellaswag",
90
+ "training_split": "train",
91
+ "validation_split": "validation",
92
+ "process_docs": "def process_docs(dataset: datasets.Dataset) -> datasets.Dataset:\n def _process_doc(doc):\n ctx = doc[\"ctx_a\"] + \" \" + doc[\"ctx_b\"].capitalize()\n out_doc = {\n \"query\": preprocess(doc[\"activity_label\"] + \": \" + ctx),\n \"choices\": [preprocess(ending) for ending in doc[\"endings\"]],\n \"gold\": int(doc[\"label\"]),\n }\n return out_doc\n\n return dataset.map(_process_doc)\n",
93
+ "doc_to_text": "{{query}}",
94
+ "doc_to_target": "{{label}}",
95
+ "unsafe_code": false,
96
+ "doc_to_choice": "choices",
97
+ "description": "",
98
+ "target_delimiter": " ",
99
+ "fewshot_delimiter": "\n\n",
100
+ "fewshot_config": {
101
+ "sampler": "default",
102
+ "split": null,
103
+ "process_docs": "<function process_docs at 0x7fcab37ff950>",
104
+ "fewshot_indices": null,
105
+ "samples": null,
106
+ "doc_to_text": "{{query}}",
107
+ "doc_to_choice": "choices",
108
+ "doc_to_target": "{{label}}",
109
+ "gen_prefix": null,
110
+ "fewshot_delimiter": "\n\n",
111
+ "target_delimiter": " "
112
+ },
113
+ "num_fewshot": 0,
114
+ "metric_list": [
115
+ {
116
+ "metric": "acc",
117
+ "aggregation": "mean",
118
+ "higher_is_better": true
119
+ },
120
+ {
121
+ "metric": "acc_norm",
122
+ "aggregation": "mean",
123
+ "higher_is_better": true
124
+ }
125
+ ],
126
+ "output_type": "multiple_choice",
127
+ "repeats": 1,
128
+ "should_decontaminate": false,
129
+ "metadata": {
130
+ "version": 1.0,
131
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
132
+ "trust_remote_code": true,
133
+ "dtype": "float32",
134
+ "use_cache": false,
135
+ "relay_mode": "cb_only",
136
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/hellaswag/hellaswag.yaml"
137
+ }
138
+ },
139
+ "piqa": {
140
+ "task": "piqa",
141
+ "dataset_path": "baber/piqa",
142
+ "training_split": "train",
143
+ "validation_split": "validation",
144
+ "doc_to_text": "Question: {{goal}}\nAnswer:",
145
+ "doc_to_target": "label",
146
+ "unsafe_code": false,
147
+ "doc_to_choice": "{{[sol1, sol2]}}",
148
+ "description": "",
149
+ "target_delimiter": " ",
150
+ "fewshot_delimiter": "\n\n",
151
+ "fewshot_config": {
152
+ "sampler": "default",
153
+ "split": null,
154
+ "process_docs": null,
155
+ "fewshot_indices": null,
156
+ "samples": null,
157
+ "doc_to_text": "Question: {{goal}}\nAnswer:",
158
+ "doc_to_choice": "{{[sol1, sol2]}}",
159
+ "doc_to_target": "label",
160
+ "gen_prefix": null,
161
+ "fewshot_delimiter": "\n\n",
162
+ "target_delimiter": " "
163
+ },
164
+ "num_fewshot": 0,
165
+ "metric_list": [
166
+ {
167
+ "metric": "acc",
168
+ "aggregation": "mean",
169
+ "higher_is_better": true
170
+ },
171
+ {
172
+ "metric": "acc_norm",
173
+ "aggregation": "mean",
174
+ "higher_is_better": true
175
+ }
176
+ ],
177
+ "output_type": "multiple_choice",
178
+ "repeats": 1,
179
+ "should_decontaminate": true,
180
+ "doc_to_decontamination_query": "goal",
181
+ "metadata": {
182
+ "version": 1.0,
183
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
184
+ "trust_remote_code": true,
185
+ "dtype": "float32",
186
+ "use_cache": false,
187
+ "relay_mode": "cb_only",
188
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/piqa/piqa.yaml"
189
+ }
190
+ }
191
+ },
192
+ "versions": {
193
+ "arc_easy": 1.0,
194
+ "hellaswag": 1.0,
195
+ "piqa": 1.0
196
+ },
197
+ "n-shot": {
198
+ "arc_easy": 0,
199
+ "hellaswag": 0,
200
+ "piqa": 0
201
+ },
202
+ "higher_is_better": {
203
+ "arc_easy": {
204
+ "acc": true,
205
+ "acc_norm": true
206
+ },
207
+ "hellaswag": {
208
+ "acc": true,
209
+ "acc_norm": true
210
+ },
211
+ "piqa": {
212
+ "acc": true,
213
+ "acc_norm": true
214
+ }
215
+ },
216
+ "n-samples": {
217
+ "arc_easy": {
218
+ "original": 2376,
219
+ "effective": 2376
220
+ },
221
+ "piqa": {
222
+ "original": 1838,
223
+ "effective": 1838
224
+ },
225
+ "hellaswag": {
226
+ "original": 10042,
227
+ "effective": 10042
228
+ }
229
+ },
230
+ "config": {
231
+ "model": "hf",
232
+ "model_args": {
233
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
234
+ "trust_remote_code": true,
235
+ "dtype": "float32",
236
+ "use_cache": false,
237
+ "relay_mode": "cb_only"
238
+ },
239
+ "model_num_parameters": 34999041,
240
+ "model_dtype": "torch.float32",
241
+ "model_revision": "main",
242
+ "model_sha": "",
243
+ "batch_size": "auto",
244
+ "batch_sizes": [
245
+ 64
246
+ ],
247
+ "device": "cuda:0",
248
+ "use_cache": null,
249
+ "limit": null,
250
+ "bootstrap_iters": 100000,
251
+ "gen_kwargs": {},
252
+ "random_seed": 0,
253
+ "numpy_seed": 1234,
254
+ "torch_seed": 1234,
255
+ "fewshot_seed": 1234
256
+ },
257
+ "git_hash": null,
258
+ "date": 1787137702.9870973,
259
+ "pretty_env_info": "PyTorch version: 2.11.0+cu130\nIs debug build: False\nCUDA used to build PyTorch: 13.0\nROCM used to build PyTorch: N/A\n\nOS: Arch Linux (x86_64)\nGCC version: (GCC) 16.2.1 20260810\nClang version: 22.1.8\nCMake version: version 4.4.2\nLibc version: glibc-2.44\n\nPython version: 3.14.7 (main, Aug 10 2026, 07:46:56) [GCC 16.1.1 20260728] (64-bit runtime)\nPython platform: Linux-7.1.8-arch1-3-x86_64-with-glibc2.44\nIs CUDA available: True\nCUDA runtime version: 13.3.73\nCUDA_MODULE_LOADING set to: \nGPU models and configuration: GPU 0: NVIDIA GeForce RTX 5070 Ti\nNvidia driver version: Could not collect\ncuDNN version: Probably one of the following:\n/usr/lib/libcudnn.so.9.25.0\n/usr/lib/libcudnn_adv.so.9.25.0\n/usr/lib/libcudnn_cnn.so.9.25.0\n/usr/lib/libcudnn_engines_precompiled.so.9.25.0\n/usr/lib/libcudnn_engines_runtime_compiled.so.9.25.0\n/usr/lib/libcudnn_engines_tensor_ir.so.9.25.0\n/usr/lib/libcudnn_ext.so.9.25.0\n/usr/lib/libcudnn_graph.so.9.25.0\n/usr/lib/libcudnn_heuristic.so.9.25.0\n/usr/lib/libcudnn_ops.so.9.25.0\nIs XPU available: False\nHIP runtime version: N/A\nMIOpen runtime version: N/A\nIs XNNPACK available: True\nCaching allocator config: N/A\n\nCPU:\nArchitecture: x86_64\nCPU op-mode(s): 32-bit, 64-bit\nAddress sizes: 39 bits physical, 48 bits virtual\nByte Order: Little Endian\nCPU(s): 24\nOn-line CPU(s) list: 0-23\nVendor ID: GenuineIntel\nModel name: 12th Gen Intel(R) Core(TM) i9-12900KF\nCPU family: 6\nModel: 151\nThread(s) per core: 2\nCore(s) per socket: 16\nSocket(s): 1\nStepping: 2\nMicrocode version: 0x3e\nCPU(s) scaling MHz: 19%\nCPU max MHz: 5200.0000\nCPU min MHz: 800.0000\nBogoMIPS: 6374.40\nFlags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect user_shstk avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi vnmi umip pku ospke waitpkg gfni vaes vpclmulqdq rdpid movdiri movdir64b fsrm md_clear serialize arch_lbr ibt flush_l1d arch_capabilities\nVirtualization: VT-x\nL1d cache: 640 KiB (16 instances)\nL1i cache: 768 KiB (16 instances)\nL2 cache: 14 MiB (10 instances)\nL3 cache: 30 MiB (1 instance)\nNUMA node(s): 1\nNUMA node0 CPU(s): 0-23\nVulnerability Gather data sampling: Not affected\nVulnerability Ghostwrite: Not affected\nVulnerability Indirect target selection: Not affected\nVulnerability Itlb multihit: Not affected\nVulnerability L1tf: Not affected\nVulnerability Mds: Not affected\nVulnerability Meltdown: Not affected\nVulnerability Mmio stale data: Not affected\nVulnerability Old microcode: Not affected\nVulnerability Reg file data sampling: Mitigation; Clear Register File\nVulnerability Retbleed: Not affected\nVulnerability Spec rstack overflow: Not affected\nVulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl\nVulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization\nVulnerability Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; PBRSB-eIBRS SW sequence; BHI BHI_DIS_S\nVulnerability Srbds: Not affected\nVulnerability Tsa: Not affected\nVulnerability Tsx async abort: Not affected\nVulnerability Vmscape: Mitigation; IBPB before exit to userspace\n\nVersions of relevant libraries:\n[pip3] numpy==2.5.2\n[pip3] nvidia-cublas==13.1.0.3\n[pip3] nvidia-cuda-cupti==13.0.85\n[pip3] nvidia-cuda-nvrtc==13.0.88\n[pip3] nvidia-cuda-runtime==13.0.96\n[pip3] nvidia-cudnn-cu13==9.19.0.56\n[pip3] nvidia-cufft==12.0.0.61\n[pip3] nvidia-curand==10.4.0.35\n[pip3] nvidia-cusolver==12.0.4.66\n[pip3] nvidia-cusparse==12.6.3.3\n[pip3] nvidia-cusparselt-cu13==0.8.0\n[pip3] nvidia-nccl-cu13==2.28.9\n[pip3] nvidia-nvjitlink==13.0.88\n[pip3] nvidia-nvtx==13.0.85\n[pip3] segmentation_models_pytorch==0.5.0\n[pip3] torch==2.11.0\n[pip3] torchao==0.17.0\n[pip3] torchaudio==2.11.0\n[pip3] torchcodec==0.16.0\n[pip3] torchvision==0.26.0\n[pip3] triton==3.6.0\n[conda] Could not collect",
260
+ "transformers_version": "5.7.0",
261
+ "lm_eval_version": "0.4.12",
262
+ "upper_git_hash": null,
263
+ "tokenizer_pad_token": [
264
+ "<|pad|>",
265
+ "0"
266
+ ],
267
+ "tokenizer_eos_token": [
268
+ "<|eos|>",
269
+ "2"
270
+ ],
271
+ "tokenizer_bos_token": [
272
+ "<|bos|>",
273
+ "1"
274
+ ],
275
+ "eot_token_id": 2,
276
+ "max_length": 4096,
277
+ "task_hashes": {},
278
+ "model_source": "hf",
279
+ "model_name": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
280
+ "model_name_sanitized": "__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified",
281
+ "system_instruction": null,
282
+ "system_instruction_sha": null,
283
+ "fewshot_as_multiturn": null,
284
+ "chat_template": null,
285
+ "chat_template_sha": null,
286
+ "total_evaluation_time_seconds": "48.45971779001411"
287
+ }
eval_results/cut_bridges/__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified/results_2026-08-19T13-10-07.184445.json ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "results": {
3
+ "arc_easy": {
4
+ "name": "arc_easy",
5
+ "alias": "arc_easy",
6
+ "sample_len": 2376,
7
+ "acc,none": 0.26515151515151514,
8
+ "acc_stderr,none": 0.009057621139172679,
9
+ "acc_norm,none": 0.27946127946127947,
10
+ "acc_norm_stderr,none": 0.009207838142597383
11
+ },
12
+ "piqa": {
13
+ "name": "piqa",
14
+ "alias": "piqa",
15
+ "sample_len": 1838,
16
+ "acc,none": 0.543525571273123,
17
+ "acc_stderr,none": 0.011621538875661558,
18
+ "acc_norm,none": 0.515233949945593,
19
+ "acc_norm_stderr,none": 0.011660408257153443
20
+ },
21
+ "hellaswag": {
22
+ "name": "hellaswag",
23
+ "alias": "hellaswag",
24
+ "sample_len": 10042,
25
+ "acc,none": 0.26289583748257317,
26
+ "acc_stderr,none": 0.004393066760916671,
27
+ "acc_norm,none": 0.2780322644891456,
28
+ "acc_norm_stderr,none": 0.004471137333619756
29
+ }
30
+ },
31
+ "group_subtasks": {},
32
+ "configs": {
33
+ "arc_easy": {
34
+ "task": "arc_easy",
35
+ "dataset_path": "allenai/ai2_arc",
36
+ "dataset_name": "ARC-Easy",
37
+ "training_split": "train",
38
+ "validation_split": "validation",
39
+ "test_split": "test",
40
+ "doc_to_text": "Question: {{question}}\nAnswer:",
41
+ "doc_to_target": "{{choices.label.index(answerKey)}}",
42
+ "unsafe_code": false,
43
+ "doc_to_choice": "{{choices.text}}",
44
+ "description": "",
45
+ "target_delimiter": " ",
46
+ "fewshot_delimiter": "\n\n",
47
+ "fewshot_config": {
48
+ "sampler": "default",
49
+ "split": null,
50
+ "process_docs": null,
51
+ "fewshot_indices": null,
52
+ "samples": null,
53
+ "doc_to_text": "Question: {{question}}\nAnswer:",
54
+ "doc_to_choice": "{{choices.text}}",
55
+ "doc_to_target": "{{choices.label.index(answerKey)}}",
56
+ "gen_prefix": null,
57
+ "fewshot_delimiter": "\n\n",
58
+ "target_delimiter": " "
59
+ },
60
+ "num_fewshot": 0,
61
+ "metric_list": [
62
+ {
63
+ "metric": "acc",
64
+ "aggregation": "mean",
65
+ "higher_is_better": true
66
+ },
67
+ {
68
+ "metric": "acc_norm",
69
+ "aggregation": "mean",
70
+ "higher_is_better": true
71
+ }
72
+ ],
73
+ "output_type": "multiple_choice",
74
+ "repeats": 1,
75
+ "should_decontaminate": true,
76
+ "doc_to_decontamination_query": "Question: {{question}}\nAnswer:",
77
+ "metadata": {
78
+ "version": 1.0,
79
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
80
+ "trust_remote_code": true,
81
+ "dtype": "float32",
82
+ "use_cache": false,
83
+ "relay_mode": "cut_bridges",
84
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/arc/arc_easy.yaml"
85
+ }
86
+ },
87
+ "hellaswag": {
88
+ "task": "hellaswag",
89
+ "dataset_path": "Rowan/hellaswag",
90
+ "training_split": "train",
91
+ "validation_split": "validation",
92
+ "process_docs": "def process_docs(dataset: datasets.Dataset) -> datasets.Dataset:\n def _process_doc(doc):\n ctx = doc[\"ctx_a\"] + \" \" + doc[\"ctx_b\"].capitalize()\n out_doc = {\n \"query\": preprocess(doc[\"activity_label\"] + \": \" + ctx),\n \"choices\": [preprocess(ending) for ending in doc[\"endings\"]],\n \"gold\": int(doc[\"label\"]),\n }\n return out_doc\n\n return dataset.map(_process_doc)\n",
93
+ "doc_to_text": "{{query}}",
94
+ "doc_to_target": "{{label}}",
95
+ "unsafe_code": false,
96
+ "doc_to_choice": "choices",
97
+ "description": "",
98
+ "target_delimiter": " ",
99
+ "fewshot_delimiter": "\n\n",
100
+ "fewshot_config": {
101
+ "sampler": "default",
102
+ "split": null,
103
+ "process_docs": "<function process_docs at 0x7fa7efa2b950>",
104
+ "fewshot_indices": null,
105
+ "samples": null,
106
+ "doc_to_text": "{{query}}",
107
+ "doc_to_choice": "choices",
108
+ "doc_to_target": "{{label}}",
109
+ "gen_prefix": null,
110
+ "fewshot_delimiter": "\n\n",
111
+ "target_delimiter": " "
112
+ },
113
+ "num_fewshot": 0,
114
+ "metric_list": [
115
+ {
116
+ "metric": "acc",
117
+ "aggregation": "mean",
118
+ "higher_is_better": true
119
+ },
120
+ {
121
+ "metric": "acc_norm",
122
+ "aggregation": "mean",
123
+ "higher_is_better": true
124
+ }
125
+ ],
126
+ "output_type": "multiple_choice",
127
+ "repeats": 1,
128
+ "should_decontaminate": false,
129
+ "metadata": {
130
+ "version": 1.0,
131
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
132
+ "trust_remote_code": true,
133
+ "dtype": "float32",
134
+ "use_cache": false,
135
+ "relay_mode": "cut_bridges",
136
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/hellaswag/hellaswag.yaml"
137
+ }
138
+ },
139
+ "piqa": {
140
+ "task": "piqa",
141
+ "dataset_path": "baber/piqa",
142
+ "training_split": "train",
143
+ "validation_split": "validation",
144
+ "doc_to_text": "Question: {{goal}}\nAnswer:",
145
+ "doc_to_target": "label",
146
+ "unsafe_code": false,
147
+ "doc_to_choice": "{{[sol1, sol2]}}",
148
+ "description": "",
149
+ "target_delimiter": " ",
150
+ "fewshot_delimiter": "\n\n",
151
+ "fewshot_config": {
152
+ "sampler": "default",
153
+ "split": null,
154
+ "process_docs": null,
155
+ "fewshot_indices": null,
156
+ "samples": null,
157
+ "doc_to_text": "Question: {{goal}}\nAnswer:",
158
+ "doc_to_choice": "{{[sol1, sol2]}}",
159
+ "doc_to_target": "label",
160
+ "gen_prefix": null,
161
+ "fewshot_delimiter": "\n\n",
162
+ "target_delimiter": " "
163
+ },
164
+ "num_fewshot": 0,
165
+ "metric_list": [
166
+ {
167
+ "metric": "acc",
168
+ "aggregation": "mean",
169
+ "higher_is_better": true
170
+ },
171
+ {
172
+ "metric": "acc_norm",
173
+ "aggregation": "mean",
174
+ "higher_is_better": true
175
+ }
176
+ ],
177
+ "output_type": "multiple_choice",
178
+ "repeats": 1,
179
+ "should_decontaminate": true,
180
+ "doc_to_decontamination_query": "goal",
181
+ "metadata": {
182
+ "version": 1.0,
183
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
184
+ "trust_remote_code": true,
185
+ "dtype": "float32",
186
+ "use_cache": false,
187
+ "relay_mode": "cut_bridges",
188
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/piqa/piqa.yaml"
189
+ }
190
+ }
191
+ },
192
+ "versions": {
193
+ "arc_easy": 1.0,
194
+ "hellaswag": 1.0,
195
+ "piqa": 1.0
196
+ },
197
+ "n-shot": {
198
+ "arc_easy": 0,
199
+ "hellaswag": 0,
200
+ "piqa": 0
201
+ },
202
+ "higher_is_better": {
203
+ "arc_easy": {
204
+ "acc": true,
205
+ "acc_norm": true
206
+ },
207
+ "hellaswag": {
208
+ "acc": true,
209
+ "acc_norm": true
210
+ },
211
+ "piqa": {
212
+ "acc": true,
213
+ "acc_norm": true
214
+ }
215
+ },
216
+ "n-samples": {
217
+ "arc_easy": {
218
+ "original": 2376,
219
+ "effective": 2376
220
+ },
221
+ "piqa": {
222
+ "original": 1838,
223
+ "effective": 1838
224
+ },
225
+ "hellaswag": {
226
+ "original": 10042,
227
+ "effective": 10042
228
+ }
229
+ },
230
+ "config": {
231
+ "model": "hf",
232
+ "model_args": {
233
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
234
+ "trust_remote_code": true,
235
+ "dtype": "float32",
236
+ "use_cache": false,
237
+ "relay_mode": "cut_bridges"
238
+ },
239
+ "model_num_parameters": 34999041,
240
+ "model_dtype": "torch.float32",
241
+ "model_revision": "main",
242
+ "model_sha": "",
243
+ "batch_size": "auto",
244
+ "batch_sizes": [
245
+ 64
246
+ ],
247
+ "device": "cuda:0",
248
+ "use_cache": null,
249
+ "limit": null,
250
+ "bootstrap_iters": 100000,
251
+ "gen_kwargs": {},
252
+ "random_seed": 0,
253
+ "numpy_seed": 1234,
254
+ "torch_seed": 1234,
255
+ "fewshot_seed": 1234
256
+ },
257
+ "git_hash": null,
258
+ "date": 1787137752.5487585,
259
+ "pretty_env_info": "PyTorch version: 2.11.0+cu130\nIs debug build: False\nCUDA used to build PyTorch: 13.0\nROCM used to build PyTorch: N/A\n\nOS: Arch Linux (x86_64)\nGCC version: (GCC) 16.2.1 20260810\nClang version: 22.1.8\nCMake version: version 4.4.2\nLibc version: glibc-2.44\n\nPython version: 3.14.7 (main, Aug 10 2026, 07:46:56) [GCC 16.1.1 20260728] (64-bit runtime)\nPython platform: Linux-7.1.8-arch1-3-x86_64-with-glibc2.44\nIs CUDA available: True\nCUDA runtime version: 13.3.73\nCUDA_MODULE_LOADING set to: \nGPU models and configuration: GPU 0: NVIDIA GeForce RTX 5070 Ti\nNvidia driver version: Could not collect\ncuDNN version: Probably one of the following:\n/usr/lib/libcudnn.so.9.25.0\n/usr/lib/libcudnn_adv.so.9.25.0\n/usr/lib/libcudnn_cnn.so.9.25.0\n/usr/lib/libcudnn_engines_precompiled.so.9.25.0\n/usr/lib/libcudnn_engines_runtime_compiled.so.9.25.0\n/usr/lib/libcudnn_engines_tensor_ir.so.9.25.0\n/usr/lib/libcudnn_ext.so.9.25.0\n/usr/lib/libcudnn_graph.so.9.25.0\n/usr/lib/libcudnn_heuristic.so.9.25.0\n/usr/lib/libcudnn_ops.so.9.25.0\nIs XPU available: False\nHIP runtime version: N/A\nMIOpen runtime version: N/A\nIs XNNPACK available: True\nCaching allocator config: N/A\n\nCPU:\nArchitecture: x86_64\nCPU op-mode(s): 32-bit, 64-bit\nAddress sizes: 39 bits physical, 48 bits virtual\nByte Order: Little Endian\nCPU(s): 24\nOn-line CPU(s) list: 0-23\nVendor ID: GenuineIntel\nModel name: 12th Gen Intel(R) Core(TM) i9-12900KF\nCPU family: 6\nModel: 151\nThread(s) per core: 2\nCore(s) per socket: 16\nSocket(s): 1\nStepping: 2\nMicrocode version: 0x3e\nCPU(s) scaling MHz: 23%\nCPU max MHz: 5200.0000\nCPU min MHz: 800.0000\nBogoMIPS: 6374.40\nFlags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect user_shstk avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi vnmi umip pku ospke waitpkg gfni vaes vpclmulqdq rdpid movdiri movdir64b fsrm md_clear serialize arch_lbr ibt flush_l1d arch_capabilities\nVirtualization: VT-x\nL1d cache: 640 KiB (16 instances)\nL1i cache: 768 KiB (16 instances)\nL2 cache: 14 MiB (10 instances)\nL3 cache: 30 MiB (1 instance)\nNUMA node(s): 1\nNUMA node0 CPU(s): 0-23\nVulnerability Gather data sampling: Not affected\nVulnerability Ghostwrite: Not affected\nVulnerability Indirect target selection: Not affected\nVulnerability Itlb multihit: Not affected\nVulnerability L1tf: Not affected\nVulnerability Mds: Not affected\nVulnerability Meltdown: Not affected\nVulnerability Mmio stale data: Not affected\nVulnerability Old microcode: Not affected\nVulnerability Reg file data sampling: Mitigation; Clear Register File\nVulnerability Retbleed: Not affected\nVulnerability Spec rstack overflow: Not affected\nVulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl\nVulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization\nVulnerability Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; PBRSB-eIBRS SW sequence; BHI BHI_DIS_S\nVulnerability Srbds: Not affected\nVulnerability Tsa: Not affected\nVulnerability Tsx async abort: Not affected\nVulnerability Vmscape: Mitigation; IBPB before exit to userspace\n\nVersions of relevant libraries:\n[pip3] numpy==2.5.2\n[pip3] nvidia-cublas==13.1.0.3\n[pip3] nvidia-cuda-cupti==13.0.85\n[pip3] nvidia-cuda-nvrtc==13.0.88\n[pip3] nvidia-cuda-runtime==13.0.96\n[pip3] nvidia-cudnn-cu13==9.19.0.56\n[pip3] nvidia-cufft==12.0.0.61\n[pip3] nvidia-curand==10.4.0.35\n[pip3] nvidia-cusolver==12.0.4.66\n[pip3] nvidia-cusparse==12.6.3.3\n[pip3] nvidia-cusparselt-cu13==0.8.0\n[pip3] nvidia-nccl-cu13==2.28.9\n[pip3] nvidia-nvjitlink==13.0.88\n[pip3] nvidia-nvtx==13.0.85\n[pip3] segmentation_models_pytorch==0.5.0\n[pip3] torch==2.11.0\n[pip3] torchao==0.17.0\n[pip3] torchaudio==2.11.0\n[pip3] torchcodec==0.16.0\n[pip3] torchvision==0.26.0\n[pip3] triton==3.6.0\n[conda] Could not collect",
260
+ "transformers_version": "5.7.0",
261
+ "lm_eval_version": "0.4.12",
262
+ "upper_git_hash": null,
263
+ "tokenizer_pad_token": [
264
+ "<|pad|>",
265
+ "0"
266
+ ],
267
+ "tokenizer_eos_token": [
268
+ "<|eos|>",
269
+ "2"
270
+ ],
271
+ "tokenizer_bos_token": [
272
+ "<|bos|>",
273
+ "1"
274
+ ],
275
+ "eot_token_id": 2,
276
+ "max_length": 4096,
277
+ "task_hashes": {},
278
+ "model_source": "hf",
279
+ "model_name": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
280
+ "model_name_sanitized": "__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified",
281
+ "system_instruction": null,
282
+ "system_instruction_sha": null,
283
+ "fewshot_as_multiturn": null,
284
+ "chat_template": null,
285
+ "chat_template_sha": null,
286
+ "total_evaluation_time_seconds": "57.18551829599892"
287
+ }
eval_results/full/__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified/results_2026-08-19T13-06-29.559607.json ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "results": {
3
+ "arc_easy": {
4
+ "name": "arc_easy",
5
+ "alias": "arc_easy",
6
+ "sample_len": 2376,
7
+ "acc,none": 0.43223905723905726,
8
+ "acc_stderr,none": 0.010165130379698673,
9
+ "acc_norm,none": 0.3851010101010101,
10
+ "acc_norm_stderr,none": 0.009985214798737322
11
+ },
12
+ "piqa": {
13
+ "name": "piqa",
14
+ "alias": "piqa",
15
+ "sample_len": 1838,
16
+ "acc,none": 0.6251360174102285,
17
+ "acc_stderr,none": 0.01129456580561892,
18
+ "acc_norm,none": 0.6175190424374319,
19
+ "acc_norm_stderr,none": 0.011339019654272245
20
+ },
21
+ "hellaswag": {
22
+ "name": "hellaswag",
23
+ "alias": "hellaswag",
24
+ "sample_len": 10042,
25
+ "acc,none": 0.28649671380203146,
26
+ "acc_stderr,none": 0.00451200245975772,
27
+ "acc_norm,none": 0.29944234216291576,
28
+ "acc_norm_stderr,none": 0.004570777326263939
29
+ }
30
+ },
31
+ "group_subtasks": {},
32
+ "configs": {
33
+ "arc_easy": {
34
+ "task": "arc_easy",
35
+ "dataset_path": "allenai/ai2_arc",
36
+ "dataset_name": "ARC-Easy",
37
+ "training_split": "train",
38
+ "validation_split": "validation",
39
+ "test_split": "test",
40
+ "doc_to_text": "Question: {{question}}\nAnswer:",
41
+ "doc_to_target": "{{choices.label.index(answerKey)}}",
42
+ "unsafe_code": false,
43
+ "doc_to_choice": "{{choices.text}}",
44
+ "description": "",
45
+ "target_delimiter": " ",
46
+ "fewshot_delimiter": "\n\n",
47
+ "fewshot_config": {
48
+ "sampler": "default",
49
+ "split": null,
50
+ "process_docs": null,
51
+ "fewshot_indices": null,
52
+ "samples": null,
53
+ "doc_to_text": "Question: {{question}}\nAnswer:",
54
+ "doc_to_choice": "{{choices.text}}",
55
+ "doc_to_target": "{{choices.label.index(answerKey)}}",
56
+ "gen_prefix": null,
57
+ "fewshot_delimiter": "\n\n",
58
+ "target_delimiter": " "
59
+ },
60
+ "num_fewshot": 0,
61
+ "metric_list": [
62
+ {
63
+ "metric": "acc",
64
+ "aggregation": "mean",
65
+ "higher_is_better": true
66
+ },
67
+ {
68
+ "metric": "acc_norm",
69
+ "aggregation": "mean",
70
+ "higher_is_better": true
71
+ }
72
+ ],
73
+ "output_type": "multiple_choice",
74
+ "repeats": 1,
75
+ "should_decontaminate": true,
76
+ "doc_to_decontamination_query": "Question: {{question}}\nAnswer:",
77
+ "metadata": {
78
+ "version": 1.0,
79
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
80
+ "trust_remote_code": true,
81
+ "dtype": "float32",
82
+ "use_cache": false,
83
+ "relay_mode": "full",
84
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/arc/arc_easy.yaml"
85
+ }
86
+ },
87
+ "hellaswag": {
88
+ "task": "hellaswag",
89
+ "dataset_path": "Rowan/hellaswag",
90
+ "training_split": "train",
91
+ "validation_split": "validation",
92
+ "process_docs": "def process_docs(dataset: datasets.Dataset) -> datasets.Dataset:\n def _process_doc(doc):\n ctx = doc[\"ctx_a\"] + \" \" + doc[\"ctx_b\"].capitalize()\n out_doc = {\n \"query\": preprocess(doc[\"activity_label\"] + \": \" + ctx),\n \"choices\": [preprocess(ending) for ending in doc[\"endings\"]],\n \"gold\": int(doc[\"label\"]),\n }\n return out_doc\n\n return dataset.map(_process_doc)\n",
93
+ "doc_to_text": "{{query}}",
94
+ "doc_to_target": "{{label}}",
95
+ "unsafe_code": false,
96
+ "doc_to_choice": "choices",
97
+ "description": "",
98
+ "target_delimiter": " ",
99
+ "fewshot_delimiter": "\n\n",
100
+ "fewshot_config": {
101
+ "sampler": "default",
102
+ "split": null,
103
+ "process_docs": "<function process_docs at 0x7fae1b617950>",
104
+ "fewshot_indices": null,
105
+ "samples": null,
106
+ "doc_to_text": "{{query}}",
107
+ "doc_to_choice": "choices",
108
+ "doc_to_target": "{{label}}",
109
+ "gen_prefix": null,
110
+ "fewshot_delimiter": "\n\n",
111
+ "target_delimiter": " "
112
+ },
113
+ "num_fewshot": 0,
114
+ "metric_list": [
115
+ {
116
+ "metric": "acc",
117
+ "aggregation": "mean",
118
+ "higher_is_better": true
119
+ },
120
+ {
121
+ "metric": "acc_norm",
122
+ "aggregation": "mean",
123
+ "higher_is_better": true
124
+ }
125
+ ],
126
+ "output_type": "multiple_choice",
127
+ "repeats": 1,
128
+ "should_decontaminate": false,
129
+ "metadata": {
130
+ "version": 1.0,
131
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
132
+ "trust_remote_code": true,
133
+ "dtype": "float32",
134
+ "use_cache": false,
135
+ "relay_mode": "full",
136
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/hellaswag/hellaswag.yaml"
137
+ }
138
+ },
139
+ "piqa": {
140
+ "task": "piqa",
141
+ "dataset_path": "baber/piqa",
142
+ "training_split": "train",
143
+ "validation_split": "validation",
144
+ "doc_to_text": "Question: {{goal}}\nAnswer:",
145
+ "doc_to_target": "label",
146
+ "unsafe_code": false,
147
+ "doc_to_choice": "{{[sol1, sol2]}}",
148
+ "description": "",
149
+ "target_delimiter": " ",
150
+ "fewshot_delimiter": "\n\n",
151
+ "fewshot_config": {
152
+ "sampler": "default",
153
+ "split": null,
154
+ "process_docs": null,
155
+ "fewshot_indices": null,
156
+ "samples": null,
157
+ "doc_to_text": "Question: {{goal}}\nAnswer:",
158
+ "doc_to_choice": "{{[sol1, sol2]}}",
159
+ "doc_to_target": "label",
160
+ "gen_prefix": null,
161
+ "fewshot_delimiter": "\n\n",
162
+ "target_delimiter": " "
163
+ },
164
+ "num_fewshot": 0,
165
+ "metric_list": [
166
+ {
167
+ "metric": "acc",
168
+ "aggregation": "mean",
169
+ "higher_is_better": true
170
+ },
171
+ {
172
+ "metric": "acc_norm",
173
+ "aggregation": "mean",
174
+ "higher_is_better": true
175
+ }
176
+ ],
177
+ "output_type": "multiple_choice",
178
+ "repeats": 1,
179
+ "should_decontaminate": true,
180
+ "doc_to_decontamination_query": "goal",
181
+ "metadata": {
182
+ "version": 1.0,
183
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
184
+ "trust_remote_code": true,
185
+ "dtype": "float32",
186
+ "use_cache": false,
187
+ "relay_mode": "full",
188
+ "config_source": "/home/banaxi/.local/lib/python3.14/site-packages/lm_eval/tasks/piqa/piqa.yaml"
189
+ }
190
+ }
191
+ },
192
+ "versions": {
193
+ "arc_easy": 1.0,
194
+ "hellaswag": 1.0,
195
+ "piqa": 1.0
196
+ },
197
+ "n-shot": {
198
+ "arc_easy": 0,
199
+ "hellaswag": 0,
200
+ "piqa": 0
201
+ },
202
+ "higher_is_better": {
203
+ "arc_easy": {
204
+ "acc": true,
205
+ "acc_norm": true
206
+ },
207
+ "hellaswag": {
208
+ "acc": true,
209
+ "acc_norm": true
210
+ },
211
+ "piqa": {
212
+ "acc": true,
213
+ "acc_norm": true
214
+ }
215
+ },
216
+ "n-samples": {
217
+ "arc_easy": {
218
+ "original": 2376,
219
+ "effective": 2376
220
+ },
221
+ "piqa": {
222
+ "original": 1838,
223
+ "effective": 1838
224
+ },
225
+ "hellaswag": {
226
+ "original": 10042,
227
+ "effective": 10042
228
+ }
229
+ },
230
+ "config": {
231
+ "model": "hf",
232
+ "model_args": {
233
+ "pretrained": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
234
+ "trust_remote_code": true,
235
+ "dtype": "float32",
236
+ "use_cache": false,
237
+ "relay_mode": "full"
238
+ },
239
+ "model_num_parameters": 34999041,
240
+ "model_dtype": "torch.float32",
241
+ "model_revision": "main",
242
+ "model_sha": "",
243
+ "batch_size": "auto",
244
+ "batch_sizes": [
245
+ 64
246
+ ],
247
+ "device": "cuda:0",
248
+ "use_cache": null,
249
+ "limit": null,
250
+ "bootstrap_iters": 100000,
251
+ "gen_kwargs": {},
252
+ "random_seed": 0,
253
+ "numpy_seed": 1234,
254
+ "torch_seed": 1234,
255
+ "fewshot_seed": 1234
256
+ },
257
+ "git_hash": null,
258
+ "date": 1787137532.7548308,
259
+ "pretty_env_info": "PyTorch version: 2.11.0+cu130\nIs debug build: False\nCUDA used to build PyTorch: 13.0\nROCM used to build PyTorch: N/A\n\nOS: Arch Linux (x86_64)\nGCC version: (GCC) 16.2.1 20260810\nClang version: 22.1.8\nCMake version: version 4.4.2\nLibc version: glibc-2.44\n\nPython version: 3.14.7 (main, Aug 10 2026, 07:46:56) [GCC 16.1.1 20260728] (64-bit runtime)\nPython platform: Linux-7.1.8-arch1-3-x86_64-with-glibc2.44\nIs CUDA available: True\nCUDA runtime version: 13.3.73\nCUDA_MODULE_LOADING set to: \nGPU models and configuration: GPU 0: NVIDIA GeForce RTX 5070 Ti\nNvidia driver version: Could not collect\ncuDNN version: Probably one of the following:\n/usr/lib/libcudnn.so.9.25.0\n/usr/lib/libcudnn_adv.so.9.25.0\n/usr/lib/libcudnn_cnn.so.9.25.0\n/usr/lib/libcudnn_engines_precompiled.so.9.25.0\n/usr/lib/libcudnn_engines_runtime_compiled.so.9.25.0\n/usr/lib/libcudnn_engines_tensor_ir.so.9.25.0\n/usr/lib/libcudnn_ext.so.9.25.0\n/usr/lib/libcudnn_graph.so.9.25.0\n/usr/lib/libcudnn_heuristic.so.9.25.0\n/usr/lib/libcudnn_ops.so.9.25.0\nIs XPU available: False\nHIP runtime version: N/A\nMIOpen runtime version: N/A\nIs XNNPACK available: True\nCaching allocator config: N/A\n\nCPU:\nArchitecture: x86_64\nCPU op-mode(s): 32-bit, 64-bit\nAddress sizes: 39 bits physical, 48 bits virtual\nByte Order: Little Endian\nCPU(s): 24\nOn-line CPU(s) list: 0-23\nVendor ID: GenuineIntel\nModel name: 12th Gen Intel(R) Core(TM) i9-12900KF\nCPU family: 6\nModel: 151\nThread(s) per core: 2\nCore(s) per socket: 16\nSocket(s): 1\nStepping: 2\nMicrocode version: 0x3e\nCPU(s) scaling MHz: 32%\nCPU max MHz: 5200.0000\nCPU min MHz: 800.0000\nBogoMIPS: 6374.40\nFlags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect user_shstk avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi vnmi umip pku ospke waitpkg gfni vaes vpclmulqdq rdpid movdiri movdir64b fsrm md_clear serialize arch_lbr ibt flush_l1d arch_capabilities\nVirtualization: VT-x\nL1d cache: 640 KiB (16 instances)\nL1i cache: 768 KiB (16 instances)\nL2 cache: 14 MiB (10 instances)\nL3 cache: 30 MiB (1 instance)\nNUMA node(s): 1\nNUMA node0 CPU(s): 0-23\nVulnerability Gather data sampling: Not affected\nVulnerability Ghostwrite: Not affected\nVulnerability Indirect target selection: Not affected\nVulnerability Itlb multihit: Not affected\nVulnerability L1tf: Not affected\nVulnerability Mds: Not affected\nVulnerability Meltdown: Not affected\nVulnerability Mmio stale data: Not affected\nVulnerability Old microcode: Not affected\nVulnerability Reg file data sampling: Mitigation; Clear Register File\nVulnerability Retbleed: Not affected\nVulnerability Spec rstack overflow: Not affected\nVulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl\nVulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization\nVulnerability Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; PBRSB-eIBRS SW sequence; BHI BHI_DIS_S\nVulnerability Srbds: Not affected\nVulnerability Tsa: Not affected\nVulnerability Tsx async abort: Not affected\nVulnerability Vmscape: Mitigation; IBPB before exit to userspace\n\nVersions of relevant libraries:\n[pip3] numpy==2.5.2\n[pip3] nvidia-cublas==13.1.0.3\n[pip3] nvidia-cuda-cupti==13.0.85\n[pip3] nvidia-cuda-nvrtc==13.0.88\n[pip3] nvidia-cuda-runtime==13.0.96\n[pip3] nvidia-cudnn-cu13==9.19.0.56\n[pip3] nvidia-cufft==12.0.0.61\n[pip3] nvidia-curand==10.4.0.35\n[pip3] nvidia-cusolver==12.0.4.66\n[pip3] nvidia-cusparse==12.6.3.3\n[pip3] nvidia-cusparselt-cu13==0.8.0\n[pip3] nvidia-nccl-cu13==2.28.9\n[pip3] nvidia-nvjitlink==13.0.88\n[pip3] nvidia-nvtx==13.0.85\n[pip3] segmentation_models_pytorch==0.5.0\n[pip3] torch==2.11.0\n[pip3] torchao==0.17.0\n[pip3] torchaudio==2.11.0\n[pip3] torchcodec==0.16.0\n[pip3] torchvision==0.26.0\n[pip3] triton==3.6.0\n[conda] Could not collect",
260
+ "transformers_version": "5.7.0",
261
+ "lm_eval_version": "0.4.12",
262
+ "upper_git_hash": null,
263
+ "tokenizer_pad_token": [
264
+ "<|pad|>",
265
+ "0"
266
+ ],
267
+ "tokenizer_eos_token": [
268
+ "<|eos|>",
269
+ "2"
270
+ ],
271
+ "tokenizer_bos_token": [
272
+ "<|bos|>",
273
+ "1"
274
+ ],
275
+ "eot_token_id": 2,
276
+ "max_length": 4096,
277
+ "task_hashes": {},
278
+ "model_source": "hf",
279
+ "model_name": "/home/banaxi/Desktop/BananaMind/BananaMind-2/BananaMind-2.1-Unified",
280
+ "model_name_sanitized": "__home__banaxi__Desktop__BananaMind__BananaMind-2__BananaMind-2.1-Unified",
281
+ "system_instruction": null,
282
+ "system_instruction_sha": null,
283
+ "fewshot_as_multiturn": null,
284
+ "chat_template": null,
285
+ "chat_template_sha": null,
286
+ "total_evaluation_time_seconds": "59.47798355802661"
287
+ }
generation_config.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 1,
4
+ "eos_token_id": 2,
5
+ "pad_token_id": 0,
6
+ "transformers_version": "5"
7
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3b23f2e1f59a5631fea477026f7b9b14f0b6fddeb42a1f448e7eff2eb365887a
3
+ size 140025876
modeling_bananamind21unified.py ADDED
@@ -0,0 +1,610 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """BananaMind 2.1 Unified as an HF causal LM.
2
+
3
+ IMPORTANT - what `.logits` contains
4
+ -----------------------------------
5
+ Towers A and C are mixed in *probability* space, so the natural output of this
6
+ model is a normalised log-probability vector, not a logit vector:
7
+
8
+ log p = logaddexp(log a + log_softmax(logits_A),
9
+ log(1-a) + log_softmax(logits_C))
10
+
11
+ `.logits` carries that log-probability vector directly. This is safe for every
12
+ standard consumer, because `log_softmax` is the identity on an already
13
+ normalised log-probability vector (its logsumexp is 0), and `softmax(log p) = p`.
14
+ So loglikelihood scoring, `generate()`, and temperature-1 sampling all behave
15
+ correctly. What is *not* meaningful is treating these numbers as unnormalised
16
+ scores with an arbitrary additive offset - they are already calibrated.
17
+
18
+ Tower B is the relay. It has no output head and never appears in the mixture;
19
+ it exists only to carry signal between A and C, which have no other path to
20
+ each other. Set `config.cut_bridges = True` to sever every bridge, which turns
21
+ A and C into two ordinary standalone transformers.
22
+
23
+ KV cache
24
+ --------
25
+ Supported, and on by default. A relay model has no single residual stack, so
26
+ the three towers share one flat cache index space - tower A first, then B, then
27
+ C - sized by `config.num_hidden_layers`, which is the sum of the three tower
28
+ depths. Each tower keeps its own entries; nothing is shared between them.
29
+
30
+ Two properties of this architecture make that work without any extra machinery:
31
+
32
+ * A bridge (`Edge`) is a per-channel gate on a linear map, so it mixes channels
33
+ but never positions. Every bridge contribution for a newly arriving token is
34
+ computable from that token's own tower states, so no bridge output has to be
35
+ cached alongside the KV states.
36
+ * RoPE enters the attention logits only through the relative offset between
37
+ query and key, so shifting a whole sequence - which is what left padding does
38
+ - leaves every attention score unchanged. Absolute positions taken from the
39
+ cache length are therefore correct for padded batches too.
40
+
41
+ Parameter names match the training module exactly, so a checkpoint transfers
42
+ without any key rewriting.
43
+ """
44
+ import math
45
+ from typing import Optional
46
+
47
+ import torch
48
+ import torch.nn as nn
49
+ import torch.nn.functional as F
50
+ from transformers import PreTrainedModel
51
+ from transformers.cache_utils import Cache, DynamicCache
52
+ from transformers.generation import GenerationMixin
53
+ from transformers.modeling_outputs import CausalLMOutputWithPast
54
+
55
+ from .configuration_bananamind21unified import BananaMind21UnifiedConfig
56
+
57
+
58
+ class RMSNorm(nn.Module):
59
+ def __init__(self, dim, eps=1e-6):
60
+ super().__init__()
61
+ self.eps = eps
62
+ self.weight = nn.Parameter(torch.ones(dim))
63
+
64
+ def forward(self, x):
65
+ x_float = x.float()
66
+ rms = torch.rsqrt(x_float.pow(2).mean(-1, keepdim=True) + self.eps)
67
+ return (x_float * rms * self.weight.float()).type_as(x)
68
+
69
+
70
+ def precompute_freqs_cis(head_dim, seq_len, theta=100000.0):
71
+ inv = 1.0 / (theta ** (torch.arange(0, head_dim, 2, dtype=torch.float32) / head_dim))
72
+ t = torch.arange(seq_len, dtype=torch.float32)
73
+ return torch.polar(torch.ones_like(torch.outer(t, inv)), torch.outer(t, inv))
74
+
75
+
76
+ def apply_rotary_emb(q, k, freqs_cis):
77
+ q_complex = torch.view_as_complex(q.float().reshape(*q.shape[:-1], -1, 2))
78
+ k_complex = torch.view_as_complex(k.float().reshape(*k.shape[:-1], -1, 2))
79
+ freqs_cis = freqs_cis.unsqueeze(0).unsqueeze(0)
80
+ q_out = torch.view_as_real(q_complex * freqs_cis).flatten(-2)
81
+ k_out = torch.view_as_real(k_complex * freqs_cis).flatten(-2)
82
+ return q_out.type_as(q), k_out.type_as(k)
83
+
84
+
85
+ class _Spec:
86
+ def __init__(self, hidden_size, num_hidden_layers, num_attention_heads, num_key_value_heads, intermediate_size):
87
+ self.hidden_size = hidden_size
88
+ self.num_hidden_layers = num_hidden_layers
89
+ self.num_attention_heads = num_attention_heads
90
+ self.num_key_value_heads = num_key_value_heads
91
+ self.intermediate_size = intermediate_size
92
+
93
+
94
+ class TowerAttention(nn.Module):
95
+ def __init__(self, spec, head_dim, rms_norm_eps, layer_idx=None):
96
+ super().__init__()
97
+ self.n_head = spec.num_attention_heads
98
+ self.n_kv_heads = spec.num_key_value_heads
99
+ self.head_dim = head_dim
100
+ self.n_rep = self.n_head // self.n_kv_heads
101
+ # flat index into the shared KV cache; see `num_hidden_layers` in the config
102
+ self.layer_idx = layer_idx
103
+ self.q_proj = nn.Linear(spec.hidden_size, self.n_head * head_dim, bias=False)
104
+ self.k_proj = nn.Linear(spec.hidden_size, self.n_kv_heads * head_dim, bias=False)
105
+ self.v_proj = nn.Linear(spec.hidden_size, self.n_kv_heads * head_dim, bias=False)
106
+ self.o_proj = nn.Linear(self.n_head * head_dim, spec.hidden_size, bias=False)
107
+ self.q_norm = RMSNorm(head_dim, eps=rms_norm_eps)
108
+ self.k_norm = RMSNorm(head_dim, eps=rms_norm_eps)
109
+
110
+ def _attn_mask(self, attention_mask, q_len, kv_len, past_len, device):
111
+ """Bottom-right aligned causal mask, intersected with the padding mask.
112
+
113
+ `F.scaled_dot_product_attention(is_causal=True)` aligns its mask to the
114
+ *top left*, which is only correct when `q_len == kv_len`. With a cache
115
+ the queries sit at positions `past_len .. past_len+q_len-1` while the
116
+ keys start at 0, so the mask has to be built explicitly. Returns
117
+ `(attn_mask, is_causal)` and prefers the cheap fast paths.
118
+ """
119
+ if attention_mask is None:
120
+ if kv_len == q_len:
121
+ return None, True # prefill: top-left alignment is correct
122
+ if q_len == 1:
123
+ return None, False # one new token attends to the whole cache
124
+ q_pos = torch.arange(q_len, device=device) + past_len
125
+ k_pos = torch.arange(kv_len, device=device)
126
+ mask = k_pos[None, :] <= q_pos[:, None]
127
+ mask = mask[None, None, :, :]
128
+ if attention_mask is not None:
129
+ mask = mask & attention_mask.to(torch.bool)[:, None, None, :kv_len]
130
+ # A fully-padded query row would be all-False, and SDPA turns an
131
+ # all-masked row into NaN, which then leaks through the residual
132
+ # stream into every later position. A token may always attend to
133
+ # itself, which is causally legal and keeps every row non-empty.
134
+ mask = mask | (k_pos[None, :] == q_pos[:, None])[None, None, :, :]
135
+ return mask, False
136
+
137
+ def forward(self, x, freqs_cis, attention_mask=None, past_key_values=None, past_len=0):
138
+ bsz, q_len, _ = x.size()
139
+ q = self.q_proj(x).view(bsz, q_len, self.n_head, self.head_dim).transpose(1, 2)
140
+ k = self.k_proj(x).view(bsz, q_len, self.n_kv_heads, self.head_dim).transpose(1, 2)
141
+ v = self.v_proj(x).view(bsz, q_len, self.n_kv_heads, self.head_dim).transpose(1, 2)
142
+ q = self.q_norm(q)
143
+ k = self.k_norm(k)
144
+ # `freqs_cis` is already sliced to this step's absolute positions
145
+ q, k = apply_rotary_emb(q, k, freqs_cis)
146
+
147
+ # Cache the pre-GQA-expansion states: n_kv_heads is 1 or 2 here, so
148
+ # storing the expanded copies would cost up to 4x the memory for nothing.
149
+ if past_key_values is not None:
150
+ k, v = past_key_values.update(k, v, self.layer_idx)
151
+ kv_len = k.size(-2)
152
+
153
+ k = k.unsqueeze(2).expand(bsz, self.n_kv_heads, self.n_rep, kv_len, self.head_dim)
154
+ k = k.reshape(bsz, self.n_head, kv_len, self.head_dim).contiguous()
155
+ v = v.unsqueeze(2).expand(bsz, self.n_kv_heads, self.n_rep, kv_len, self.head_dim)
156
+ v = v.reshape(bsz, self.n_head, kv_len, self.head_dim).contiguous()
157
+
158
+ attn_mask, is_causal = self._attn_mask(
159
+ attention_mask, q_len, kv_len, past_len, x.device
160
+ )
161
+ y = F.scaled_dot_product_attention(q, k, v, attn_mask=attn_mask, is_causal=is_causal)
162
+ y = y.transpose(1, 2).contiguous().view(bsz, q_len, self.n_head * self.head_dim)
163
+ return self.o_proj(y)
164
+
165
+
166
+ class TowerSwiGLUMLP(nn.Module):
167
+ def __init__(self, spec):
168
+ super().__init__()
169
+ self.w_gate = nn.Linear(spec.hidden_size, spec.intermediate_size, bias=False)
170
+ self.w_up = nn.Linear(spec.hidden_size, spec.intermediate_size, bias=False)
171
+ self.w_down = nn.Linear(spec.intermediate_size, spec.hidden_size, bias=False)
172
+
173
+ def forward(self, x):
174
+ return self.w_down(F.silu(self.w_gate(x)) * self.w_up(x))
175
+
176
+
177
+ class TowerBlock(nn.Module):
178
+ def __init__(self, spec, head_dim, rms_norm_eps, layer_idx=None):
179
+ super().__init__()
180
+ self.ln_1 = RMSNorm(spec.hidden_size, eps=rms_norm_eps)
181
+ self.attn = TowerAttention(spec, head_dim, rms_norm_eps, layer_idx=layer_idx)
182
+ self.ln_2 = RMSNorm(spec.hidden_size, eps=rms_norm_eps)
183
+ self.mlp = TowerSwiGLUMLP(spec)
184
+
185
+ def forward(self, x, freqs_cis, attention_mask=None, past_key_values=None, past_len=0):
186
+ x = x + self.attn(
187
+ self.ln_1(x),
188
+ freqs_cis,
189
+ attention_mask=attention_mask,
190
+ past_key_values=past_key_values,
191
+ past_len=past_len,
192
+ )
193
+ x = x + self.mlp(self.ln_2(x))
194
+ return x
195
+
196
+
197
+ class Edge(nn.Module):
198
+ def __init__(self, dim_in, dim_out, gate_init=0.01):
199
+ super().__init__()
200
+ self.w = nn.Linear(dim_in, dim_out, bias=False)
201
+ self.g = nn.Parameter(torch.full((dim_out,), float(gate_init)))
202
+
203
+ def forward(self, x):
204
+ return self.g * self.w(x)
205
+
206
+
207
+ class RelayMode:
208
+ """Which towers run, whether the bridges carry, and which heads vote.
209
+
210
+ The point of the 2.1 topology is that A and C have no direct path to each
211
+ other, so "what is the relay worth?" is only answerable by ablation. Each
212
+ mode below cuts the model somewhere different; every one of them runs on the
213
+ same weights, with no retraining and no reloading.
214
+
215
+ ``run_b=False`` with ``bridges=True`` is the interesting one: tower B's
216
+ blocks are replaced by the identity, but the bridge wiring stays live, so A
217
+ and C still exchange signal - through a channel that does no computation.
218
+ That separates "the relay computes something" from "a channel exists at all".
219
+ """
220
+
221
+ __slots__ = ("name", "run_a", "run_b", "run_c", "bridges", "head_a", "head_c", "doc")
222
+
223
+ def __init__(self, name, run_a, run_b, run_c, bridges, head_a, head_c, doc):
224
+ self.name = name
225
+ self.run_a, self.run_b, self.run_c = run_a, run_b, run_c
226
+ self.bridges = bridges
227
+ self.head_a, self.head_c = head_a, head_c
228
+ self.doc = doc
229
+
230
+ @property
231
+ def two_headed(self):
232
+ return self.head_a and self.head_c
233
+
234
+
235
+ RELAY_MODES = {
236
+ m.name: m
237
+ for m in (
238
+ RelayMode("full", True, True, True, True, True, True,
239
+ "the model as trained: three towers, all bridges, both heads mixed"),
240
+ RelayMode("cut_bridges", True, True, True, False, True, True,
241
+ "all 12 bridges severed; A and C become standalone transformers, "
242
+ "B is orphaned; the two heads are still mixed"),
243
+ RelayMode("bypass_b", True, False, True, True, True, True,
244
+ "B's 5 blocks are skipped but every bridge stays live: A and C "
245
+ "still exchange, through a relay that does no computation"),
246
+ RelayMode("ab_only", True, True, False, True, True, False,
247
+ "tower C is switched off; A and B run with the A<->B bridges "
248
+ "live; head A alone produces the distribution"),
249
+ RelayMode("cb_only", False, True, True, True, False, True,
250
+ "tower A is switched off; C and B run with the C<->B bridges "
251
+ "live; head C alone produces the distribution"),
252
+ RelayMode("a_only", True, False, False, False, True, False,
253
+ "tower A alone, no bridges, head A alone"),
254
+ RelayMode("c_only", False, False, True, False, False, True,
255
+ "tower C alone, no bridges, head C alone"),
256
+ )
257
+ }
258
+
259
+ _SINGLE_TOWER_MODES = {"a": "a_only", "c": "c_only"}
260
+
261
+
262
+ def resolve_relay_mode(relay_mode=None, use_single_tower=None, cut_bridges=False):
263
+ """Fold the three user-facing switches into exactly one `RelayMode`.
264
+
265
+ They overlap on purpose - `cut_bridges` predates the others and stays
266
+ supported - so anything contradictory is rejected rather than silently
267
+ resolved in an order nobody can guess.
268
+ """
269
+ chosen = []
270
+ if relay_mode is not None:
271
+ name = str(relay_mode).lower()
272
+ if name not in RELAY_MODES:
273
+ raise ValueError(
274
+ f"unknown relay_mode {relay_mode!r}; expected one of "
275
+ f"{sorted(RELAY_MODES)}"
276
+ )
277
+ chosen.append(("relay_mode", name))
278
+ if use_single_tower is not None:
279
+ tower = str(use_single_tower).lower()
280
+ if tower not in _SINGLE_TOWER_MODES:
281
+ raise ValueError(
282
+ f"use_single_tower must be 'a' or 'c' (tower B has no output "
283
+ f"head and cannot run alone), got {use_single_tower!r}"
284
+ )
285
+ chosen.append(("use_single_tower", _SINGLE_TOWER_MODES[tower]))
286
+ if cut_bridges:
287
+ chosen.append(("cut_bridges", "cut_bridges"))
288
+
289
+ names = {name for _, name in chosen}
290
+ if len(names) > 1:
291
+ detail = ", ".join(f"{src}={name!r}" for src, name in chosen)
292
+ raise ValueError(f"conflicting relay settings: {detail}")
293
+ return RELAY_MODES[names.pop()] if names else RELAY_MODES["full"]
294
+
295
+
296
+ class BananaMind21UnifiedPreTrainedModel(PreTrainedModel):
297
+ config_class = BananaMind21UnifiedConfig
298
+ base_model_prefix = "model"
299
+ supports_gradient_checkpointing = False
300
+
301
+ def _init_weights(self, module):
302
+ if isinstance(module, nn.Linear):
303
+ torch.nn.init.normal_(module.weight, mean=0.0, std=0.02)
304
+ if module.bias is not None:
305
+ torch.nn.init.zeros_(module.bias)
306
+ elif isinstance(module, nn.Embedding):
307
+ torch.nn.init.normal_(module.weight, mean=0.0, std=0.02)
308
+
309
+
310
+ class BananaMind21UnifiedForCausalLM(BananaMind21UnifiedPreTrainedModel, GenerationMixin):
311
+ def __init__(self, config):
312
+ super().__init__(config)
313
+ self.config = config
314
+ a = _Spec(config.hidden_size_a, config.num_hidden_layers_a, config.num_attention_heads_a,
315
+ config.num_key_value_heads_a, config.intermediate_size_a)
316
+ b = _Spec(config.hidden_size_b, config.num_hidden_layers_b, config.num_attention_heads_b,
317
+ config.num_key_value_heads_b, config.intermediate_size_b)
318
+ c = _Spec(config.hidden_size_c, config.num_hidden_layers_c, config.num_attention_heads_c,
319
+ config.num_key_value_heads_c, config.intermediate_size_c)
320
+
321
+ self.wte = nn.Embedding(config.vocab_size, config.embed_width)
322
+ self.in_proj_a = nn.Linear(config.embed_width, a.hidden_size, bias=False)
323
+ self.in_proj_b = nn.Linear(config.embed_width, b.hidden_size, bias=False)
324
+
325
+ # Flat KV-cache index space over the three towers, in the order the
326
+ # config documents: A first, then B, then C. Each tower keeps its own
327
+ # cache entries; nothing is shared between them.
328
+ self._cache_offset_a = 0
329
+ self._cache_offset_b = a.num_hidden_layers
330
+ self._cache_offset_c = a.num_hidden_layers + b.num_hidden_layers
331
+
332
+ self.blocks_a = nn.ModuleList([TowerBlock(a, config.head_dim, config.rms_norm_eps,
333
+ layer_idx=self._cache_offset_a + i)
334
+ for i in range(a.num_hidden_layers)])
335
+ self.blocks_b = nn.ModuleList([TowerBlock(b, config.head_dim, config.rms_norm_eps,
336
+ layer_idx=self._cache_offset_b + i)
337
+ for i in range(b.num_hidden_layers)])
338
+ self.blocks_c = nn.ModuleList([TowerBlock(c, config.head_dim, config.rms_norm_eps,
339
+ layer_idx=self._cache_offset_c + i)
340
+ for i in range(c.num_hidden_layers)])
341
+
342
+ n = len(config.a_read)
343
+ gi = config.gate_init
344
+ self.edges_a2b = nn.ModuleList([Edge(a.hidden_size, b.hidden_size, gi) for _ in range(n)])
345
+ self.edges_c2b = nn.ModuleList([Edge(c.hidden_size, b.hidden_size, gi) for _ in range(n)])
346
+ self.edges_b2a = nn.ModuleList([Edge(b.hidden_size, a.hidden_size, gi) for _ in range(n)])
347
+ self.edges_b2c = nn.ModuleList([Edge(b.hidden_size, c.hidden_size, gi) for _ in range(n)])
348
+
349
+ self.ln_f_a = RMSNorm(a.hidden_size, eps=config.rms_norm_eps)
350
+ self.ln_f_c = RMSNorm(c.hidden_size, eps=config.rms_norm_eps)
351
+ self.lm_head_a = nn.Linear(a.hidden_size, config.vocab_size, bias=False)
352
+ self.lm_head_c = nn.Linear(c.hidden_size, config.vocab_size, bias=False)
353
+ self.mix_head = nn.Linear(a.hidden_size + c.hidden_size, 1, bias=True)
354
+
355
+ self._embd_scale = math.sqrt(config.embed_width)
356
+ self._freqs_cis_cache = None
357
+ # Validated once at construction so a bad mode fails on load, not on the
358
+ # first forward pass halfway through an evaluation sweep.
359
+ self._config_mode = resolve_relay_mode(
360
+ getattr(config, "relay_mode", None),
361
+ getattr(config, "use_single_tower", None),
362
+ getattr(config, "cut_bridges", False),
363
+ )
364
+ self.post_init()
365
+
366
+ @property
367
+ def relay_mode(self):
368
+ """The `RelayMode` this model runs in unless a call overrides it."""
369
+ return self._config_mode
370
+
371
+ def set_relay_mode(self, relay_mode=None, use_single_tower=None):
372
+ """Switch ablation mode in place, for sweeping without reloading.
373
+
374
+ Returns the resolved `RelayMode`. Any KV cache built under the previous
375
+ mode is invalid afterwards - the towers it holds state for may no longer
376
+ be the towers that run - so start a fresh cache after calling this.
377
+ """
378
+ mode = resolve_relay_mode(relay_mode, use_single_tower)
379
+ self._config_mode = mode
380
+ self.config.relay_mode = mode.name
381
+ self.config.use_single_tower = None
382
+ self.config.cut_bridges = mode.name == "cut_bridges"
383
+ return mode
384
+
385
+ def get_input_embeddings(self):
386
+ return self.wte
387
+
388
+ def set_input_embeddings(self, value):
389
+ self.wte = value
390
+
391
+ def get_output_embeddings(self):
392
+ return self.lm_head_c
393
+
394
+ def resolve_mode(self, relay_mode=None, use_single_tower=None):
395
+ """The `RelayMode` in force, per-call arguments overriding the config."""
396
+ if relay_mode is None and use_single_tower is None:
397
+ return self._config_mode
398
+ return resolve_relay_mode(relay_mode, use_single_tower)
399
+
400
+ def prepare_inputs_for_generation(
401
+ self, input_ids, past_key_values=None, attention_mask=None, use_cache=True,
402
+ relay_mode=None, use_single_tower=None, **kwargs
403
+ ):
404
+ # With a warm cache only the tokens the towers have not seen yet need to
405
+ # be forwarded. Every live tower advances over the same positions, so
406
+ # one probed cache length describes all of them.
407
+ mode = self.resolve_mode(relay_mode, use_single_tower)
408
+ past_len = self._cache_len(past_key_values, mode)
409
+ if past_len > 0:
410
+ input_ids = input_ids[:, past_len:]
411
+ out = {
412
+ "input_ids": input_ids,
413
+ "attention_mask": attention_mask,
414
+ "past_key_values": past_key_values,
415
+ "use_cache": use_cache,
416
+ }
417
+ # Only forward an explicit override; otherwise the config mode applies.
418
+ if relay_mode is not None:
419
+ out["relay_mode"] = relay_mode
420
+ if use_single_tower is not None:
421
+ out["use_single_tower"] = use_single_tower
422
+ return out
423
+
424
+ def _get_freqs_cis(self, seq_len, device):
425
+ cache = self._freqs_cis_cache
426
+ if cache is None or cache.device != device or cache.size(0) < seq_len:
427
+ cache = precompute_freqs_cis(
428
+ self.config.head_dim, seq_len, self.config.rope_theta
429
+ ).to(device)
430
+ self._freqs_cis_cache = cache
431
+ return cache[:seq_len]
432
+
433
+ @staticmethod
434
+ def _advance(blocks, x, cursor, target, freqs_cis, pending, attention_mask,
435
+ past_key_values=None, past_len=0, run_blocks=True):
436
+ """Run `blocks[cursor:target]`, folding in bridge arrivals as they land.
437
+
438
+ With `run_blocks=False` the blocks are replaced by the identity but the
439
+ arrivals are still added and the cursor still advances, which is what
440
+ turns tower B into a pass-through channel in `bypass_b`.
441
+ """
442
+ while cursor < target:
443
+ arriving = pending.pop(cursor + 1, None)
444
+ if arriving is not None:
445
+ x = x + arriving
446
+ if run_blocks:
447
+ x = blocks[cursor](
448
+ x,
449
+ freqs_cis,
450
+ attention_mask=attention_mask,
451
+ past_key_values=past_key_values,
452
+ past_len=past_len,
453
+ )
454
+ cursor += 1
455
+ return x, cursor
456
+
457
+ def _cache_probe_idx(self, mode):
458
+ """Flat cache index of the first block that actually runs in `mode`.
459
+
460
+ `Cache.get_seq_length()` defaults to layer 0, which is tower A's first
461
+ block - but A does not run in every mode, and an untouched layer reports
462
+ length 0 forever. Probing a layer that really runs keeps the cache
463
+ length honest under every ablation.
464
+ """
465
+ if mode.run_a:
466
+ return self._cache_offset_a
467
+ if mode.run_b:
468
+ return self._cache_offset_b
469
+ return self._cache_offset_c
470
+
471
+ def _cache_len(self, past_key_values, mode):
472
+ if past_key_values is None:
473
+ return 0
474
+ return past_key_values.get_seq_length(self._cache_probe_idx(mode))
475
+
476
+ def hidden_states(self, input_ids, attention_mask=None, past_key_values=None,
477
+ relay_mode=None, use_single_tower=None):
478
+ """Run the towers and return `(h_a, h_c, mix_logit)`.
479
+
480
+ A tower switched off by the active mode returns `None` in its slot, and
481
+ `mix_logit` is `None` whenever only one head is live - there is nothing
482
+ for the mixer to weigh. In the default `full` mode all three are always
483
+ tensors, so existing callers are unaffected.
484
+ """
485
+ cfg = self.config
486
+ mode = self.resolve_mode(relay_mode, use_single_tower)
487
+ _, seq_len = input_ids.size()
488
+ # Read the cache length once, before any layer writes to it.
489
+ past_len = self._cache_len(past_key_values, mode)
490
+ # RoPE is applied at absolute positions, so a cached run has to skip the
491
+ # `past_len` entries the earlier tokens already used.
492
+ freqs_cis = self._get_freqs_cis(past_len + seq_len, input_ids.device)[past_len:]
493
+
494
+ embedded = self.wte(input_ids) * self._embd_scale
495
+ x_a = self.in_proj_a(embedded) if mode.run_a else None
496
+ x_b = self.in_proj_b(embedded) if (mode.run_b or mode.bridges) else None
497
+ x_c = embedded if mode.run_c else None
498
+
499
+ pend_a, pend_b, pend_c = {}, {}, {}
500
+ cur_a = cur_b = cur_c = 0
501
+ kv = dict(past_key_values=past_key_values, past_len=past_len)
502
+ step_a = dict(kv, run_blocks=mode.run_a)
503
+ step_b = dict(kv, run_blocks=mode.run_b)
504
+ step_c = dict(kv, run_blocks=mode.run_c)
505
+
506
+ # A bridge is only carried when both of its endpoints are live: in
507
+ # `ab_only` there is no tower C to read from or write back to, so the
508
+ # C-side edges are skipped rather than fed zeros.
509
+ carry_a = mode.bridges and mode.run_a
510
+ carry_c = mode.bridges and mode.run_c
511
+ relay_live = mode.bridges and x_b is not None
512
+
513
+ # An `Edge` is a per-channel gate on a linear map, so a bridge mixes
514
+ # channels but never positions. Every bridge contribution for the new
515
+ # tokens is therefore computable from the new tokens' own tower states,
516
+ # and no bridge output needs to be cached alongside the KV states.
517
+ for k in range(len(cfg.a_read)):
518
+ if x_a is not None:
519
+ x_a, cur_a = self._advance(self.blocks_a, x_a, cur_a, cfg.a_read[k],
520
+ freqs_cis, pend_a, attention_mask, **step_a)
521
+ if x_c is not None:
522
+ x_c, cur_c = self._advance(self.blocks_c, x_c, cur_c, cfg.c_read[k],
523
+ freqs_cis, pend_c, attention_mask, **step_c)
524
+ if relay_live:
525
+ into_b = None
526
+ if carry_a:
527
+ into_b = self.edges_a2b[k](x_a)
528
+ if carry_c:
529
+ contrib = self.edges_c2b[k](x_c)
530
+ into_b = contrib if into_b is None else into_b + contrib
531
+ if into_b is not None:
532
+ pend_b[cfg.b_land[k]] = into_b
533
+ if x_b is not None:
534
+ x_b, cur_b = self._advance(self.blocks_b, x_b, cur_b, cfg.b_read[k],
535
+ freqs_cis, pend_b, attention_mask, **step_b)
536
+ if relay_live:
537
+ if carry_a:
538
+ pend_a[cfg.a_land[k]] = self.edges_b2a[k](x_b)
539
+ if carry_c:
540
+ pend_c[cfg.c_land[k]] = self.edges_b2c[k](x_b)
541
+
542
+ if x_a is not None:
543
+ x_a, _ = self._advance(self.blocks_a, x_a, cur_a, cfg.num_hidden_layers_a,
544
+ freqs_cis, pend_a, attention_mask, **step_a)
545
+ if x_c is not None:
546
+ x_c, _ = self._advance(self.blocks_c, x_c, cur_c, cfg.num_hidden_layers_c,
547
+ freqs_cis, pend_c, attention_mask, **step_c)
548
+ if x_b is not None:
549
+ x_b, _ = self._advance(self.blocks_b, x_b, cur_b, cfg.num_hidden_layers_b,
550
+ freqs_cis, pend_b, attention_mask, **step_b)
551
+
552
+ h_a = self.ln_f_a(x_a) if x_a is not None else None
553
+ h_c = self.ln_f_c(x_c) if x_c is not None else None
554
+ mix_logit = None
555
+ if mode.two_headed:
556
+ mix_logit = self.mix_head(torch.cat([h_a, h_c], dim=-1)).squeeze(-1)
557
+ return h_a, h_c, mix_logit
558
+
559
+ def forward(
560
+ self,
561
+ input_ids,
562
+ attention_mask=None,
563
+ labels=None,
564
+ past_key_values: Optional[Cache] = None,
565
+ use_cache: Optional[bool] = None,
566
+ relay_mode=None,
567
+ use_single_tower=None,
568
+ **kwargs,
569
+ ):
570
+ mode = self.resolve_mode(relay_mode, use_single_tower)
571
+
572
+ if use_cache is None:
573
+ use_cache = getattr(self.config, "use_cache", True)
574
+ if labels is not None:
575
+ # A scoring or training pass consumes the whole sequence in one go
576
+ # and throws the states away, so building 25 layers of cache is pure
577
+ # overhead. An explicitly supplied cache is still honoured.
578
+ use_cache = use_cache and past_key_values is not None
579
+ if use_cache and past_key_values is None:
580
+ past_key_values = DynamicCache(config=self.config)
581
+ if not use_cache:
582
+ past_key_values = None
583
+
584
+ h_a, h_c, mix_logit = self.hidden_states(
585
+ input_ids,
586
+ attention_mask=attention_mask,
587
+ past_key_values=past_key_values,
588
+ relay_mode=mode.name,
589
+ )
590
+
591
+ # With one head live there is nothing to mix, and `log_softmax` alone
592
+ # already gives the normalised log-probability vector `.logits` promises.
593
+ if mode.two_headed:
594
+ log_p_a = F.log_softmax(self.lm_head_a(h_a).float(), dim=-1)
595
+ log_p_c = F.log_softmax(self.lm_head_c(h_c).float(), dim=-1)
596
+ log_alpha = F.logsigmoid(mix_logit).unsqueeze(-1)
597
+ log_one_minus = F.logsigmoid(-mix_logit).unsqueeze(-1)
598
+ log_p = torch.logaddexp(log_alpha + log_p_a, log_one_minus + log_p_c)
599
+ elif mode.head_a:
600
+ log_p = F.log_softmax(self.lm_head_a(h_a).float(), dim=-1)
601
+ else:
602
+ log_p = F.log_softmax(self.lm_head_c(h_c).float(), dim=-1)
603
+
604
+ loss = None
605
+ if labels is not None:
606
+ loss = F.nll_loss(
607
+ log_p[..., :-1, :].reshape(-1, log_p.size(-1)),
608
+ labels[..., 1:].reshape(-1),
609
+ )
610
+ return CausalLMOutputWithPast(loss=loss, logits=log_p, past_key_values=past_key_values)
modeling_relay.py ADDED
@@ -0,0 +1,680 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """BananaMind 2.1 Unified - three towers, relay middle, 35.0M params.
3
+
4
+ Three independent transformer stacks share one input embedding. A and C are
5
+ the outer towers; each owns an output head and contributes to the mixture. B is
6
+ the relay: it has no head, no solo loss term, and no gradient of its own except
7
+ what arrives through its four bridge directions. There is no direct A<->C path,
8
+ so anything the two outer towers share about a token has to survive a trip
9
+ through B.
10
+
11
+ Exchange schedule
12
+ -----------------
13
+ Three rounds. Each round reads the outer towers, lands the sum in B, lets B
14
+ process, then reads B and lands the result back in both outer towers.
15
+
16
+ round | A read | C read | -> B | B runs | B read | -> A | -> C
17
+ 1 | 5 | 2 | pre-1 | 1-2 | 2 | 7 | 3
18
+ 2 | 9 | 4 | pre-3 | 3-4 | 4 | 11 | 5
19
+ 3 | 12 | 5 | pre-5 | 5 | 5 | 14 | 6
20
+
21
+ Bridge output is added to the residual *before* the receiving block rather than
22
+ after it, which is what guarantees B always has at least one full block between
23
+ taking a signal in and handing one back out.
24
+
25
+ Gates are per-channel and initialise to 0.01, not 0. B is the only path between
26
+ A and C and it carries no solo loss, so a zero-init would leave the middle with
27
+ no gradient signal at all on step 0 and a real chance of never waking up. 0.01
28
+ is small enough that the towers still start as three near-independent models.
29
+ """
30
+ from __future__ import annotations
31
+
32
+ import math
33
+ from dataclasses import dataclass, field
34
+
35
+ import torch
36
+ import torch.nn as nn
37
+ import torch.nn.functional as F
38
+
39
+
40
+ # --------------------------------------------------------------------------- #
41
+ # config
42
+ # --------------------------------------------------------------------------- #
43
+
44
+
45
+ @dataclass
46
+ class TowerSpec:
47
+ hidden_size: int
48
+ num_hidden_layers: int
49
+ num_attention_heads: int
50
+ num_key_value_heads: int
51
+ intermediate_size: int
52
+
53
+
54
+ @dataclass
55
+ class RelayConfig:
56
+ # inherited from Mini / 2.0 Unified, unchanged
57
+ vocab_size: int = 8192
58
+ head_dim: int = 64
59
+ max_position_embeddings: int = 4096
60
+ rope_theta: float = 100000.0
61
+ rms_norm_eps: float = 1e-6
62
+
63
+ # the shared embedding lives at tower C's width, so C reads it natively and
64
+ # A and B each get one projection down.
65
+ embed_width: int = 384
66
+
67
+ tower_a: TowerSpec = field(
68
+ default_factory=lambda: TowerSpec(
69
+ hidden_size=256,
70
+ num_hidden_layers=14,
71
+ num_attention_heads=4,
72
+ num_key_value_heads=1,
73
+ intermediate_size=704,
74
+ )
75
+ )
76
+ tower_b: TowerSpec = field(
77
+ default_factory=lambda: TowerSpec(
78
+ hidden_size=320,
79
+ num_hidden_layers=5,
80
+ num_attention_heads=5,
81
+ num_key_value_heads=1,
82
+ intermediate_size=960,
83
+ )
84
+ )
85
+ tower_c: TowerSpec = field(
86
+ default_factory=lambda: TowerSpec(
87
+ hidden_size=384,
88
+ num_hidden_layers=6,
89
+ num_attention_heads=6,
90
+ num_key_value_heads=2,
91
+ intermediate_size=1024,
92
+ )
93
+ )
94
+
95
+ # 1-indexed exchange schedule. `*_read` is where a bridge takes a tower's
96
+ # state; `*_land` is where the returning signal is added. Biased deep on
97
+ # the outer towers, because in the 2.0 run the deep bridges carried 4-25x
98
+ # the gate magnitude of the shallow ones.
99
+ a_read: tuple[int, ...] = (5, 9, 12)
100
+ a_land: tuple[int, ...] = (7, 11, 14)
101
+ c_read: tuple[int, ...] = (2, 4, 5)
102
+ c_land: tuple[int, ...] = (3, 5, 6)
103
+ b_land: tuple[int, ...] = (1, 3, 5)
104
+ b_read: tuple[int, ...] = (2, 4, 5)
105
+
106
+ gate_init: float = 0.01
107
+
108
+ # untied on purpose: A and C each own an output space, so either one still
109
+ # decodes by itself once the bridges come off.
110
+ tie_word_embeddings: bool = False
111
+
112
+ @property
113
+ def n_rounds(self) -> int:
114
+ return len(self.a_read)
115
+
116
+ def validate(self) -> None:
117
+ if self.embed_width != self.tower_c.hidden_size:
118
+ raise ValueError("shared embedding width must match tower C width")
119
+ n = self.n_rounds
120
+ for name in ("a_read", "a_land", "c_read", "c_land", "b_land", "b_read"):
121
+ if len(getattr(self, name)) != n:
122
+ raise ValueError(f"{name} must have {n} entries")
123
+
124
+ # Every tower is visited strictly left to right, and every bridge reads
125
+ # a state that already exists. If this passes, the forward pass below
126
+ # is a valid topological order.
127
+ for read, land, spec, tag in (
128
+ (self.a_read, self.a_land, self.tower_a, "A"),
129
+ (self.c_read, self.c_land, self.tower_c, "C"),
130
+ ):
131
+ cursor = 0
132
+ for k in range(n):
133
+ # `==` is legal: the previous round's signal is added before that
134
+ # layer runs, so reading right after it is still causal.
135
+ if not cursor <= read[k]:
136
+ raise ValueError(f"tower {tag} round {k}: read layer {read[k]} is behind cursor {cursor}")
137
+ if not read[k] < land[k]:
138
+ raise ValueError(f"tower {tag} round {k}: land {land[k]} must follow read {read[k]}")
139
+ cursor = land[k]
140
+ if max(land) > spec.num_hidden_layers or min(read) < 1:
141
+ raise ValueError(f"tower {tag} schedule leaves the stack")
142
+
143
+ cursor = 0
144
+ for k in range(n):
145
+ if not cursor < self.b_land[k]:
146
+ raise ValueError(f"tower B round {k}: land {self.b_land[k]} is not ahead of {cursor}")
147
+ if not self.b_land[k] <= self.b_read[k]:
148
+ raise ValueError(f"tower B round {k}: read {self.b_read[k]} precedes land {self.b_land[k]}")
149
+ cursor = self.b_read[k]
150
+ if max(self.b_read) > self.tower_b.num_hidden_layers or min(self.b_land) < 1:
151
+ raise ValueError("tower B schedule leaves the stack")
152
+
153
+
154
+ # --------------------------------------------------------------------------- #
155
+ # primitives (identical to train_mini.py / 2.0 Unified)
156
+ # --------------------------------------------------------------------------- #
157
+
158
+
159
+ class RMSNorm(nn.Module):
160
+ def __init__(self, dim: int, eps: float = 1e-6):
161
+ super().__init__()
162
+ self.eps = eps
163
+ self.weight = nn.Parameter(torch.ones(dim))
164
+
165
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
166
+ x_float = x.float()
167
+ rms = torch.rsqrt(x_float.pow(2).mean(-1, keepdim=True) + self.eps)
168
+ return (x_float * rms * self.weight.float()).type_as(x)
169
+
170
+
171
+ def build_rope_inv_freq(head_dim: int, theta: float = 100000.0) -> torch.Tensor:
172
+ return 1.0 / (theta ** (torch.arange(0, head_dim, 2, dtype=torch.float32) / head_dim))
173
+
174
+
175
+ def precompute_freqs_cis(head_dim: int, seq_len: int, theta: float = 100000.0) -> torch.Tensor:
176
+ freqs = torch.outer(torch.arange(seq_len, dtype=torch.float32), build_rope_inv_freq(head_dim, theta))
177
+ return torch.polar(torch.ones_like(freqs), freqs)
178
+
179
+
180
+ def apply_rotary_emb(
181
+ q: torch.Tensor, k: torch.Tensor, freqs_cis: torch.Tensor
182
+ ) -> tuple[torch.Tensor, torch.Tensor]:
183
+ q_complex = torch.view_as_complex(q.float().reshape(*q.shape[:-1], -1, 2))
184
+ k_complex = torch.view_as_complex(k.float().reshape(*k.shape[:-1], -1, 2))
185
+ freqs_cis = freqs_cis.unsqueeze(0).unsqueeze(0)
186
+ q_out = torch.view_as_real(q_complex * freqs_cis).flatten(-2)
187
+ k_out = torch.view_as_real(k_complex * freqs_cis).flatten(-2)
188
+ return q_out.type_as(q), k_out.type_as(k)
189
+
190
+
191
+ class TowerAttention(nn.Module):
192
+ def __init__(self, spec: TowerSpec, head_dim: int, rms_norm_eps: float):
193
+ super().__init__()
194
+ self.n_head = spec.num_attention_heads
195
+ self.n_kv_heads = spec.num_key_value_heads
196
+ self.head_dim = head_dim
197
+ self.n_rep = self.n_head // self.n_kv_heads
198
+
199
+ self.q_proj = nn.Linear(spec.hidden_size, self.n_head * head_dim, bias=False)
200
+ self.k_proj = nn.Linear(spec.hidden_size, self.n_kv_heads * head_dim, bias=False)
201
+ self.v_proj = nn.Linear(spec.hidden_size, self.n_kv_heads * head_dim, bias=False)
202
+ self.o_proj = nn.Linear(self.n_head * head_dim, spec.hidden_size, bias=False)
203
+ self.o_proj.NANOGPT_SCALE_INIT = 1
204
+
205
+ self.q_norm = RMSNorm(head_dim, eps=rms_norm_eps)
206
+ self.k_norm = RMSNorm(head_dim, eps=rms_norm_eps)
207
+
208
+ def forward(self, x: torch.Tensor, freqs_cis: torch.Tensor) -> torch.Tensor:
209
+ bsz, seq_len, _ = x.size()
210
+
211
+ q = self.q_proj(x).view(bsz, seq_len, self.n_head, self.head_dim).transpose(1, 2)
212
+ k = self.k_proj(x).view(bsz, seq_len, self.n_kv_heads, self.head_dim).transpose(1, 2)
213
+ v = self.v_proj(x).view(bsz, seq_len, self.n_kv_heads, self.head_dim).transpose(1, 2)
214
+
215
+ q = self.q_norm(q)
216
+ k = self.k_norm(k)
217
+ q, k = apply_rotary_emb(q, k, freqs_cis)
218
+
219
+ # .contiguous() is required for torch.compile: without it the expanded
220
+ # view reaches the flash-attention backward with strides Inductor
221
+ # rejects. Pure layout change, no effect on the math.
222
+ k = (
223
+ k.unsqueeze(2)
224
+ .expand(bsz, self.n_kv_heads, self.n_rep, seq_len, self.head_dim)
225
+ .reshape(bsz, self.n_head, seq_len, self.head_dim)
226
+ .contiguous()
227
+ )
228
+ v = (
229
+ v.unsqueeze(2)
230
+ .expand(bsz, self.n_kv_heads, self.n_rep, seq_len, self.head_dim)
231
+ .reshape(bsz, self.n_head, seq_len, self.head_dim)
232
+ .contiguous()
233
+ )
234
+
235
+ y = F.scaled_dot_product_attention(q, k, v, is_causal=True)
236
+ y = y.transpose(1, 2).contiguous().view(bsz, seq_len, self.n_head * self.head_dim)
237
+ return self.o_proj(y)
238
+
239
+
240
+ class TowerSwiGLUMLP(nn.Module):
241
+ def __init__(self, spec: TowerSpec):
242
+ super().__init__()
243
+ self.w_gate = nn.Linear(spec.hidden_size, spec.intermediate_size, bias=False)
244
+ self.w_up = nn.Linear(spec.hidden_size, spec.intermediate_size, bias=False)
245
+ self.w_down = nn.Linear(spec.intermediate_size, spec.hidden_size, bias=False)
246
+ self.w_down.NANOGPT_SCALE_INIT = 1
247
+
248
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
249
+ return self.w_down(F.silu(self.w_gate(x)) * self.w_up(x))
250
+
251
+
252
+ class TowerBlock(nn.Module):
253
+ """A plain Mini block. Nothing in here knows about bridges."""
254
+
255
+ def __init__(self, spec: TowerSpec, head_dim: int, rms_norm_eps: float):
256
+ super().__init__()
257
+ self.ln_1 = RMSNorm(spec.hidden_size, eps=rms_norm_eps)
258
+ self.attn = TowerAttention(spec, head_dim, rms_norm_eps)
259
+ self.ln_2 = RMSNorm(spec.hidden_size, eps=rms_norm_eps)
260
+ self.mlp = TowerSwiGLUMLP(spec)
261
+
262
+ def forward(self, x: torch.Tensor, freqs_cis: torch.Tensor) -> torch.Tensor:
263
+ x = x + self.attn(self.ln_1(x), freqs_cis)
264
+ x = x + self.mlp(self.ln_2(x))
265
+ return x
266
+
267
+
268
+ # --------------------------------------------------------------------------- #
269
+ # bridge
270
+ # --------------------------------------------------------------------------- #
271
+
272
+
273
+ class Edge(nn.Module):
274
+ """One direction of one exchange point.
275
+
276
+ W is a plain linear, g a per-channel gate. The gate starts small but not
277
+ zero so the relay gets traffic on step 0.
278
+ """
279
+
280
+ def __init__(self, dim_in: int, dim_out: int, gate_init: float):
281
+ super().__init__()
282
+ self.w = nn.Linear(dim_in, dim_out, bias=False)
283
+ self.g = nn.Parameter(torch.full((dim_out,), float(gate_init)))
284
+
285
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
286
+ return self.g * self.w(x)
287
+
288
+
289
+ # --------------------------------------------------------------------------- #
290
+ # model
291
+ # --------------------------------------------------------------------------- #
292
+
293
+
294
+ class BananaMindRelay(nn.Module):
295
+ def __init__(self, config: RelayConfig):
296
+ super().__init__()
297
+ config.validate()
298
+ self.config = config
299
+ a, b, c = config.tower_a, config.tower_b, config.tower_c
300
+
301
+ self.wte = nn.Embedding(config.vocab_size, config.embed_width)
302
+ self.in_proj_a = nn.Linear(config.embed_width, a.hidden_size, bias=False)
303
+ self.in_proj_b = nn.Linear(config.embed_width, b.hidden_size, bias=False)
304
+ # tower C reads the shared embedding natively; no projection
305
+
306
+ self.blocks_a = nn.ModuleList(
307
+ [TowerBlock(a, config.head_dim, config.rms_norm_eps) for _ in range(a.num_hidden_layers)]
308
+ )
309
+ self.blocks_b = nn.ModuleList(
310
+ [TowerBlock(b, config.head_dim, config.rms_norm_eps) for _ in range(b.num_hidden_layers)]
311
+ )
312
+ self.blocks_c = nn.ModuleList(
313
+ [TowerBlock(c, config.head_dim, config.rms_norm_eps) for _ in range(c.num_hidden_layers)]
314
+ )
315
+
316
+ n = config.n_rounds
317
+ gi = config.gate_init
318
+ self.edges_a2b = nn.ModuleList([Edge(a.hidden_size, b.hidden_size, gi) for _ in range(n)])
319
+ self.edges_c2b = nn.ModuleList([Edge(c.hidden_size, b.hidden_size, gi) for _ in range(n)])
320
+ self.edges_b2a = nn.ModuleList([Edge(b.hidden_size, a.hidden_size, gi) for _ in range(n)])
321
+ self.edges_b2c = nn.ModuleList([Edge(b.hidden_size, c.hidden_size, gi) for _ in range(n)])
322
+
323
+ # B has no final norm because it has no head: its only outputs are the
324
+ # bridge reads, which are normalised by the receiving tower's blocks.
325
+ self.ln_f_a = RMSNorm(a.hidden_size, eps=config.rms_norm_eps)
326
+ self.ln_f_c = RMSNorm(c.hidden_size, eps=config.rms_norm_eps)
327
+
328
+ self.lm_head_a = nn.Linear(a.hidden_size, config.vocab_size, bias=False)
329
+ self.lm_head_c = nn.Linear(c.hidden_size, config.vocab_size, bias=False)
330
+ if config.tie_word_embeddings:
331
+ self.lm_head_c.weight = self.wte.weight
332
+
333
+ # still a 2-way mixer: it reads the two towers that have heads
334
+ self.mix_head = nn.Linear(a.hidden_size + c.hidden_size, 1, bias=True)
335
+
336
+ self._embd_scale = math.sqrt(config.embed_width)
337
+ self._freqs_cis_cache: torch.Tensor | None = None
338
+
339
+ self._init_all()
340
+
341
+ # ---- init -------------------------------------------------------------- #
342
+
343
+ def _init_module(self, module: nn.Module, depth: int) -> None:
344
+ std = 0.02
345
+ if hasattr(module, "NANOGPT_SCALE_INIT"):
346
+ std *= 2 * depth**-0.5
347
+ if isinstance(module, nn.Linear):
348
+ torch.nn.init.normal_(module.weight, mean=0.0, std=std)
349
+ if module.bias is not None:
350
+ torch.nn.init.zeros_(module.bias)
351
+ elif isinstance(module, nn.Embedding):
352
+ torch.nn.init.normal_(module.weight, mean=0.0, std=0.02)
353
+
354
+ def _init_all(self) -> None:
355
+ cfg = self.config
356
+ depth_a = cfg.tower_a.num_hidden_layers
357
+ depth_b = cfg.tower_b.num_hidden_layers
358
+ depth_c = cfg.tower_c.num_hidden_layers
359
+
360
+ for blocks, depth in (
361
+ (self.blocks_a, depth_a),
362
+ (self.blocks_b, depth_b),
363
+ (self.blocks_c, depth_c),
364
+ ):
365
+ for m in blocks.modules():
366
+ self._init_module(m, depth)
367
+
368
+ for m in (
369
+ self.wte,
370
+ self.in_proj_a,
371
+ self.in_proj_b,
372
+ self.lm_head_a,
373
+ self.lm_head_c,
374
+ self.mix_head,
375
+ ):
376
+ self._init_module(m, depth_a)
377
+
378
+ for edges, depth in (
379
+ (self.edges_a2b, depth_b),
380
+ (self.edges_c2b, depth_b),
381
+ (self.edges_b2a, depth_a),
382
+ (self.edges_b2c, depth_c),
383
+ ):
384
+ for edge in edges:
385
+ self._init_module(edge.w, depth)
386
+ torch.nn.init.constant_(edge.g, cfg.gate_init)
387
+
388
+ # start the mixer at alpha = 0.5 so neither outer tower is favoured
389
+ torch.nn.init.zeros_(self.mix_head.weight)
390
+ torch.nn.init.zeros_(self.mix_head.bias)
391
+
392
+ # ---- rope cache -------------------------------------------------------- #
393
+
394
+ def _get_freqs_cis(self, seq_len: int, device: torch.device) -> torch.Tensor:
395
+ cache = self._freqs_cis_cache
396
+ if cache is None or cache.device != device or cache.size(0) < seq_len:
397
+ cache = precompute_freqs_cis(
398
+ self.config.head_dim, seq_len, self.config.rope_theta
399
+ ).to(device)
400
+ self._freqs_cis_cache = cache
401
+ return cache[:seq_len]
402
+
403
+ # ---- forward ----------------------------------------------------------- #
404
+
405
+ @staticmethod
406
+ def _advance(
407
+ blocks: nn.ModuleList,
408
+ x: torch.Tensor,
409
+ cursor: int,
410
+ target: int,
411
+ freqs_cis: torch.Tensor,
412
+ pending: dict[int, torch.Tensor],
413
+ ) -> tuple[torch.Tensor, int]:
414
+ """Run `blocks` from `cursor` up to and including 1-indexed `target`.
415
+
416
+ A pending bridge value keyed by a 1-indexed layer is added to the
417
+ residual immediately before that layer runs.
418
+ """
419
+ while cursor < target:
420
+ layer = cursor + 1
421
+ arriving = pending.pop(layer, None)
422
+ if arriving is not None:
423
+ x = x + arriving
424
+ x = blocks[cursor](x, freqs_cis)
425
+ cursor += 1
426
+ return x, cursor
427
+
428
+ def forward(
429
+ self,
430
+ input_ids: torch.Tensor,
431
+ cut_bridges: bool = False,
432
+ collect_diagnostics: bool = False,
433
+ ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, dict]:
434
+ """Returns (h_a, h_c, mix_logit, diagnostics).
435
+
436
+ With `cut_bridges=True` the three stacks run completely independently:
437
+ A and C become ordinary transformers and B becomes dead weight that
438
+ influences nothing.
439
+ """
440
+ cfg = self.config
441
+ _, seq_len = input_ids.size()
442
+ freqs_cis = self._get_freqs_cis(seq_len, input_ids.device)
443
+
444
+ embedded = self.wte(input_ids) * self._embd_scale
445
+ x_a = self.in_proj_a(embedded)
446
+ x_b = self.in_proj_b(embedded)
447
+ x_c = embedded
448
+
449
+ pend_a: dict[int, torch.Tensor] = {}
450
+ pend_b: dict[int, torch.Tensor] = {}
451
+ pend_c: dict[int, torch.Tensor] = {}
452
+ cur_a = cur_b = cur_c = 0
453
+ diagnostics: dict = {}
454
+
455
+ for k in range(cfg.n_rounds):
456
+ # 1. outer towers walk to their read points, applying whatever the
457
+ # previous round handed them on the way.
458
+ x_a, cur_a = self._advance(self.blocks_a, x_a, cur_a, cfg.a_read[k], freqs_cis, pend_a)
459
+ x_c, cur_c = self._advance(self.blocks_c, x_c, cur_c, cfg.c_read[k], freqs_cis, pend_c)
460
+
461
+ # 2. both outer signals land in the relay at the same layer.
462
+ if not cut_bridges:
463
+ pend_b[cfg.b_land[k]] = self.edges_a2b[k](x_a) + self.edges_c2b[k](x_c)
464
+
465
+ # 3. the relay processes, then hands one signal back to each side.
466
+ x_b, cur_b = self._advance(self.blocks_b, x_b, cur_b, cfg.b_read[k], freqs_cis, pend_b)
467
+
468
+ if not cut_bridges:
469
+ pend_a[cfg.a_land[k]] = self.edges_b2a[k](x_b)
470
+ pend_c[cfg.c_land[k]] = self.edges_b2c[k](x_b)
471
+
472
+ if collect_diagnostics:
473
+ with torch.no_grad():
474
+ fa, fb, fc = x_a.float(), x_b.float(), x_c.float()
475
+ diagnostics[f"cos_a2b/round{k}"] = float(
476
+ F.cosine_similarity(self.edges_a2b[k].w(fa), fb, dim=-1).mean()
477
+ )
478
+ diagnostics[f"cos_c2b/round{k}"] = float(
479
+ F.cosine_similarity(self.edges_c2b[k].w(fc), fb, dim=-1).mean()
480
+ )
481
+ diagnostics[f"cos_b2a/round{k}"] = float(
482
+ F.cosine_similarity(self.edges_b2a[k].w(fb), fa, dim=-1).mean()
483
+ )
484
+ diagnostics[f"cos_b2c/round{k}"] = float(
485
+ F.cosine_similarity(self.edges_b2c[k].w(fb), fc, dim=-1).mean()
486
+ )
487
+ # how much of A survives the trip to C and back through B
488
+ diagnostics[f"rms_a/round{k}"] = float(fa.pow(2).mean().sqrt())
489
+ diagnostics[f"rms_b/round{k}"] = float(fb.pow(2).mean().sqrt())
490
+ diagnostics[f"rms_c/round{k}"] = float(fc.pow(2).mean().sqrt())
491
+
492
+ # 4. finish every stack
493
+ x_a, cur_a = self._advance(
494
+ self.blocks_a, x_a, cur_a, cfg.tower_a.num_hidden_layers, freqs_cis, pend_a
495
+ )
496
+ x_c, cur_c = self._advance(
497
+ self.blocks_c, x_c, cur_c, cfg.tower_c.num_hidden_layers, freqs_cis, pend_c
498
+ )
499
+ # B's tail runs only so its parameters see gradient in later rounds; with
500
+ # the default schedule B is already finished here.
501
+ x_b, cur_b = self._advance(
502
+ self.blocks_b, x_b, cur_b, cfg.tower_b.num_hidden_layers, freqs_cis, pend_b
503
+ )
504
+
505
+ if pend_a or pend_b or pend_c:
506
+ raise RuntimeError(f"bridge values were never consumed: {sorted(pend_a) + sorted(pend_b) + sorted(pend_c)}")
507
+
508
+ h_a = self.ln_f_a(x_a)
509
+ h_c = self.ln_f_c(x_c)
510
+ mix_logit = self.mix_head(torch.cat([h_a, h_c], dim=-1)).squeeze(-1)
511
+ return h_a, h_c, mix_logit, diagnostics
512
+
513
+ # ---- diagnostics ------------------------------------------------------- #
514
+
515
+ @torch.no_grad()
516
+ def gate_stats(self) -> dict[str, float]:
517
+ """Per-round, per-direction gate magnitudes."""
518
+ cfg = self.config
519
+ stats: dict[str, float] = {}
520
+ groups = (
521
+ ("a2b", self.edges_a2b, cfg.b_land),
522
+ ("c2b", self.edges_c2b, cfg.b_land),
523
+ ("b2a", self.edges_b2a, cfg.a_land),
524
+ ("b2c", self.edges_b2c, cfg.c_land),
525
+ )
526
+ for name, edges, layers in groups:
527
+ for i, edge in enumerate(edges):
528
+ g = edge.g.detach().float()
529
+ stats[f"gate_{name}/L{layers[i]}_absmean"] = float(g.abs().mean())
530
+ stats[f"gate_{name}/L{layers[i]}_absmax"] = float(g.abs().max())
531
+ stats[f"gate_{name}/L{layers[i]}_rms"] = float(g.pow(2).mean().sqrt())
532
+ return stats
533
+
534
+ # ---- parameter accounting ---------------------------------------------- #
535
+
536
+ def param_breakdown(self) -> dict[str, int]:
537
+ def n(module: nn.Module) -> int:
538
+ return sum(p.numel() for p in module.parameters())
539
+
540
+ bridges = sum(n(e) for e in (self.edges_a2b, self.edges_c2b, self.edges_b2a, self.edges_b2c))
541
+ return {
542
+ "shared_embedding": n(self.wte),
543
+ "in_proj_384_to_256": n(self.in_proj_a),
544
+ "in_proj_384_to_320": n(self.in_proj_b),
545
+ "tower_a_layers": n(self.blocks_a),
546
+ "tower_b_layers": n(self.blocks_b),
547
+ "tower_c_layers": n(self.blocks_c),
548
+ "bridges": bridges,
549
+ "ln_f_a": n(self.ln_f_a),
550
+ "ln_f_c": n(self.ln_f_c),
551
+ "lm_head_a": n(self.lm_head_a),
552
+ "lm_head_c": n(self.lm_head_c),
553
+ "mix_head": n(self.mix_head),
554
+ "total": sum(p.numel() for p in self.parameters()),
555
+ }
556
+
557
+ def matmul_parameters(self) -> int:
558
+ """Total excluding norms, gates and the mixer.
559
+
560
+ This is the number the architecture is specified against: everything
561
+ that is a weight matrix, and nothing that is a per-channel scalar.
562
+ """
563
+ skip = set()
564
+ for module in self.modules():
565
+ if isinstance(module, RMSNorm):
566
+ skip.add(id(module.weight))
567
+ for edges in (self.edges_a2b, self.edges_c2b, self.edges_b2a, self.edges_b2c):
568
+ for edge in edges:
569
+ skip.add(id(edge.g))
570
+ for p in self.mix_head.parameters():
571
+ skip.add(id(p))
572
+ return sum(p.numel() for p in self.parameters() if id(p) not in skip)
573
+
574
+
575
+ # --------------------------------------------------------------------------- #
576
+ # loss
577
+ # --------------------------------------------------------------------------- #
578
+
579
+
580
+ def _loss_chunk(
581
+ h_a: torch.Tensor,
582
+ h_c: torch.Tensor,
583
+ mix_logit: torch.Tensor,
584
+ targets: torch.Tensor,
585
+ w_a: torch.Tensor,
586
+ w_c: torch.Tensor,
587
+ ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
588
+ """One chunk of positions. Returns summed NLLs and summed squared logits."""
589
+ logits_a = F.linear(h_a, w_a).float()
590
+ logits_c = F.linear(h_c, w_c).float()
591
+
592
+ log_p_a = F.log_softmax(logits_a, dim=-1)
593
+ log_p_c = F.log_softmax(logits_c, dim=-1)
594
+
595
+ # Mixing happens in probability space, computed in log space:
596
+ # log(a*p_A + (1-a)*p_C) = logaddexp(log a + log p_A, log(1-a) + log p_C)
597
+ log_alpha = F.logsigmoid(mix_logit).unsqueeze(-1)
598
+ log_one_minus_alpha = F.logsigmoid(-mix_logit).unsqueeze(-1)
599
+ log_p_mix = torch.logaddexp(log_alpha + log_p_a, log_one_minus_alpha + log_p_c)
600
+
601
+ idx = targets.unsqueeze(-1)
602
+ nll_mix = -log_p_mix.gather(-1, idx).squeeze(-1).sum()
603
+ nll_a = -log_p_a.gather(-1, idx).squeeze(-1).sum()
604
+ nll_c = -log_p_c.gather(-1, idx).squeeze(-1).sum()
605
+ sq_logits = logits_a.pow(2).sum() + logits_c.pow(2).sum()
606
+ return nll_mix, nll_a, nll_c, sq_logits
607
+
608
+
609
+ def relay_loss(
610
+ model: BananaMindRelay,
611
+ h_a: torch.Tensor,
612
+ h_c: torch.Tensor,
613
+ mix_logit: torch.Tensor,
614
+ targets: torch.Tensor,
615
+ solo_lambda: float,
616
+ z_loss_coeff: float = 0.0,
617
+ chunk_size: int = 16384,
618
+ ) -> dict[str, torch.Tensor]:
619
+ """L = L_mix + lambda * (L_A + L_C).
620
+
621
+ There is no L_B term. B has no head to compute one with, and giving it one
622
+ would turn the relay into a third predictor instead of a channel. B trains
623
+ entirely on gradient arriving through its four bridge directions.
624
+
625
+ Positions are processed in chunks under gradient checkpointing: three
626
+ vocab-sized float tensors per position do not fit at 4096 context otherwise.
627
+ """
628
+ w_a = model.lm_head_a.weight
629
+ w_c = model.lm_head_c.weight
630
+ vocab = w_a.size(0)
631
+
632
+ flat_a = h_a.reshape(-1, h_a.size(-1))
633
+ flat_c = h_c.reshape(-1, h_c.size(-1))
634
+ flat_z = mix_logit.reshape(-1)
635
+ flat_y = targets.reshape(-1)
636
+ n_pos = flat_y.numel()
637
+
638
+ if chunk_size <= 0 or chunk_size >= n_pos:
639
+ bounds = [(0, n_pos)]
640
+ else:
641
+ bounds = [(i, min(i + chunk_size, n_pos)) for i in range(0, n_pos, chunk_size)]
642
+
643
+ mix_sum = flat_a.new_zeros((), dtype=torch.float32)
644
+ a_sum = flat_a.new_zeros((), dtype=torch.float32)
645
+ c_sum = flat_a.new_zeros((), dtype=torch.float32)
646
+ sq_sum = flat_a.new_zeros((), dtype=torch.float32)
647
+
648
+ use_ckpt = torch.is_grad_enabled() and len(bounds) > 1
649
+ for lo, hi in bounds:
650
+ args = (flat_a[lo:hi], flat_c[lo:hi], flat_z[lo:hi], flat_y[lo:hi], w_a, w_c)
651
+ if use_ckpt:
652
+ part = torch.utils.checkpoint.checkpoint(_loss_chunk, *args, use_reentrant=False)
653
+ else:
654
+ part = _loss_chunk(*args)
655
+ mix_sum = mix_sum + part[0]
656
+ a_sum = a_sum + part[1]
657
+ c_sum = c_sum + part[2]
658
+ sq_sum = sq_sum + part[3]
659
+
660
+ l_mix = mix_sum / n_pos
661
+ l_a = a_sum / n_pos
662
+ l_c = c_sum / n_pos
663
+ z_loss = sq_sum / (2.0 * n_pos * vocab)
664
+
665
+ loss = l_mix + solo_lambda * (l_a + l_c) + z_loss_coeff * z_loss
666
+ return {"loss": loss, "l_mix": l_mix, "l_a": l_a, "l_c": l_c, "z_loss": z_loss}
667
+
668
+
669
+ def count_parameters(model: nn.Module) -> int:
670
+ return sum(p.numel() for p in model.parameters())
671
+
672
+
673
+ def estimate_training_flops_per_token(config: RelayConfig, param_count: int, seq_len: int) -> int:
674
+ dense_flops = 6 * param_count
675
+ attention_flops = 0
676
+ for spec in (config.tower_a, config.tower_b, config.tower_c):
677
+ attention_flops += (
678
+ 12 * spec.num_hidden_layers * spec.num_attention_heads * config.head_dim * seq_len
679
+ )
680
+ return dense_flops + attention_flops
special_tokens_map.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "pad_token": "<|pad|>",
3
+ "bos_token": "<|bos|>",
4
+ "eos_token": "<|eos|>",
5
+ "unk_token": "<|unk|>"
6
+ }
token_types.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Bucket the 8192-token vocab into coarse types.
3
+
4
+ Used to log the mixing scalar's distribution over token types: knowing that
5
+ alpha averages 0.5 overall says nothing, knowing that it sits at 0.8 on digits
6
+ and 0.4 on word continuations says a lot about what each tower is doing.
7
+
8
+ The Mini tokenizer is byte-level BPE (with digits split out by a pre-tokenizer),
9
+ so token strings are byte-level encoded and have to be mapped back through the
10
+ GPT-2 byte<->unicode table before they can be classified.
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ from pathlib import Path
16
+
17
+ import numpy as np
18
+
19
+
20
+ TYPE_NAMES = (
21
+ "special",
22
+ "whitespace",
23
+ "digit",
24
+ "word_start",
25
+ "word_cont",
26
+ "punct",
27
+ "other",
28
+ )
29
+ TYPE_INDEX = {name: i for i, name in enumerate(TYPE_NAMES)}
30
+
31
+
32
+ def _byte_decoder() -> dict[str, int]:
33
+ bs = (
34
+ list(range(ord("!"), ord("~") + 1))
35
+ + list(range(ord("¡"), ord("¬") + 1))
36
+ + list(range(ord("®"), ord("ÿ") + 1))
37
+ )
38
+ cs = bs[:]
39
+ n = 0
40
+ for b in range(256):
41
+ if b not in bs:
42
+ bs.append(b)
43
+ cs.append(256 + n)
44
+ n += 1
45
+ return {chr(c): b for b, c in zip(bs, cs)}
46
+
47
+
48
+ def _decode(token: str, byte_decoder: dict[str, int]) -> str:
49
+ try:
50
+ raw = bytes(byte_decoder[ch] for ch in token)
51
+ except KeyError:
52
+ return token
53
+ return raw.decode("utf-8", errors="replace")
54
+
55
+
56
+ def classify(text: str) -> int:
57
+ if text == "":
58
+ return TYPE_INDEX["other"]
59
+ core = text.lstrip(" \t")
60
+ leading_space = core != text
61
+ if core.strip() == "":
62
+ return TYPE_INDEX["whitespace"]
63
+ if any(ch.isdigit() for ch in core):
64
+ return TYPE_INDEX["digit"]
65
+ letters = core.replace("'", "").replace("’", "")
66
+ if letters and all(ch.isalpha() for ch in letters):
67
+ return TYPE_INDEX["word_start"] if leading_space else TYPE_INDEX["word_cont"]
68
+ if all(not ch.isalnum() for ch in core):
69
+ return TYPE_INDEX["punct"]
70
+ return TYPE_INDEX["other"]
71
+
72
+
73
+ def build_token_type_table(tokenizer_path: Path, vocab_size: int) -> np.ndarray:
74
+ """Returns an int64 array of length vocab_size mapping token id -> type index."""
75
+ path = Path(tokenizer_path)
76
+ if path.is_dir():
77
+ path = path / "tokenizer.json"
78
+ with path.open("r", encoding="utf-8") as f:
79
+ data = json.load(f)
80
+
81
+ vocab: dict[str, int] = data["model"]["vocab"]
82
+ specials = {entry["content"] for entry in data.get("added_tokens", [])}
83
+ byte_decoder = _byte_decoder()
84
+
85
+ table = np.full(vocab_size, TYPE_INDEX["other"], dtype=np.int64)
86
+ for token, idx in vocab.items():
87
+ if idx >= vocab_size:
88
+ continue
89
+ if token in specials:
90
+ table[idx] = TYPE_INDEX["special"]
91
+ continue
92
+ table[idx] = classify(_decode(token, byte_decoder))
93
+ return table
94
+
95
+
96
+ if __name__ == "__main__":
97
+ import sys
98
+ from collections import Counter
99
+
100
+ tok = Path(
101
+ sys.argv[1]
102
+ if len(sys.argv) > 1
103
+ else "/home/banaxi/Desktop/BananaMind/BananaMind-2/tokenizers/fineweb_edu_first_50gib_8k_digits/tokenizer.json"
104
+ )
105
+ table = build_token_type_table(tok, 8192)
106
+ counts = Counter(table.tolist())
107
+ for i, name in enumerate(TYPE_NAMES):
108
+ print(f"{name:12s} {counts.get(i, 0):5d} {counts.get(i, 0) / len(table):6.2%}")
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "tokenizer_class": "PreTrainedTokenizerFast",
3
+ "model_max_length": 4096,
4
+ "pad_token": "<|pad|>",
5
+ "bos_token": "<|bos|>",
6
+ "eos_token": "<|eos|>",
7
+ "unk_token": "<|unk|>"
8
+ }
training_metrics.jsonl ADDED
The diff for this file is too large to render. See raw diff