Rishav commited on
Commit
be8d222
·
1 Parent(s): 8258b94

Add SFT warm start training pipeline

Browse files
results/training_dashboard.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
- "status": "eval_completed",
3
- "updated_at": "2026-04-26 10:53 IST",
4
  "hardware": "a10g-small",
5
  "summary": "30-step smoke training completed and pushed adapters. Eval did not show improvement yet; this validates the pipeline but not learning progress.",
6
  "runs": [
@@ -74,5 +74,1881 @@
74
  "invalid_payloads": 1,
75
  "invalid_actions": 0
76
  }
77
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  }
 
1
  {
2
+ "status": "pipeline_upgraded",
3
+ "updated_at": "2026-04-26 11:10 IST",
4
  "hardware": "a10g-small",
5
  "summary": "30-step smoke training completed and pushed adapters. Eval did not show improvement yet; this validates the pipeline but not learning progress.",
6
  "runs": [
 
74
  "invalid_payloads": 1,
75
  "invalid_actions": 0
76
  }
77
+ ],
78
+ "training_series": {
79
+ "center": {
80
+ "source_log": "results\\center_train_job.log",
81
+ "steps": [
82
+ {
83
+ "loss": 0.0,
84
+ "grad_norm": 0.0,
85
+ "learning_rate": 1e-06,
86
+ "num_tokens": 3082.0,
87
+ "completions/mean_length": 256.0,
88
+ "completions/min_length": 256.0,
89
+ "completions/max_length": 256.0,
90
+ "completions/clipped_ratio": 1.0,
91
+ "completions/mean_terminated_length": 0.0,
92
+ "completions/min_terminated_length": 0.0,
93
+ "completions/max_terminated_length": 0.0,
94
+ "rewards/reward_completions/mean": -8.0,
95
+ "rewards/reward_completions/std": 0.0,
96
+ "reward": -8.0,
97
+ "reward_std": 0.0,
98
+ "frac_reward_zero_std": 1.0,
99
+ "entropy": 1.627,
100
+ "clip_ratio/low_mean": 0.0,
101
+ "clip_ratio/low_min": 0.0,
102
+ "clip_ratio/high_mean": 0.0,
103
+ "clip_ratio/high_max": 0.0,
104
+ "clip_ratio/region_mean": 0.0,
105
+ "step_time": 15.12,
106
+ "epoch": 0.02778,
107
+ "completion_length": 256.0,
108
+ "clipped_ratio": 1.0,
109
+ "step": 1
110
+ },
111
+ {
112
+ "loss": 0.4278,
113
+ "grad_norm": 1.68,
114
+ "learning_rate": 9.667e-07,
115
+ "num_tokens": 5533.0,
116
+ "completions/mean_length": 159.5,
117
+ "completions/min_length": 63.0,
118
+ "completions/max_length": 256.0,
119
+ "completions/clipped_ratio": 0.5,
120
+ "completions/mean_terminated_length": 63.0,
121
+ "completions/min_terminated_length": 63.0,
122
+ "completions/max_terminated_length": 63.0,
123
+ "rewards/reward_completions/mean": -3.014,
124
+ "rewards/reward_completions/std": 7.051,
125
+ "reward": -3.014,
126
+ "reward_std": 7.051,
127
+ "frac_reward_zero_std": 0.0,
128
+ "entropy": 1.15,
129
+ "clip_ratio/low_mean": 0.0,
130
+ "clip_ratio/low_min": 0.0,
131
+ "clip_ratio/high_mean": 0.0,
132
+ "clip_ratio/high_max": 0.0,
133
+ "clip_ratio/region_mean": 0.0,
134
+ "step_time": 14.61,
135
+ "epoch": 0.05556,
136
+ "completion_length": 159.5,
137
+ "clipped_ratio": 0.5,
138
+ "step": 2
139
+ },
140
+ {
141
+ "loss": 0.09386,
142
+ "grad_norm": 1.048,
143
+ "learning_rate": 9.333e-07,
144
+ "num_tokens": 8641.0,
145
+ "completions/mean_length": 226.0,
146
+ "completions/min_length": 196.0,
147
+ "completions/max_length": 256.0,
148
+ "completions/clipped_ratio": 0.5,
149
+ "completions/mean_terminated_length": 196.0,
150
+ "completions/min_terminated_length": 196.0,
151
+ "completions/max_terminated_length": 196.0,
152
+ "rewards/reward_completions/mean": -1.928,
153
+ "rewards/reward_completions/std": 8.587,
154
+ "reward": -1.928,
155
+ "reward_std": 8.587,
156
+ "frac_reward_zero_std": 0.0,
157
+ "entropy": 0.7438,
158
+ "clip_ratio/low_mean": 0.0,
159
+ "clip_ratio/low_min": 0.0,
160
+ "clip_ratio/high_mean": 0.0,
161
+ "clip_ratio/high_max": 0.0,
162
+ "clip_ratio/region_mean": 0.0,
163
+ "step_time": 14.57,
164
+ "epoch": 0.08333,
165
+ "completion_length": 226.0,
166
+ "clipped_ratio": 0.5,
167
+ "step": 3
168
+ },
169
+ {
170
+ "loss": 0.01842,
171
+ "grad_norm": 0.858,
172
+ "learning_rate": 9e-07,
173
+ "num_tokens": 11720.0,
174
+ "completions/mean_length": 249.5,
175
+ "completions/min_length": 243.0,
176
+ "completions/max_length": 256.0,
177
+ "completions/clipped_ratio": 0.5,
178
+ "completions/mean_terminated_length": 243.0,
179
+ "completions/min_terminated_length": 243.0,
180
+ "completions/max_terminated_length": 243.0,
181
+ "rewards/reward_completions/mean": -2.648,
182
+ "rewards/reward_completions/std": 7.569,
183
+ "reward": -2.648,
184
+ "reward_std": 7.569,
185
+ "frac_reward_zero_std": 0.0,
186
+ "entropy": 0.2652,
187
+ "clip_ratio/low_mean": 0.0,
188
+ "clip_ratio/low_min": 0.0,
189
+ "clip_ratio/high_mean": 0.0,
190
+ "clip_ratio/high_max": 0.0,
191
+ "clip_ratio/region_mean": 0.0,
192
+ "step_time": 14.57,
193
+ "epoch": 0.1111,
194
+ "completion_length": 249.5,
195
+ "clipped_ratio": 0.5,
196
+ "step": 4
197
+ },
198
+ {
199
+ "loss": 0.3577,
200
+ "grad_norm": 1.185,
201
+ "learning_rate": 8.667e-07,
202
+ "num_tokens": 14150.0,
203
+ "completions/mean_length": 170.0,
204
+ "completions/min_length": 84.0,
205
+ "completions/max_length": 256.0,
206
+ "completions/clipped_ratio": 0.5,
207
+ "completions/mean_terminated_length": 84.0,
208
+ "completions/min_terminated_length": 84.0,
209
+ "completions/max_terminated_length": 84.0,
210
+ "rewards/reward_completions/mean": -3.044,
211
+ "rewards/reward_completions/std": 7.009,
212
+ "reward": -3.044,
213
+ "reward_std": 7.009,
214
+ "frac_reward_zero_std": 0.0,
215
+ "entropy": 0.755,
216
+ "clip_ratio/low_mean": 0.0,
217
+ "clip_ratio/low_min": 0.0,
218
+ "clip_ratio/high_mean": 0.0,
219
+ "clip_ratio/high_max": 0.0,
220
+ "clip_ratio/region_mean": 0.0,
221
+ "step_time": 14.5,
222
+ "epoch": 0.1389,
223
+ "completion_length": 170.0,
224
+ "clipped_ratio": 0.5,
225
+ "step": 5
226
+ },
227
+ {
228
+ "loss": 0.0,
229
+ "grad_norm": 0.0,
230
+ "learning_rate": 8.333e-07,
231
+ "num_tokens": 16970.0,
232
+ "completions/mean_length": 177.0,
233
+ "completions/min_length": 131.0,
234
+ "completions/max_length": 223.0,
235
+ "completions/clipped_ratio": 0.0,
236
+ "completions/mean_terminated_length": 177.0,
237
+ "completions/min_terminated_length": 131.0,
238
+ "completions/max_terminated_length": 223.0,
239
+ "rewards/reward_completions/mean": 0.5122,
240
+ "rewards/reward_completions/std": 0.0,
241
+ "reward": 0.5122,
242
+ "reward_std": 0.0,
243
+ "frac_reward_zero_std": 1.0,
244
+ "entropy": 1.003,
245
+ "clip_ratio/low_mean": 0.0,
246
+ "clip_ratio/low_min": 0.0,
247
+ "clip_ratio/high_mean": 0.0,
248
+ "clip_ratio/high_max": 0.0,
249
+ "clip_ratio/region_mean": 0.0,
250
+ "step_time": 12.66,
251
+ "epoch": 0.1667,
252
+ "completion_length": 177.0,
253
+ "clipped_ratio": 0.0,
254
+ "step": 6
255
+ },
256
+ {
257
+ "loss": 0.0,
258
+ "grad_norm": 0.0,
259
+ "learning_rate": 8e-07,
260
+ "num_tokens": 20100.0,
261
+ "completions/mean_length": 256.0,
262
+ "completions/min_length": 256.0,
263
+ "completions/max_length": 256.0,
264
+ "completions/clipped_ratio": 1.0,
265
+ "completions/mean_terminated_length": 0.0,
266
+ "completions/min_terminated_length": 0.0,
267
+ "completions/max_terminated_length": 0.0,
268
+ "rewards/reward_completions/mean": -8.0,
269
+ "rewards/reward_completions/std": 0.0,
270
+ "reward": -8.0,
271
+ "reward_std": 0.0,
272
+ "frac_reward_zero_std": 1.0,
273
+ "entropy": 0.2946,
274
+ "clip_ratio/low_mean": 0.0,
275
+ "clip_ratio/low_min": 0.0,
276
+ "clip_ratio/high_mean": 0.0,
277
+ "clip_ratio/high_max": 0.0,
278
+ "clip_ratio/region_mean": 0.0,
279
+ "step_time": 14.51,
280
+ "epoch": 0.1944,
281
+ "completion_length": 256.0,
282
+ "clipped_ratio": 1.0,
283
+ "step": 7
284
+ },
285
+ {
286
+ "loss": 0.3392,
287
+ "grad_norm": 1.515,
288
+ "learning_rate": 7.667e-07,
289
+ "num_tokens": 22980.0,
290
+ "completions/mean_length": 173.0,
291
+ "completions/min_length": 90.0,
292
+ "completions/max_length": 256.0,
293
+ "completions/clipped_ratio": 0.5,
294
+ "completions/mean_terminated_length": 90.0,
295
+ "completions/min_terminated_length": 90.0,
296
+ "completions/max_terminated_length": 90.0,
297
+ "rewards/reward_completions/mean": -2.942,
298
+ "rewards/reward_completions/std": 7.153,
299
+ "reward": -2.942,
300
+ "reward_std": 7.153,
301
+ "frac_reward_zero_std": 0.0,
302
+ "entropy": 0.8725,
303
+ "clip_ratio/low_mean": 0.0,
304
+ "clip_ratio/low_min": 0.0,
305
+ "clip_ratio/high_mean": 0.0,
306
+ "clip_ratio/high_max": 0.0,
307
+ "clip_ratio/region_mean": 0.0,
308
+ "step_time": 14.57,
309
+ "epoch": 0.2222,
310
+ "completion_length": 173.0,
311
+ "clipped_ratio": 0.5,
312
+ "step": 8
313
+ },
314
+ {
315
+ "loss": 0.0,
316
+ "grad_norm": 0.0,
317
+ "learning_rate": 7.333e-07,
318
+ "num_tokens": 25860.0,
319
+ "completions/mean_length": 200.5,
320
+ "completions/min_length": 200.0,
321
+ "completions/max_length": 201.0,
322
+ "completions/clipped_ratio": 0.0,
323
+ "completions/mean_terminated_length": 200.5,
324
+ "completions/min_terminated_length": 200.0,
325
+ "completions/max_terminated_length": 201.0,
326
+ "rewards/reward_completions/mean": 2.848,
327
+ "rewards/reward_completions/std": 0.0,
328
+ "reward": 2.848,
329
+ "reward_std": 0.0,
330
+ "frac_reward_zero_std": 1.0,
331
+ "entropy": 0.9884,
332
+ "clip_ratio/low_mean": 0.0,
333
+ "clip_ratio/low_min": 0.0,
334
+ "clip_ratio/high_mean": 0.0,
335
+ "clip_ratio/high_max": 0.0,
336
+ "clip_ratio/region_mean": 0.0,
337
+ "step_time": 11.6,
338
+ "epoch": 0.25,
339
+ "completion_length": 200.5,
340
+ "clipped_ratio": 0.0,
341
+ "step": 9
342
+ },
343
+ {
344
+ "loss": 0.0,
345
+ "grad_norm": 0.0,
346
+ "learning_rate": 7e-07,
347
+ "num_tokens": 28890.0,
348
+ "completions/mean_length": 256.0,
349
+ "completions/min_length": 256.0,
350
+ "completions/max_length": 256.0,
351
+ "completions/clipped_ratio": 1.0,
352
+ "completions/mean_terminated_length": 0.0,
353
+ "completions/min_terminated_length": 0.0,
354
+ "completions/max_terminated_length": 0.0,
355
+ "rewards/reward_completions/mean": -8.0,
356
+ "rewards/reward_completions/std": 0.0,
357
+ "reward": -8.0,
358
+ "reward_std": 0.0,
359
+ "frac_reward_zero_std": 1.0,
360
+ "entropy": 0.06355,
361
+ "clip_ratio/low_mean": 0.0,
362
+ "clip_ratio/low_min": 0.0,
363
+ "clip_ratio/high_mean": 0.0,
364
+ "clip_ratio/high_max": 0.0,
365
+ "clip_ratio/region_mean": 0.0,
366
+ "step_time": 14.68,
367
+ "epoch": 0.2778,
368
+ "completion_length": 256.0,
369
+ "clipped_ratio": 1.0,
370
+ "step": 10
371
+ },
372
+ {
373
+ "loss": 0.0,
374
+ "grad_norm": 0.0,
375
+ "learning_rate": 6.667e-07,
376
+ "num_tokens": 31890.0,
377
+ "completions/mean_length": 256.0,
378
+ "completions/min_length": 256.0,
379
+ "completions/max_length": 256.0,
380
+ "completions/clipped_ratio": 1.0,
381
+ "completions/mean_terminated_length": 0.0,
382
+ "completions/min_terminated_length": 0.0,
383
+ "completions/max_terminated_length": 0.0,
384
+ "rewards/reward_completions/mean": -8.0,
385
+ "rewards/reward_completions/std": 0.0,
386
+ "reward": -8.0,
387
+ "reward_std": 0.0,
388
+ "frac_reward_zero_std": 1.0,
389
+ "entropy": 0.4979,
390
+ "clip_ratio/low_mean": 0.0,
391
+ "clip_ratio/low_min": 0.0,
392
+ "clip_ratio/high_mean": 0.0,
393
+ "clip_ratio/high_max": 0.0,
394
+ "clip_ratio/region_mean": 0.0,
395
+ "step_time": 14.65,
396
+ "epoch": 0.3056,
397
+ "completion_length": 256.0,
398
+ "clipped_ratio": 1.0,
399
+ "step": 11
400
+ },
401
+ {
402
+ "loss": 0.09564,
403
+ "grad_norm": 0.9437,
404
+ "learning_rate": 6.333e-07,
405
+ "num_tokens": 34460.0,
406
+ "completions/mean_length": 225.5,
407
+ "completions/min_length": 195.0,
408
+ "completions/max_length": 256.0,
409
+ "completions/clipped_ratio": 0.5,
410
+ "completions/mean_terminated_length": 195.0,
411
+ "completions/min_terminated_length": 195.0,
412
+ "completions/max_terminated_length": 195.0,
413
+ "rewards/reward_completions/mean": -3.376,
414
+ "rewards/reward_completions/std": 6.539,
415
+ "reward": -3.376,
416
+ "reward_std": 6.539,
417
+ "frac_reward_zero_std": 0.0,
418
+ "entropy": 0.5531,
419
+ "clip_ratio/low_mean": 0.0,
420
+ "clip_ratio/low_min": 0.0,
421
+ "clip_ratio/high_mean": 0.0,
422
+ "clip_ratio/high_max": 0.0,
423
+ "clip_ratio/region_mean": 0.0,
424
+ "step_time": 14.52,
425
+ "epoch": 0.3333,
426
+ "completion_length": 225.5,
427
+ "clipped_ratio": 0.5,
428
+ "step": 12
429
+ },
430
+ {
431
+ "loss": 0.4957,
432
+ "grad_norm": 1.425,
433
+ "learning_rate": 6e-07,
434
+ "num_tokens": 37220.0,
435
+ "completions/mean_length": 150.5,
436
+ "completions/min_length": 45.0,
437
+ "completions/max_length": 256.0,
438
+ "completions/clipped_ratio": 0.5,
439
+ "completions/mean_terminated_length": 45.0,
440
+ "completions/min_terminated_length": 45.0,
441
+ "completions/max_terminated_length": 45.0,
442
+ "rewards/reward_completions/mean": -2.778,
443
+ "rewards/reward_completions/std": 7.385,
444
+ "reward": -2.778,
445
+ "reward_std": 7.385,
446
+ "frac_reward_zero_std": 0.0,
447
+ "entropy": 0.8273,
448
+ "clip_ratio/low_mean": 0.0,
449
+ "clip_ratio/low_min": 0.0,
450
+ "clip_ratio/high_mean": 0.0,
451
+ "clip_ratio/high_max": 0.0,
452
+ "clip_ratio/region_mean": 0.0,
453
+ "step_time": 14.7,
454
+ "epoch": 0.3611,
455
+ "completion_length": 150.5,
456
+ "clipped_ratio": 0.5,
457
+ "step": 13
458
+ },
459
+ {
460
+ "loss": 0.07147,
461
+ "grad_norm": 1.156,
462
+ "learning_rate": 5.667e-07,
463
+ "num_tokens": 40280.0,
464
+ "completions/mean_length": 232.5,
465
+ "completions/min_length": 209.0,
466
+ "completions/max_length": 256.0,
467
+ "completions/clipped_ratio": 0.5,
468
+ "completions/mean_terminated_length": 209.0,
469
+ "completions/min_terminated_length": 209.0,
470
+ "completions/max_terminated_length": 209.0,
471
+ "rewards/reward_completions/mean": -3.959,
472
+ "rewards/reward_completions/std": 5.715,
473
+ "reward": -3.959,
474
+ "reward_std": 5.715,
475
+ "frac_reward_zero_std": 0.0,
476
+ "entropy": 0.7875,
477
+ "clip_ratio/low_mean": 0.0,
478
+ "clip_ratio/low_min": 0.0,
479
+ "clip_ratio/high_mean": 0.0,
480
+ "clip_ratio/high_max": 0.0,
481
+ "clip_ratio/region_mean": 0.0,
482
+ "step_time": 14.51,
483
+ "epoch": 0.3889,
484
+ "completion_length": 232.5,
485
+ "clipped_ratio": 0.5,
486
+ "step": 14
487
+ },
488
+ {
489
+ "loss": 0.0,
490
+ "grad_norm": 0.0,
491
+ "learning_rate": 5.333e-07,
492
+ "num_tokens": 42900.0,
493
+ "completions/mean_length": 256.0,
494
+ "completions/min_length": 256.0,
495
+ "completions/max_length": 256.0,
496
+ "completions/clipped_ratio": 1.0,
497
+ "completions/mean_terminated_length": 0.0,
498
+ "completions/min_terminated_length": 0.0,
499
+ "completions/max_terminated_length": 0.0,
500
+ "rewards/reward_completions/mean": -8.0,
501
+ "rewards/reward_completions/std": 0.0,
502
+ "reward": -8.0,
503
+ "reward_std": 0.0,
504
+ "frac_reward_zero_std": 1.0,
505
+ "entropy": 0.06475,
506
+ "clip_ratio/low_mean": 0.0,
507
+ "clip_ratio/low_min": 0.0,
508
+ "clip_ratio/high_mean": 0.0,
509
+ "clip_ratio/high_max": 0.0,
510
+ "clip_ratio/region_mean": 0.0,
511
+ "step_time": 14.5,
512
+ "epoch": 0.4167,
513
+ "completion_length": 256.0,
514
+ "clipped_ratio": 1.0,
515
+ "step": 15
516
+ },
517
+ {
518
+ "loss": 0.101,
519
+ "grad_norm": 0.9229,
520
+ "learning_rate": 5e-07,
521
+ "num_tokens": 46060.0,
522
+ "completions/mean_length": 224.0,
523
+ "completions/min_length": 192.0,
524
+ "completions/max_length": 256.0,
525
+ "completions/clipped_ratio": 0.5,
526
+ "completions/mean_terminated_length": 192.0,
527
+ "completions/min_terminated_length": 192.0,
528
+ "completions/max_terminated_length": 192.0,
529
+ "rewards/reward_completions/mean": -3.372,
530
+ "rewards/reward_completions/std": 6.545,
531
+ "reward": -3.372,
532
+ "reward_std": 6.545,
533
+ "frac_reward_zero_std": 0.0,
534
+ "entropy": 0.5082,
535
+ "clip_ratio/low_mean": 0.0,
536
+ "clip_ratio/low_min": 0.0,
537
+ "clip_ratio/high_mean": 0.0,
538
+ "clip_ratio/high_max": 0.0,
539
+ "clip_ratio/region_mean": 0.0,
540
+ "step_time": 14.68,
541
+ "epoch": 0.4444,
542
+ "completion_length": 224.0,
543
+ "clipped_ratio": 0.5,
544
+ "step": 16
545
+ },
546
+ {
547
+ "loss": 0.07823,
548
+ "grad_norm": 1.086,
549
+ "learning_rate": 4.667e-07,
550
+ "num_tokens": 48650.0,
551
+ "completions/mean_length": 230.5,
552
+ "completions/min_length": 205.0,
553
+ "completions/max_length": 256.0,
554
+ "completions/clipped_ratio": 0.5,
555
+ "completions/mean_terminated_length": 205.0,
556
+ "completions/min_terminated_length": 205.0,
557
+ "completions/max_terminated_length": 205.0,
558
+ "rewards/reward_completions/mean": -1.764,
559
+ "rewards/reward_completions/std": 8.819,
560
+ "reward": -1.764,
561
+ "reward_std": 8.819,
562
+ "frac_reward_zero_std": 0.0,
563
+ "entropy": 0.8177,
564
+ "clip_ratio/low_mean": 0.0,
565
+ "clip_ratio/low_min": 0.0,
566
+ "clip_ratio/high_mean": 0.0,
567
+ "clip_ratio/high_max": 0.0,
568
+ "clip_ratio/region_mean": 0.0,
569
+ "step_time": 14.56,
570
+ "epoch": 0.4722,
571
+ "completion_length": 230.5,
572
+ "clipped_ratio": 0.5,
573
+ "step": 17
574
+ },
575
+ {
576
+ "loss": 0.0,
577
+ "grad_norm": 0.0,
578
+ "learning_rate": 4.333e-07,
579
+ "num_tokens": 51320.0,
580
+ "completions/mean_length": 78.5,
581
+ "completions/min_length": 74.0,
582
+ "completions/max_length": 83.0,
583
+ "completions/clipped_ratio": 0.0,
584
+ "completions/mean_terminated_length": 78.5,
585
+ "completions/min_terminated_length": 74.0,
586
+ "completions/max_terminated_length": 83.0,
587
+ "rewards/reward_completions/mean": 2.844,
588
+ "rewards/reward_completions/std": 0.0,
589
+ "reward": 2.844,
590
+ "reward_std": 0.0,
591
+ "frac_reward_zero_std": 1.0,
592
+ "entropy": 1.933,
593
+ "clip_ratio/low_mean": 0.0,
594
+ "clip_ratio/low_min": 0.0,
595
+ "clip_ratio/high_mean": 0.0,
596
+ "clip_ratio/high_max": 0.0,
597
+ "clip_ratio/region_mean": 0.0,
598
+ "step_time": 5.248,
599
+ "epoch": 0.5,
600
+ "completion_length": 78.5,
601
+ "clipped_ratio": 0.0,
602
+ "step": 18
603
+ },
604
+ {
605
+ "loss": 0.0,
606
+ "grad_norm": 0.0,
607
+ "learning_rate": 4e-07,
608
+ "num_tokens": 54290.0,
609
+ "completions/mean_length": 256.0,
610
+ "completions/min_length": 256.0,
611
+ "completions/max_length": 256.0,
612
+ "completions/clipped_ratio": 1.0,
613
+ "completions/mean_terminated_length": 0.0,
614
+ "completions/min_terminated_length": 0.0,
615
+ "completions/max_terminated_length": 0.0,
616
+ "rewards/reward_completions/mean": -8.0,
617
+ "rewards/reward_completions/std": 0.0,
618
+ "reward": -8.0,
619
+ "reward_std": 0.0,
620
+ "frac_reward_zero_std": 1.0,
621
+ "entropy": 0.0686,
622
+ "clip_ratio/low_mean": 0.0,
623
+ "clip_ratio/low_min": 0.0,
624
+ "clip_ratio/high_mean": 0.0,
625
+ "clip_ratio/high_max": 0.0,
626
+ "clip_ratio/region_mean": 0.0,
627
+ "step_time": 14.69,
628
+ "epoch": 0.5278,
629
+ "completion_length": 256.0,
630
+ "clipped_ratio": 1.0,
631
+ "step": 19
632
+ },
633
+ {
634
+ "loss": 0.0,
635
+ "grad_norm": 0.0,
636
+ "learning_rate": 3.667e-07,
637
+ "num_tokens": 57200.0,
638
+ "completions/mean_length": 183.5,
639
+ "completions/min_length": 150.0,
640
+ "completions/max_length": 217.0,
641
+ "completions/clipped_ratio": 0.0,
642
+ "completions/mean_terminated_length": 183.5,
643
+ "completions/min_terminated_length": 150.0,
644
+ "completions/max_terminated_length": 217.0,
645
+ "rewards/reward_completions/mean": 2.672,
646
+ "rewards/reward_completions/std": 0.0,
647
+ "reward": 2.672,
648
+ "reward_std": 0.0,
649
+ "frac_reward_zero_std": 1.0,
650
+ "entropy": 0.8566,
651
+ "clip_ratio/low_mean": 0.0,
652
+ "clip_ratio/low_min": 0.0,
653
+ "clip_ratio/high_mean": 0.0,
654
+ "clip_ratio/high_max": 0.0,
655
+ "clip_ratio/region_mean": 0.0,
656
+ "step_time": 12.47,
657
+ "epoch": 0.5556,
658
+ "completion_length": 183.5,
659
+ "clipped_ratio": 0.0,
660
+ "step": 20
661
+ },
662
+ {
663
+ "loss": 0.06483,
664
+ "grad_norm": 1.153,
665
+ "learning_rate": 3.333e-07,
666
+ "num_tokens": 60320.0,
667
+ "completions/mean_length": 234.5,
668
+ "completions/min_length": 213.0,
669
+ "completions/max_length": 256.0,
670
+ "completions/clipped_ratio": 0.5,
671
+ "completions/mean_terminated_length": 213.0,
672
+ "completions/min_terminated_length": 213.0,
673
+ "completions/max_terminated_length": 213.0,
674
+ "rewards/reward_completions/mean": -3.488,
675
+ "rewards/reward_completions/std": 6.381,
676
+ "reward": -3.488,
677
+ "reward_std": 6.381,
678
+ "frac_reward_zero_std": 0.0,
679
+ "entropy": 0.6029,
680
+ "clip_ratio/low_mean": 0.0,
681
+ "clip_ratio/low_min": 0.0,
682
+ "clip_ratio/high_mean": 0.0,
683
+ "clip_ratio/high_max": 0.0,
684
+ "clip_ratio/region_mean": 0.0,
685
+ "step_time": 14.57,
686
+ "epoch": 0.5833,
687
+ "completion_length": 234.5,
688
+ "clipped_ratio": 0.5,
689
+ "step": 21
690
+ },
691
+ {
692
+ "loss": 0.6747,
693
+ "grad_norm": 1.753,
694
+ "learning_rate": 3e-07,
695
+ "num_tokens": 63170.0,
696
+ "completions/mean_length": 131.0,
697
+ "completions/min_length": 6.0,
698
+ "completions/max_length": 256.0,
699
+ "completions/clipped_ratio": 0.5,
700
+ "completions/mean_terminated_length": 6.0,
701
+ "completions/min_terminated_length": 6.0,
702
+ "completions/max_terminated_length": 6.0,
703
+ "rewards/reward_completions/mean": -3.338,
704
+ "rewards/reward_completions/std": 6.593,
705
+ "reward": -3.338,
706
+ "reward_std": 6.593,
707
+ "frac_reward_zero_std": 0.0,
708
+ "entropy": 0.4945,
709
+ "clip_ratio/low_mean": 0.0,
710
+ "clip_ratio/low_min": 0.0,
711
+ "clip_ratio/high_mean": 0.0,
712
+ "clip_ratio/high_max": 0.0,
713
+ "clip_ratio/region_mean": 0.0,
714
+ "step_time": 14.57,
715
+ "epoch": 0.6111,
716
+ "completion_length": 131.0,
717
+ "clipped_ratio": 0.5,
718
+ "step": 22
719
+ },
720
+ {
721
+ "loss": 0.5278,
722
+ "grad_norm": 1.556,
723
+ "learning_rate": 2.667e-07,
724
+ "num_tokens": 66020.0,
725
+ "completions/mean_length": 138.0,
726
+ "completions/min_length": 35.0,
727
+ "completions/max_length": 241.0,
728
+ "completions/clipped_ratio": 0.0,
729
+ "completions/mean_terminated_length": 138.0,
730
+ "completions/min_terminated_length": 35.0,
731
+ "completions/max_terminated_length": 241.0,
732
+ "rewards/reward_completions/mean": -2.936,
733
+ "rewards/reward_completions/std": 7.162,
734
+ "reward": -2.936,
735
+ "reward_std": 7.162,
736
+ "frac_reward_zero_std": 0.0,
737
+ "entropy": 1.108,
738
+ "clip_ratio/low_mean": 0.0,
739
+ "clip_ratio/low_min": 0.0,
740
+ "clip_ratio/high_mean": 0.0,
741
+ "clip_ratio/high_max": 0.0,
742
+ "clip_ratio/region_mean": 0.0,
743
+ "step_time": 13.85,
744
+ "epoch": 0.6389,
745
+ "completion_length": 138.0,
746
+ "clipped_ratio": 0.0,
747
+ "step": 23
748
+ },
749
+ {
750
+ "loss": 0.0,
751
+ "grad_norm": 0.0,
752
+ "learning_rate": 2.333e-07,
753
+ "num_tokens": 68630.0,
754
+ "completions/mean_length": 256.0,
755
+ "completions/min_length": 256.0,
756
+ "completions/max_length": 256.0,
757
+ "completions/clipped_ratio": 1.0,
758
+ "completions/mean_terminated_length": 0.0,
759
+ "completions/min_terminated_length": 0.0,
760
+ "completions/max_terminated_length": 0.0,
761
+ "rewards/reward_completions/mean": -8.0,
762
+ "rewards/reward_completions/std": 0.0,
763
+ "reward": -8.0,
764
+ "reward_std": 0.0,
765
+ "frac_reward_zero_std": 1.0,
766
+ "entropy": 0.102,
767
+ "clip_ratio/low_mean": 0.0,
768
+ "clip_ratio/low_min": 0.0,
769
+ "clip_ratio/high_mean": 0.0,
770
+ "clip_ratio/high_max": 0.0,
771
+ "clip_ratio/region_mean": 0.0,
772
+ "step_time": 14.58,
773
+ "epoch": 0.6667,
774
+ "completion_length": 256.0,
775
+ "clipped_ratio": 1.0,
776
+ "step": 24
777
+ },
778
+ {
779
+ "loss": 0.2583,
780
+ "grad_norm": 1.3,
781
+ "learning_rate": 2e-07,
782
+ "num_tokens": 71160.0,
783
+ "completions/mean_length": 187.5,
784
+ "completions/min_length": 119.0,
785
+ "completions/max_length": 256.0,
786
+ "completions/clipped_ratio": 0.5,
787
+ "completions/mean_terminated_length": 119.0,
788
+ "completions/min_terminated_length": 119.0,
789
+ "completions/max_terminated_length": 119.0,
790
+ "rewards/reward_completions/mean": -3.544,
791
+ "rewards/reward_completions/std": 6.302,
792
+ "reward": -3.544,
793
+ "reward_std": 6.302,
794
+ "frac_reward_zero_std": 0.0,
795
+ "entropy": 0.9402,
796
+ "clip_ratio/low_mean": 0.0,
797
+ "clip_ratio/low_min": 0.0,
798
+ "clip_ratio/high_mean": 0.0,
799
+ "clip_ratio/high_max": 0.0,
800
+ "clip_ratio/region_mean": 0.0,
801
+ "step_time": 14.71,
802
+ "epoch": 0.6944,
803
+ "completion_length": 187.5,
804
+ "clipped_ratio": 0.5,
805
+ "step": 25
806
+ },
807
+ {
808
+ "loss": 0.4722,
809
+ "grad_norm": 1.068,
810
+ "learning_rate": 1.667e-07,
811
+ "num_tokens": 73970.0,
812
+ "completions/mean_length": 153.5,
813
+ "completions/min_length": 51.0,
814
+ "completions/max_length": 256.0,
815
+ "completions/clipped_ratio": 0.5,
816
+ "completions/mean_terminated_length": 51.0,
817
+ "completions/min_terminated_length": 51.0,
818
+ "completions/max_terminated_length": 51.0,
819
+ "rewards/reward_completions/mean": -3.54,
820
+ "rewards/reward_completions/std": 6.307,
821
+ "reward": -3.54,
822
+ "reward_std": 6.307,
823
+ "frac_reward_zero_std": 0.0,
824
+ "entropy": 0.9242,
825
+ "clip_ratio/low_mean": 0.0,
826
+ "clip_ratio/low_min": 0.0,
827
+ "clip_ratio/high_mean": 0.0,
828
+ "clip_ratio/high_max": 0.0,
829
+ "clip_ratio/region_mean": 0.0,
830
+ "step_time": 14.58,
831
+ "epoch": 0.7222,
832
+ "completion_length": 153.5,
833
+ "clipped_ratio": 0.5,
834
+ "step": 26
835
+ },
836
+ {
837
+ "loss": 0.0,
838
+ "grad_norm": 0.0,
839
+ "learning_rate": 1.333e-07,
840
+ "num_tokens": 76560.0,
841
+ "completions/mean_length": 256.0,
842
+ "completions/min_length": 256.0,
843
+ "completions/max_length": 256.0,
844
+ "completions/clipped_ratio": 1.0,
845
+ "completions/mean_terminated_length": 0.0,
846
+ "completions/min_terminated_length": 0.0,
847
+ "completions/max_terminated_length": 0.0,
848
+ "rewards/reward_completions/mean": -8.0,
849
+ "rewards/reward_completions/std": 0.0,
850
+ "reward": -8.0,
851
+ "reward_std": 0.0,
852
+ "frac_reward_zero_std": 1.0,
853
+ "entropy": 0.9256,
854
+ "clip_ratio/low_mean": 0.0,
855
+ "clip_ratio/low_min": 0.0,
856
+ "clip_ratio/high_mean": 0.0,
857
+ "clip_ratio/high_max": 0.0,
858
+ "clip_ratio/region_mean": 0.0,
859
+ "step_time": 14.47,
860
+ "epoch": 0.75,
861
+ "completion_length": 256.0,
862
+ "clipped_ratio": 1.0,
863
+ "step": 27
864
+ },
865
+ {
866
+ "loss": 0.0,
867
+ "grad_norm": 0.0,
868
+ "learning_rate": 1e-07,
869
+ "num_tokens": 79250.0,
870
+ "completions/mean_length": 256.0,
871
+ "completions/min_length": 256.0,
872
+ "completions/max_length": 256.0,
873
+ "completions/clipped_ratio": 1.0,
874
+ "completions/mean_terminated_length": 0.0,
875
+ "completions/min_terminated_length": 0.0,
876
+ "completions/max_terminated_length": 0.0,
877
+ "rewards/reward_completions/mean": -8.0,
878
+ "rewards/reward_completions/std": 0.0,
879
+ "reward": -8.0,
880
+ "reward_std": 0.0,
881
+ "frac_reward_zero_std": 1.0,
882
+ "entropy": 0.6306,
883
+ "clip_ratio/low_mean": 0.0,
884
+ "clip_ratio/low_min": 0.0,
885
+ "clip_ratio/high_mean": 0.0,
886
+ "clip_ratio/high_max": 0.0,
887
+ "clip_ratio/region_mean": 0.0,
888
+ "step_time": 14.61,
889
+ "epoch": 0.7778,
890
+ "completion_length": 256.0,
891
+ "clipped_ratio": 1.0,
892
+ "step": 28
893
+ },
894
+ {
895
+ "loss": 0.3016,
896
+ "grad_norm": 1.609,
897
+ "learning_rate": 6.667e-08,
898
+ "num_tokens": 82100.0,
899
+ "completions/mean_length": 139.5,
900
+ "completions/min_length": 80.0,
901
+ "completions/max_length": 199.0,
902
+ "completions/clipped_ratio": 0.0,
903
+ "completions/mean_terminated_length": 139.5,
904
+ "completions/min_terminated_length": 80.0,
905
+ "completions/max_terminated_length": 199.0,
906
+ "rewards/reward_completions/mean": -3.454,
907
+ "rewards/reward_completions/std": 6.429,
908
+ "reward": -3.454,
909
+ "reward_std": 6.429,
910
+ "frac_reward_zero_std": 0.0,
911
+ "entropy": 1.362,
912
+ "clip_ratio/low_mean": 0.0,
913
+ "clip_ratio/low_min": 0.0,
914
+ "clip_ratio/high_mean": 0.0,
915
+ "clip_ratio/high_max": 0.0,
916
+ "clip_ratio/region_mean": 0.0,
917
+ "step_time": 11.6,
918
+ "epoch": 0.8056,
919
+ "completion_length": 139.5,
920
+ "clipped_ratio": 0.0,
921
+ "step": 29
922
+ },
923
+ {
924
+ "loss": 0.0,
925
+ "grad_norm": 0.0,
926
+ "learning_rate": 3.333e-08,
927
+ "num_tokens": 84690.0,
928
+ "completions/mean_length": 256.0,
929
+ "completions/min_length": 256.0,
930
+ "completions/max_length": 256.0,
931
+ "completions/clipped_ratio": 1.0,
932
+ "completions/mean_terminated_length": 0.0,
933
+ "completions/min_terminated_length": 0.0,
934
+ "completions/max_terminated_length": 0.0,
935
+ "rewards/reward_completions/mean": -8.0,
936
+ "rewards/reward_completions/std": 0.0,
937
+ "reward": -8.0,
938
+ "reward_std": 0.0,
939
+ "frac_reward_zero_std": 1.0,
940
+ "entropy": 0.04163,
941
+ "clip_ratio/low_mean": 0.0,
942
+ "clip_ratio/low_min": 0.0,
943
+ "clip_ratio/high_mean": 0.0,
944
+ "clip_ratio/high_max": 0.0,
945
+ "clip_ratio/region_mean": 0.0,
946
+ "step_time": 14.61,
947
+ "epoch": 0.8333,
948
+ "completion_length": 256.0,
949
+ "clipped_ratio": 1.0,
950
+ "step": 30
951
+ }
952
+ ],
953
+ "reward_batches": [
954
+ {
955
+ "call": 1,
956
+ "count": 2,
957
+ "invalid_actions": 0,
958
+ "invalid_payloads": 2,
959
+ "max_reward": -8.0,
960
+ "mean_reward": -8.0,
961
+ "message": "reward_batch",
962
+ "min_reward": -8.0,
963
+ "role": "center"
964
+ },
965
+ {
966
+ "call": 10,
967
+ "count": 2,
968
+ "invalid_actions": 0,
969
+ "invalid_payloads": 2,
970
+ "max_reward": -8.0,
971
+ "mean_reward": -8.0,
972
+ "message": "reward_batch",
973
+ "min_reward": -8.0,
974
+ "role": "center"
975
+ },
976
+ {
977
+ "call": 20,
978
+ "count": 2,
979
+ "invalid_actions": 0,
980
+ "invalid_payloads": 0,
981
+ "max_reward": 2.672,
982
+ "mean_reward": 2.672,
983
+ "message": "reward_batch",
984
+ "min_reward": 2.672,
985
+ "role": "center"
986
+ },
987
+ {
988
+ "call": 30,
989
+ "count": 2,
990
+ "invalid_actions": 0,
991
+ "invalid_payloads": 2,
992
+ "max_reward": -8.0,
993
+ "mean_reward": -8.0,
994
+ "message": "reward_batch",
995
+ "min_reward": -8.0,
996
+ "role": "center"
997
+ }
998
+ ]
999
+ },
1000
+ "warehouse": {
1001
+ "source_log": "results\\warehouse_train_job.log",
1002
+ "steps": [
1003
+ {
1004
+ "loss": 0.0,
1005
+ "grad_norm": 0.0,
1006
+ "learning_rate": 1e-06,
1007
+ "num_tokens": 4050.0,
1008
+ "completions/mean_length": 256.0,
1009
+ "completions/min_length": 256.0,
1010
+ "completions/max_length": 256.0,
1011
+ "completions/clipped_ratio": 1.0,
1012
+ "completions/mean_terminated_length": 0.0,
1013
+ "completions/min_terminated_length": 0.0,
1014
+ "completions/max_terminated_length": 0.0,
1015
+ "rewards/reward_completions/mean": -8.0,
1016
+ "rewards/reward_completions/std": 0.0,
1017
+ "reward": -8.0,
1018
+ "reward_std": 0.0,
1019
+ "frac_reward_zero_std": 1.0,
1020
+ "entropy": 0.4094,
1021
+ "clip_ratio/low_mean": 0.0,
1022
+ "clip_ratio/low_min": 0.0,
1023
+ "clip_ratio/high_mean": 0.0,
1024
+ "clip_ratio/high_max": 0.0,
1025
+ "clip_ratio/region_mean": 0.0,
1026
+ "step_time": 15.48,
1027
+ "epoch": 0.02778,
1028
+ "completion_length": 256.0,
1029
+ "clipped_ratio": 1.0,
1030
+ "step": 1
1031
+ },
1032
+ {
1033
+ "loss": 0.3127,
1034
+ "grad_norm": 1.122,
1035
+ "learning_rate": 9.667e-07,
1036
+ "num_tokens": 6999.0,
1037
+ "completions/mean_length": 177.5,
1038
+ "completions/min_length": 99.0,
1039
+ "completions/max_length": 256.0,
1040
+ "completions/clipped_ratio": 0.5,
1041
+ "completions/mean_terminated_length": 99.0,
1042
+ "completions/min_terminated_length": 99.0,
1043
+ "completions/max_terminated_length": 99.0,
1044
+ "rewards/reward_completions/mean": -3.53,
1045
+ "rewards/reward_completions/std": 6.322,
1046
+ "reward": -3.53,
1047
+ "reward_std": 6.322,
1048
+ "frac_reward_zero_std": 0.0,
1049
+ "entropy": 0.4915,
1050
+ "clip_ratio/low_mean": 0.0,
1051
+ "clip_ratio/low_min": 0.0,
1052
+ "clip_ratio/high_mean": 0.0,
1053
+ "clip_ratio/high_max": 0.0,
1054
+ "clip_ratio/region_mean": 0.0,
1055
+ "step_time": 14.84,
1056
+ "epoch": 0.05556,
1057
+ "completion_length": 177.5,
1058
+ "clipped_ratio": 0.5,
1059
+ "step": 2
1060
+ },
1061
+ {
1062
+ "loss": 0.0,
1063
+ "grad_norm": 0.0,
1064
+ "learning_rate": 9.333e-07,
1065
+ "num_tokens": 11900.0,
1066
+ "completions/mean_length": 256.0,
1067
+ "completions/min_length": 256.0,
1068
+ "completions/max_length": 256.0,
1069
+ "completions/clipped_ratio": 1.0,
1070
+ "completions/mean_terminated_length": 0.0,
1071
+ "completions/min_terminated_length": 0.0,
1072
+ "completions/max_terminated_length": 0.0,
1073
+ "rewards/reward_completions/mean": -8.0,
1074
+ "rewards/reward_completions/std": 0.0,
1075
+ "reward": -8.0,
1076
+ "reward_std": 0.0,
1077
+ "frac_reward_zero_std": 1.0,
1078
+ "entropy": 0.2992,
1079
+ "clip_ratio/low_mean": 0.0,
1080
+ "clip_ratio/low_min": 0.0,
1081
+ "clip_ratio/high_mean": 0.0,
1082
+ "clip_ratio/high_max": 0.0,
1083
+ "clip_ratio/region_mean": 0.0,
1084
+ "step_time": 15.08,
1085
+ "epoch": 0.08333,
1086
+ "completion_length": 256.0,
1087
+ "clipped_ratio": 1.0,
1088
+ "step": 3
1089
+ },
1090
+ {
1091
+ "loss": 0.0,
1092
+ "grad_norm": 0.0,
1093
+ "learning_rate": 9e-07,
1094
+ "num_tokens": 14640.0,
1095
+ "completions/mean_length": 97.0,
1096
+ "completions/min_length": 32.0,
1097
+ "completions/max_length": 162.0,
1098
+ "completions/clipped_ratio": 0.0,
1099
+ "completions/mean_terminated_length": 97.0,
1100
+ "completions/min_terminated_length": 32.0,
1101
+ "completions/max_terminated_length": 162.0,
1102
+ "rewards/reward_completions/mean": 0.8633,
1103
+ "rewards/reward_completions/std": 0.0,
1104
+ "reward": 0.8633,
1105
+ "reward_std": 0.0,
1106
+ "frac_reward_zero_std": 1.0,
1107
+ "entropy": 1.096,
1108
+ "clip_ratio/low_mean": 0.0,
1109
+ "clip_ratio/low_min": 0.0,
1110
+ "clip_ratio/high_mean": 0.0,
1111
+ "clip_ratio/high_max": 0.0,
1112
+ "clip_ratio/region_mean": 0.0,
1113
+ "step_time": 9.737,
1114
+ "epoch": 0.1111,
1115
+ "completion_length": 97.0,
1116
+ "clipped_ratio": 0.0,
1117
+ "step": 4
1118
+ },
1119
+ {
1120
+ "loss": 0.0,
1121
+ "grad_norm": 0.0,
1122
+ "learning_rate": 8.667e-07,
1123
+ "num_tokens": 17530.0,
1124
+ "completions/mean_length": 171.0,
1125
+ "completions/min_length": 86.0,
1126
+ "completions/max_length": 256.0,
1127
+ "completions/clipped_ratio": 0.5,
1128
+ "completions/mean_terminated_length": 86.0,
1129
+ "completions/min_terminated_length": 86.0,
1130
+ "completions/max_terminated_length": 86.0,
1131
+ "rewards/reward_completions/mean": -8.0,
1132
+ "rewards/reward_completions/std": 0.0,
1133
+ "reward": -8.0,
1134
+ "reward_std": 0.0,
1135
+ "frac_reward_zero_std": 1.0,
1136
+ "entropy": 0.2295,
1137
+ "clip_ratio/low_mean": 0.0,
1138
+ "clip_ratio/low_min": 0.0,
1139
+ "clip_ratio/high_mean": 0.0,
1140
+ "clip_ratio/high_max": 0.0,
1141
+ "clip_ratio/region_mean": 0.0,
1142
+ "step_time": 14.84,
1143
+ "epoch": 0.1389,
1144
+ "completion_length": 171.0,
1145
+ "clipped_ratio": 0.5,
1146
+ "step": 5
1147
+ },
1148
+ {
1149
+ "loss": 0.0,
1150
+ "grad_norm": 0.0,
1151
+ "learning_rate": 8.333e-07,
1152
+ "num_tokens": 20420.0,
1153
+ "completions/mean_length": 221.5,
1154
+ "completions/min_length": 187.0,
1155
+ "completions/max_length": 256.0,
1156
+ "completions/clipped_ratio": 0.5,
1157
+ "completions/mean_terminated_length": 187.0,
1158
+ "completions/min_terminated_length": 187.0,
1159
+ "completions/max_terminated_length": 187.0,
1160
+ "rewards/reward_completions/mean": -8.0,
1161
+ "rewards/reward_completions/std": 0.0,
1162
+ "reward": -8.0,
1163
+ "reward_std": 0.0,
1164
+ "frac_reward_zero_std": 1.0,
1165
+ "entropy": 0.3646,
1166
+ "clip_ratio/low_mean": 0.0,
1167
+ "clip_ratio/low_min": 0.0,
1168
+ "clip_ratio/high_mean": 0.0,
1169
+ "clip_ratio/high_max": 0.0,
1170
+ "clip_ratio/region_mean": 0.0,
1171
+ "step_time": 14.81,
1172
+ "epoch": 0.1667,
1173
+ "completion_length": 221.5,
1174
+ "clipped_ratio": 0.5,
1175
+ "step": 6
1176
+ },
1177
+ {
1178
+ "loss": 0.0,
1179
+ "grad_norm": 0.0,
1180
+ "learning_rate": 8e-07,
1181
+ "num_tokens": 24280.0,
1182
+ "completions/mean_length": 256.0,
1183
+ "completions/min_length": 256.0,
1184
+ "completions/max_length": 256.0,
1185
+ "completions/clipped_ratio": 1.0,
1186
+ "completions/mean_terminated_length": 0.0,
1187
+ "completions/min_terminated_length": 0.0,
1188
+ "completions/max_terminated_length": 0.0,
1189
+ "rewards/reward_completions/mean": -8.0,
1190
+ "rewards/reward_completions/std": 0.0,
1191
+ "reward": -8.0,
1192
+ "reward_std": 0.0,
1193
+ "frac_reward_zero_std": 1.0,
1194
+ "entropy": 0.2839,
1195
+ "clip_ratio/low_mean": 0.0,
1196
+ "clip_ratio/low_min": 0.0,
1197
+ "clip_ratio/high_mean": 0.0,
1198
+ "clip_ratio/high_max": 0.0,
1199
+ "clip_ratio/region_mean": 0.0,
1200
+ "step_time": 14.82,
1201
+ "epoch": 0.1944,
1202
+ "completion_length": 256.0,
1203
+ "clipped_ratio": 1.0,
1204
+ "step": 7
1205
+ },
1206
+ {
1207
+ "loss": 0.0,
1208
+ "grad_norm": 0.0,
1209
+ "learning_rate": 7.667e-07,
1210
+ "num_tokens": 27330.0,
1211
+ "completions/mean_length": 21.5,
1212
+ "completions/min_length": 19.0,
1213
+ "completions/max_length": 24.0,
1214
+ "completions/clipped_ratio": 0.0,
1215
+ "completions/mean_terminated_length": 21.5,
1216
+ "completions/min_terminated_length": 19.0,
1217
+ "completions/max_terminated_length": 24.0,
1218
+ "rewards/reward_completions/mean": -8.0,
1219
+ "rewards/reward_completions/std": 0.0,
1220
+ "reward": -8.0,
1221
+ "reward_std": 0.0,
1222
+ "frac_reward_zero_std": 1.0,
1223
+ "entropy": 1.141,
1224
+ "clip_ratio/low_mean": 0.0,
1225
+ "clip_ratio/low_min": 0.0,
1226
+ "clip_ratio/high_mean": 0.0,
1227
+ "clip_ratio/high_max": 0.0,
1228
+ "clip_ratio/region_mean": 0.0,
1229
+ "step_time": 2.069,
1230
+ "epoch": 0.2222,
1231
+ "completion_length": 21.5,
1232
+ "clipped_ratio": 0.0,
1233
+ "step": 8
1234
+ },
1235
+ {
1236
+ "loss": 0.2284,
1237
+ "grad_norm": 1.003,
1238
+ "learning_rate": 7.333e-07,
1239
+ "num_tokens": 30430.0,
1240
+ "completions/mean_length": 193.5,
1241
+ "completions/min_length": 131.0,
1242
+ "completions/max_length": 256.0,
1243
+ "completions/clipped_ratio": 0.5,
1244
+ "completions/mean_terminated_length": 131.0,
1245
+ "completions/min_terminated_length": 131.0,
1246
+ "completions/max_terminated_length": 131.0,
1247
+ "rewards/reward_completions/mean": -3.516,
1248
+ "rewards/reward_completions/std": 6.342,
1249
+ "reward": -3.516,
1250
+ "reward_std": 6.342,
1251
+ "frac_reward_zero_std": 0.0,
1252
+ "entropy": 0.4621,
1253
+ "clip_ratio/low_mean": 0.0,
1254
+ "clip_ratio/low_min": 0.0,
1255
+ "clip_ratio/high_mean": 0.0,
1256
+ "clip_ratio/high_max": 0.0,
1257
+ "clip_ratio/region_mean": 0.0,
1258
+ "step_time": 14.85,
1259
+ "epoch": 0.25,
1260
+ "completion_length": 193.5,
1261
+ "clipped_ratio": 0.5,
1262
+ "step": 9
1263
+ },
1264
+ {
1265
+ "loss": -0.3379,
1266
+ "grad_norm": 1.762,
1267
+ "learning_rate": 7e-07,
1268
+ "num_tokens": 33690.0,
1269
+ "completions/mean_length": 124.5,
1270
+ "completions/min_length": 65.0,
1271
+ "completions/max_length": 184.0,
1272
+ "completions/clipped_ratio": 0.0,
1273
+ "completions/mean_terminated_length": 124.5,
1274
+ "completions/min_terminated_length": 65.0,
1275
+ "completions/max_terminated_length": 184.0,
1276
+ "rewards/reward_completions/mean": -4.32,
1277
+ "rewards/reward_completions/std": 5.205,
1278
+ "reward": -4.32,
1279
+ "reward_std": 5.205,
1280
+ "frac_reward_zero_std": 0.0,
1281
+ "entropy": 0.4933,
1282
+ "clip_ratio/low_mean": 0.0,
1283
+ "clip_ratio/low_min": 0.0,
1284
+ "clip_ratio/high_mean": 0.0,
1285
+ "clip_ratio/high_max": 0.0,
1286
+ "clip_ratio/region_mean": 0.0,
1287
+ "step_time": 10.8,
1288
+ "epoch": 0.2778,
1289
+ "completion_length": 124.5,
1290
+ "clipped_ratio": 0.0,
1291
+ "step": 10
1292
+ },
1293
+ {
1294
+ "loss": 0.09742,
1295
+ "grad_norm": 0.6973,
1296
+ "learning_rate": 6.667e-07,
1297
+ "num_tokens": 36580.0,
1298
+ "completions/mean_length": 225.0,
1299
+ "completions/min_length": 194.0,
1300
+ "completions/max_length": 256.0,
1301
+ "completions/clipped_ratio": 0.5,
1302
+ "completions/mean_terminated_length": 194.0,
1303
+ "completions/min_terminated_length": 194.0,
1304
+ "completions/max_terminated_length": 194.0,
1305
+ "rewards/reward_completions/mean": -4.728,
1306
+ "rewards/reward_completions/std": 4.628,
1307
+ "reward": -4.728,
1308
+ "reward_std": 4.628,
1309
+ "frac_reward_zero_std": 0.0,
1310
+ "entropy": 0.3318,
1311
+ "clip_ratio/low_mean": 0.0,
1312
+ "clip_ratio/low_min": 0.0,
1313
+ "clip_ratio/high_mean": 0.0,
1314
+ "clip_ratio/high_max": 0.0,
1315
+ "clip_ratio/region_mean": 0.0,
1316
+ "step_time": 14.69,
1317
+ "epoch": 0.3056,
1318
+ "completion_length": 225.0,
1319
+ "clipped_ratio": 0.5,
1320
+ "step": 11
1321
+ },
1322
+ {
1323
+ "loss": 0.0,
1324
+ "grad_norm": 0.0,
1325
+ "learning_rate": 6.333e-07,
1326
+ "num_tokens": 39430.0,
1327
+ "completions/mean_length": 256.0,
1328
+ "completions/min_length": 256.0,
1329
+ "completions/max_length": 256.0,
1330
+ "completions/clipped_ratio": 1.0,
1331
+ "completions/mean_terminated_length": 0.0,
1332
+ "completions/min_terminated_length": 0.0,
1333
+ "completions/max_terminated_length": 0.0,
1334
+ "rewards/reward_completions/mean": -8.0,
1335
+ "rewards/reward_completions/std": 0.0,
1336
+ "reward": -8.0,
1337
+ "reward_std": 0.0,
1338
+ "frac_reward_zero_std": 1.0,
1339
+ "entropy": 0.5381,
1340
+ "clip_ratio/low_mean": 0.0,
1341
+ "clip_ratio/low_min": 0.0,
1342
+ "clip_ratio/high_mean": 0.0,
1343
+ "clip_ratio/high_max": 0.0,
1344
+ "clip_ratio/region_mean": 0.0,
1345
+ "step_time": 14.71,
1346
+ "epoch": 0.3333,
1347
+ "completion_length": 256.0,
1348
+ "clipped_ratio": 1.0,
1349
+ "step": 12
1350
+ },
1351
+ {
1352
+ "loss": 0.0,
1353
+ "grad_norm": 0.0,
1354
+ "learning_rate": 6e-07,
1355
+ "num_tokens": 42910.0,
1356
+ "completions/mean_length": 140.5,
1357
+ "completions/min_length": 140.0,
1358
+ "completions/max_length": 141.0,
1359
+ "completions/clipped_ratio": 0.0,
1360
+ "completions/mean_terminated_length": 140.5,
1361
+ "completions/min_terminated_length": 140.0,
1362
+ "completions/max_terminated_length": 141.0,
1363
+ "rewards/reward_completions/mean": 0.51,
1364
+ "rewards/reward_completions/std": 0.0,
1365
+ "reward": 0.51,
1366
+ "reward_std": 0.0,
1367
+ "frac_reward_zero_std": 1.0,
1368
+ "entropy": 0.4382,
1369
+ "clip_ratio/low_mean": 0.0,
1370
+ "clip_ratio/low_min": 0.0,
1371
+ "clip_ratio/high_mean": 0.0,
1372
+ "clip_ratio/high_max": 0.0,
1373
+ "clip_ratio/region_mean": 0.0,
1374
+ "step_time": 8.593,
1375
+ "epoch": 0.3611,
1376
+ "completion_length": 140.5,
1377
+ "clipped_ratio": 0.0,
1378
+ "step": 13
1379
+ },
1380
+ {
1381
+ "loss": 0.0,
1382
+ "grad_norm": 0.0,
1383
+ "learning_rate": 5.667e-07,
1384
+ "num_tokens": 46500.0,
1385
+ "completions/mean_length": 256.0,
1386
+ "completions/min_length": 256.0,
1387
+ "completions/max_length": 256.0,
1388
+ "completions/clipped_ratio": 1.0,
1389
+ "completions/mean_terminated_length": 0.0,
1390
+ "completions/min_terminated_length": 0.0,
1391
+ "completions/max_terminated_length": 0.0,
1392
+ "rewards/reward_completions/mean": -8.0,
1393
+ "rewards/reward_completions/std": 0.0,
1394
+ "reward": -8.0,
1395
+ "reward_std": 0.0,
1396
+ "frac_reward_zero_std": 1.0,
1397
+ "entropy": 0.3101,
1398
+ "clip_ratio/low_mean": 0.0,
1399
+ "clip_ratio/low_min": 0.0,
1400
+ "clip_ratio/high_mean": 0.0,
1401
+ "clip_ratio/high_max": 0.0,
1402
+ "clip_ratio/region_mean": 0.0,
1403
+ "step_time": 14.95,
1404
+ "epoch": 0.3889,
1405
+ "completion_length": 256.0,
1406
+ "clipped_ratio": 1.0,
1407
+ "step": 14
1408
+ },
1409
+ {
1410
+ "loss": 0.0,
1411
+ "grad_norm": 0.0,
1412
+ "learning_rate": 5.333e-07,
1413
+ "num_tokens": 49590.0,
1414
+ "completions/mean_length": 256.0,
1415
+ "completions/min_length": 256.0,
1416
+ "completions/max_length": 256.0,
1417
+ "completions/clipped_ratio": 1.0,
1418
+ "completions/mean_terminated_length": 0.0,
1419
+ "completions/min_terminated_length": 0.0,
1420
+ "completions/max_terminated_length": 0.0,
1421
+ "rewards/reward_completions/mean": -8.0,
1422
+ "rewards/reward_completions/std": 0.0,
1423
+ "reward": -8.0,
1424
+ "reward_std": 0.0,
1425
+ "frac_reward_zero_std": 1.0,
1426
+ "entropy": 0.06061,
1427
+ "clip_ratio/low_mean": 0.0,
1428
+ "clip_ratio/low_min": 0.0,
1429
+ "clip_ratio/high_mean": 0.0,
1430
+ "clip_ratio/high_max": 0.0,
1431
+ "clip_ratio/region_mean": 0.0,
1432
+ "step_time": 14.74,
1433
+ "epoch": 0.4167,
1434
+ "completion_length": 256.0,
1435
+ "clipped_ratio": 1.0,
1436
+ "step": 15
1437
+ },
1438
+ {
1439
+ "loss": 0.0,
1440
+ "grad_norm": 0.0,
1441
+ "learning_rate": 5e-07,
1442
+ "num_tokens": 53260.0,
1443
+ "completions/mean_length": 256.0,
1444
+ "completions/min_length": 256.0,
1445
+ "completions/max_length": 256.0,
1446
+ "completions/clipped_ratio": 1.0,
1447
+ "completions/mean_terminated_length": 0.0,
1448
+ "completions/min_terminated_length": 0.0,
1449
+ "completions/max_terminated_length": 0.0,
1450
+ "rewards/reward_completions/mean": -8.0,
1451
+ "rewards/reward_completions/std": 0.0,
1452
+ "reward": -8.0,
1453
+ "reward_std": 0.0,
1454
+ "frac_reward_zero_std": 1.0,
1455
+ "entropy": 0.4906,
1456
+ "clip_ratio/low_mean": 0.0,
1457
+ "clip_ratio/low_min": 0.0,
1458
+ "clip_ratio/high_mean": 0.0,
1459
+ "clip_ratio/high_max": 0.0,
1460
+ "clip_ratio/region_mean": 0.0,
1461
+ "step_time": 14.9,
1462
+ "epoch": 0.4444,
1463
+ "completion_length": 256.0,
1464
+ "clipped_ratio": 1.0,
1465
+ "step": 16
1466
+ },
1467
+ {
1468
+ "loss": 0.0,
1469
+ "grad_norm": 0.0,
1470
+ "learning_rate": 4.667e-07,
1471
+ "num_tokens": 56880.0,
1472
+ "completions/mean_length": 256.0,
1473
+ "completions/min_length": 256.0,
1474
+ "completions/max_length": 256.0,
1475
+ "completions/clipped_ratio": 1.0,
1476
+ "completions/mean_terminated_length": 0.0,
1477
+ "completions/min_terminated_length": 0.0,
1478
+ "completions/max_terminated_length": 0.0,
1479
+ "rewards/reward_completions/mean": -8.0,
1480
+ "rewards/reward_completions/std": 0.0,
1481
+ "reward": -8.0,
1482
+ "reward_std": 0.0,
1483
+ "frac_reward_zero_std": 1.0,
1484
+ "entropy": 0.1981,
1485
+ "clip_ratio/low_mean": 0.0,
1486
+ "clip_ratio/low_min": 0.0,
1487
+ "clip_ratio/high_mean": 0.0,
1488
+ "clip_ratio/high_max": 0.0,
1489
+ "clip_ratio/region_mean": 0.0,
1490
+ "step_time": 14.74,
1491
+ "epoch": 0.4722,
1492
+ "completion_length": 256.0,
1493
+ "clipped_ratio": 1.0,
1494
+ "step": 17
1495
+ },
1496
+ {
1497
+ "loss": 0.6388,
1498
+ "grad_norm": 1.889,
1499
+ "learning_rate": 4.333e-07,
1500
+ "num_tokens": 60150.0,
1501
+ "completions/mean_length": 134.5,
1502
+ "completions/min_length": 13.0,
1503
+ "completions/max_length": 256.0,
1504
+ "completions/clipped_ratio": 0.5,
1505
+ "completions/mean_terminated_length": 13.0,
1506
+ "completions/min_terminated_length": 13.0,
1507
+ "completions/max_terminated_length": 13.0,
1508
+ "rewards/reward_completions/mean": -3.513,
1509
+ "rewards/reward_completions/std": 6.346,
1510
+ "reward": -3.513,
1511
+ "reward_std": 6.346,
1512
+ "frac_reward_zero_std": 0.0,
1513
+ "entropy": 0.5667,
1514
+ "clip_ratio/low_mean": 0.0,
1515
+ "clip_ratio/low_min": 0.0,
1516
+ "clip_ratio/high_mean": 0.0,
1517
+ "clip_ratio/high_max": 0.0,
1518
+ "clip_ratio/region_mean": 0.0,
1519
+ "step_time": 14.92,
1520
+ "epoch": 0.5,
1521
+ "completion_length": 134.5,
1522
+ "clipped_ratio": 0.5,
1523
+ "step": 18
1524
+ },
1525
+ {
1526
+ "loss": 0.5243,
1527
+ "grad_norm": 1.268,
1528
+ "learning_rate": 4e-07,
1529
+ "num_tokens": 62860.0,
1530
+ "completions/mean_length": 147.0,
1531
+ "completions/min_length": 38.0,
1532
+ "completions/max_length": 256.0,
1533
+ "completions/clipped_ratio": 0.5,
1534
+ "completions/mean_terminated_length": 38.0,
1535
+ "completions/min_terminated_length": 38.0,
1536
+ "completions/max_terminated_length": 38.0,
1537
+ "rewards/reward_completions/mean": -3.716,
1538
+ "rewards/reward_completions/std": 6.059,
1539
+ "reward": -3.716,
1540
+ "reward_std": 6.059,
1541
+ "frac_reward_zero_std": 0.0,
1542
+ "entropy": 0.8373,
1543
+ "clip_ratio/low_mean": 0.0,
1544
+ "clip_ratio/low_min": 0.0,
1545
+ "clip_ratio/high_mean": 0.0,
1546
+ "clip_ratio/high_max": 0.0,
1547
+ "clip_ratio/region_mean": 0.0,
1548
+ "step_time": 14.79,
1549
+ "epoch": 0.5278,
1550
+ "completion_length": 147.0,
1551
+ "clipped_ratio": 0.5,
1552
+ "step": 19
1553
+ },
1554
+ {
1555
+ "loss": 0.0,
1556
+ "grad_norm": 0.0,
1557
+ "learning_rate": 3.667e-07,
1558
+ "num_tokens": 65780.0,
1559
+ "completions/mean_length": 77.0,
1560
+ "completions/min_length": 64.0,
1561
+ "completions/max_length": 90.0,
1562
+ "completions/clipped_ratio": 0.0,
1563
+ "completions/mean_terminated_length": 77.0,
1564
+ "completions/min_terminated_length": 64.0,
1565
+ "completions/max_terminated_length": 90.0,
1566
+ "rewards/reward_completions/mean": 0.932,
1567
+ "rewards/reward_completions/std": 0.0,
1568
+ "reward": 0.932,
1569
+ "reward_std": 0.0,
1570
+ "frac_reward_zero_std": 1.0,
1571
+ "entropy": 0.7881,
1572
+ "clip_ratio/low_mean": 0.0,
1573
+ "clip_ratio/low_min": 0.0,
1574
+ "clip_ratio/high_mean": 0.0,
1575
+ "clip_ratio/high_max": 0.0,
1576
+ "clip_ratio/region_mean": 0.0,
1577
+ "step_time": 5.699,
1578
+ "epoch": 0.5556,
1579
+ "completion_length": 77.0,
1580
+ "clipped_ratio": 0.0,
1581
+ "step": 20
1582
+ },
1583
+ {
1584
+ "loss": 0.0,
1585
+ "grad_norm": 0.0,
1586
+ "learning_rate": 3.333e-07,
1587
+ "num_tokens": 70160.0,
1588
+ "completions/mean_length": 256.0,
1589
+ "completions/min_length": 256.0,
1590
+ "completions/max_length": 256.0,
1591
+ "completions/clipped_ratio": 1.0,
1592
+ "completions/mean_terminated_length": 0.0,
1593
+ "completions/min_terminated_length": 0.0,
1594
+ "completions/max_terminated_length": 0.0,
1595
+ "rewards/reward_completions/mean": -8.0,
1596
+ "rewards/reward_completions/std": 0.0,
1597
+ "reward": -8.0,
1598
+ "reward_std": 0.0,
1599
+ "frac_reward_zero_std": 1.0,
1600
+ "entropy": 0.5528,
1601
+ "clip_ratio/low_mean": 0.0,
1602
+ "clip_ratio/low_min": 0.0,
1603
+ "clip_ratio/high_mean": 0.0,
1604
+ "clip_ratio/high_max": 0.0,
1605
+ "clip_ratio/region_mean": 0.0,
1606
+ "step_time": 14.82,
1607
+ "epoch": 0.5833,
1608
+ "completion_length": 256.0,
1609
+ "clipped_ratio": 1.0,
1610
+ "step": 21
1611
+ },
1612
+ {
1613
+ "loss": 0.0,
1614
+ "grad_norm": 0.0,
1615
+ "learning_rate": 3e-07,
1616
+ "num_tokens": 73480.0,
1617
+ "completions/mean_length": 256.0,
1618
+ "completions/min_length": 256.0,
1619
+ "completions/max_length": 256.0,
1620
+ "completions/clipped_ratio": 1.0,
1621
+ "completions/mean_terminated_length": 0.0,
1622
+ "completions/min_terminated_length": 0.0,
1623
+ "completions/max_terminated_length": 0.0,
1624
+ "rewards/reward_completions/mean": -8.0,
1625
+ "rewards/reward_completions/std": 0.0,
1626
+ "reward": -8.0,
1627
+ "reward_std": 0.0,
1628
+ "frac_reward_zero_std": 1.0,
1629
+ "entropy": 0.3867,
1630
+ "clip_ratio/low_mean": 0.0,
1631
+ "clip_ratio/low_min": 0.0,
1632
+ "clip_ratio/high_mean": 0.0,
1633
+ "clip_ratio/high_max": 0.0,
1634
+ "clip_ratio/region_mean": 0.0,
1635
+ "step_time": 14.77,
1636
+ "epoch": 0.6111,
1637
+ "completion_length": 256.0,
1638
+ "clipped_ratio": 1.0,
1639
+ "step": 22
1640
+ },
1641
+ {
1642
+ "loss": 0.2431,
1643
+ "grad_norm": 1.327,
1644
+ "learning_rate": 2.667e-07,
1645
+ "num_tokens": 76920.0,
1646
+ "completions/mean_length": 190.5,
1647
+ "completions/min_length": 125.0,
1648
+ "completions/max_length": 256.0,
1649
+ "completions/clipped_ratio": 0.5,
1650
+ "completions/mean_terminated_length": 125.0,
1651
+ "completions/min_terminated_length": 125.0,
1652
+ "completions/max_terminated_length": 125.0,
1653
+ "rewards/reward_completions/mean": -3.758,
1654
+ "rewards/reward_completions/std": 5.999,
1655
+ "reward": -3.758,
1656
+ "reward_std": 5.999,
1657
+ "frac_reward_zero_std": 0.0,
1658
+ "entropy": 0.6645,
1659
+ "clip_ratio/low_mean": 0.0,
1660
+ "clip_ratio/low_min": 0.0,
1661
+ "clip_ratio/high_mean": 0.0,
1662
+ "clip_ratio/high_max": 0.0,
1663
+ "clip_ratio/region_mean": 0.0,
1664
+ "step_time": 14.8,
1665
+ "epoch": 0.6389,
1666
+ "completion_length": 190.5,
1667
+ "clipped_ratio": 0.5,
1668
+ "step": 23
1669
+ },
1670
+ {
1671
+ "loss": 0.04159,
1672
+ "grad_norm": 5.867,
1673
+ "learning_rate": 2.333e-07,
1674
+ "num_tokens": 79280.0,
1675
+ "completions/mean_length": 25.5,
1676
+ "completions/min_length": 24.0,
1677
+ "completions/max_length": 27.0,
1678
+ "completions/clipped_ratio": 0.0,
1679
+ "completions/mean_terminated_length": 25.5,
1680
+ "completions/min_terminated_length": 24.0,
1681
+ "completions/max_terminated_length": 27.0,
1682
+ "rewards/reward_completions/mean": -3.545,
1683
+ "rewards/reward_completions/std": 6.3,
1684
+ "reward": -3.545,
1685
+ "reward_std": 6.3,
1686
+ "frac_reward_zero_std": 0.0,
1687
+ "entropy": 1.493,
1688
+ "clip_ratio/low_mean": 0.0,
1689
+ "clip_ratio/low_min": 0.0,
1690
+ "clip_ratio/high_mean": 0.0,
1691
+ "clip_ratio/high_max": 0.0,
1692
+ "clip_ratio/region_mean": 0.0,
1693
+ "step_time": 2.284,
1694
+ "epoch": 0.6667,
1695
+ "completion_length": 25.5,
1696
+ "clipped_ratio": 0.0,
1697
+ "step": 24
1698
+ },
1699
+ {
1700
+ "loss": 0.5813,
1701
+ "grad_norm": 1.224,
1702
+ "learning_rate": 2e-07,
1703
+ "num_tokens": 81420.0,
1704
+ "completions/mean_length": 140.5,
1705
+ "completions/min_length": 25.0,
1706
+ "completions/max_length": 256.0,
1707
+ "completions/clipped_ratio": 0.5,
1708
+ "completions/mean_terminated_length": 25.0,
1709
+ "completions/min_terminated_length": 25.0,
1710
+ "completions/max_terminated_length": 25.0,
1711
+ "rewards/reward_completions/mean": -3.538,
1712
+ "rewards/reward_completions/std": 6.31,
1713
+ "reward": -3.538,
1714
+ "reward_std": 6.31,
1715
+ "frac_reward_zero_std": 0.0,
1716
+ "entropy": 0.5115,
1717
+ "clip_ratio/low_mean": 0.0,
1718
+ "clip_ratio/low_min": 0.0,
1719
+ "clip_ratio/high_mean": 0.0,
1720
+ "clip_ratio/high_max": 0.0,
1721
+ "clip_ratio/region_mean": 0.0,
1722
+ "step_time": 14.88,
1723
+ "epoch": 0.6944,
1724
+ "completion_length": 140.5,
1725
+ "clipped_ratio": 0.5,
1726
+ "step": 25
1727
+ },
1728
+ {
1729
+ "loss": 0.5813,
1730
+ "grad_norm": 1.274,
1731
+ "learning_rate": 1.667e-07,
1732
+ "num_tokens": 84420.0,
1733
+ "completions/mean_length": 140.5,
1734
+ "completions/min_length": 25.0,
1735
+ "completions/max_length": 256.0,
1736
+ "completions/clipped_ratio": 0.5,
1737
+ "completions/mean_terminated_length": 25.0,
1738
+ "completions/min_terminated_length": 25.0,
1739
+ "completions/max_terminated_length": 25.0,
1740
+ "rewards/reward_completions/mean": -3.514,
1741
+ "rewards/reward_completions/std": 6.344,
1742
+ "reward": -3.514,
1743
+ "reward_std": 6.344,
1744
+ "frac_reward_zero_std": 0.0,
1745
+ "entropy": 0.5967,
1746
+ "clip_ratio/low_mean": 0.0,
1747
+ "clip_ratio/low_min": 0.0,
1748
+ "clip_ratio/high_mean": 0.0,
1749
+ "clip_ratio/high_max": 0.0,
1750
+ "clip_ratio/region_mean": 0.0,
1751
+ "step_time": 14.89,
1752
+ "epoch": 0.7222,
1753
+ "completion_length": 140.5,
1754
+ "clipped_ratio": 0.5,
1755
+ "step": 26
1756
+ },
1757
+ {
1758
+ "loss": 0.0,
1759
+ "grad_norm": 0.0,
1760
+ "learning_rate": 1.333e-07,
1761
+ "num_tokens": 86700.0,
1762
+ "completions/mean_length": 256.0,
1763
+ "completions/min_length": 256.0,
1764
+ "completions/max_length": 256.0,
1765
+ "completions/clipped_ratio": 1.0,
1766
+ "completions/mean_terminated_length": 0.0,
1767
+ "completions/min_terminated_length": 0.0,
1768
+ "completions/max_terminated_length": 0.0,
1769
+ "rewards/reward_completions/mean": -8.0,
1770
+ "rewards/reward_completions/std": 0.0,
1771
+ "reward": -8.0,
1772
+ "reward_std": 0.0,
1773
+ "frac_reward_zero_std": 1.0,
1774
+ "entropy": 0.4072,
1775
+ "clip_ratio/low_mean": 0.0,
1776
+ "clip_ratio/low_min": 0.0,
1777
+ "clip_ratio/high_mean": 0.0,
1778
+ "clip_ratio/high_max": 0.0,
1779
+ "clip_ratio/region_mean": 0.0,
1780
+ "step_time": 14.78,
1781
+ "epoch": 0.75,
1782
+ "completion_length": 256.0,
1783
+ "clipped_ratio": 1.0,
1784
+ "step": 27
1785
+ },
1786
+ {
1787
+ "loss": 0.0,
1788
+ "grad_norm": 0.0,
1789
+ "learning_rate": 1e-07,
1790
+ "num_tokens": 89350.0,
1791
+ "completions/mean_length": 256.0,
1792
+ "completions/min_length": 256.0,
1793
+ "completions/max_length": 256.0,
1794
+ "completions/clipped_ratio": 1.0,
1795
+ "completions/mean_terminated_length": 0.0,
1796
+ "completions/min_terminated_length": 0.0,
1797
+ "completions/max_terminated_length": 0.0,
1798
+ "rewards/reward_completions/mean": -8.0,
1799
+ "rewards/reward_completions/std": 0.0,
1800
+ "reward": -8.0,
1801
+ "reward_std": 0.0,
1802
+ "frac_reward_zero_std": 1.0,
1803
+ "entropy": 0.5724,
1804
+ "clip_ratio/low_mean": 0.0,
1805
+ "clip_ratio/low_min": 0.0,
1806
+ "clip_ratio/high_mean": 0.0,
1807
+ "clip_ratio/high_max": 0.0,
1808
+ "clip_ratio/region_mean": 0.0,
1809
+ "step_time": 14.85,
1810
+ "epoch": 0.7778,
1811
+ "completion_length": 256.0,
1812
+ "clipped_ratio": 1.0,
1813
+ "step": 28
1814
+ },
1815
+ {
1816
+ "loss": 0.0,
1817
+ "grad_norm": 0.0,
1818
+ "learning_rate": 6.667e-08,
1819
+ "num_tokens": 92410.0,
1820
+ "completions/mean_length": 151.5,
1821
+ "completions/min_length": 47.0,
1822
+ "completions/max_length": 256.0,
1823
+ "completions/clipped_ratio": 0.5,
1824
+ "completions/mean_terminated_length": 47.0,
1825
+ "completions/min_terminated_length": 47.0,
1826
+ "completions/max_terminated_length": 47.0,
1827
+ "rewards/reward_completions/mean": -8.0,
1828
+ "rewards/reward_completions/std": 0.0,
1829
+ "reward": -8.0,
1830
+ "reward_std": 0.0,
1831
+ "frac_reward_zero_std": 1.0,
1832
+ "entropy": 0.5002,
1833
+ "clip_ratio/low_mean": 0.0,
1834
+ "clip_ratio/low_min": 0.0,
1835
+ "clip_ratio/high_mean": 0.0,
1836
+ "clip_ratio/high_max": 0.0,
1837
+ "clip_ratio/region_mean": 0.0,
1838
+ "step_time": 14.8,
1839
+ "epoch": 0.8056,
1840
+ "completion_length": 151.5,
1841
+ "clipped_ratio": 0.5,
1842
+ "step": 29
1843
+ },
1844
+ {
1845
+ "loss": 0.0,
1846
+ "grad_norm": 0.0,
1847
+ "learning_rate": 3.333e-08,
1848
+ "num_tokens": 94650.0,
1849
+ "completions/mean_length": 229.0,
1850
+ "completions/min_length": 210.0,
1851
+ "completions/max_length": 248.0,
1852
+ "completions/clipped_ratio": 0.0,
1853
+ "completions/mean_terminated_length": 229.0,
1854
+ "completions/min_terminated_length": 210.0,
1855
+ "completions/max_terminated_length": 248.0,
1856
+ "rewards/reward_completions/mean": 0.001667,
1857
+ "rewards/reward_completions/std": 0.0,
1858
+ "reward": 0.001667,
1859
+ "reward_std": 0.0,
1860
+ "frac_reward_zero_std": 1.0,
1861
+ "entropy": 0.79,
1862
+ "clip_ratio/low_mean": 0.0,
1863
+ "clip_ratio/low_min": 0.0,
1864
+ "clip_ratio/high_mean": 0.0,
1865
+ "clip_ratio/high_max": 0.0,
1866
+ "clip_ratio/region_mean": 0.0,
1867
+ "step_time": 14.23,
1868
+ "epoch": 0.8333,
1869
+ "completion_length": 229.0,
1870
+ "clipped_ratio": 0.0,
1871
+ "step": 30
1872
+ }
1873
+ ],
1874
+ "reward_batches": [
1875
+ {
1876
+ "call": 1,
1877
+ "count": 2,
1878
+ "invalid_actions": 0,
1879
+ "invalid_payloads": 2,
1880
+ "max_reward": -8.0,
1881
+ "mean_reward": -8.0,
1882
+ "message": "reward_batch",
1883
+ "min_reward": -8.0,
1884
+ "role": "warehouse"
1885
+ },
1886
+ {
1887
+ "call": 10,
1888
+ "count": 2,
1889
+ "invalid_actions": 0,
1890
+ "invalid_payloads": 1,
1891
+ "max_reward": -0.6396,
1892
+ "mean_reward": -4.3198,
1893
+ "message": "reward_batch",
1894
+ "min_reward": -8.0,
1895
+ "role": "warehouse"
1896
+ },
1897
+ {
1898
+ "call": 20,
1899
+ "count": 2,
1900
+ "invalid_actions": 0,
1901
+ "invalid_payloads": 0,
1902
+ "max_reward": 0.932,
1903
+ "mean_reward": 0.932,
1904
+ "message": "reward_batch",
1905
+ "min_reward": 0.932,
1906
+ "role": "warehouse"
1907
+ },
1908
+ {
1909
+ "call": 30,
1910
+ "count": 2,
1911
+ "invalid_actions": 0,
1912
+ "invalid_payloads": 0,
1913
+ "max_reward": 0.0017,
1914
+ "mean_reward": 0.0017,
1915
+ "message": "reward_batch",
1916
+ "min_reward": 0.0017,
1917
+ "role": "warehouse"
1918
+ }
1919
+ ]
1920
+ }
1921
+ },
1922
+ "training_summary": {
1923
+ "center": {
1924
+ "steps": 30,
1925
+ "reward_batches": 4,
1926
+ "invalid_payloads": 6,
1927
+ "invalid_actions": 0,
1928
+ "first_reward": -8.0,
1929
+ "last_reward": -8.0,
1930
+ "best_reward": 2.848,
1931
+ "mean_reward": -4.0082933333333335,
1932
+ "first_loss": 0.0,
1933
+ "last_loss": 0.0,
1934
+ "mean_loss": 0.14594833333333335,
1935
+ "mean_clipped_ratio": 0.5666666666666667,
1936
+ "mean_completion_length": 207.48333333333332
1937
+ },
1938
+ "warehouse": {
1939
+ "steps": 30,
1940
+ "reward_batches": 4,
1941
+ "invalid_payloads": 3,
1942
+ "invalid_actions": 0,
1943
+ "first_reward": -8.0,
1944
+ "last_reward": 0.001667,
1945
+ "best_reward": 0.932,
1946
+ "mean_reward": -5.4457011,
1947
+ "first_loss": 0.0,
1948
+ "last_loss": 0.0,
1949
+ "mean_loss": 0.09703366666666667,
1950
+ "mean_clipped_ratio": 0.5833333333333334,
1951
+ "mean_completion_length": 189.33333333333334
1952
+ }
1953
+ }
1954
  }
scripts/hf_eval_supplymind_adapters.py CHANGED
@@ -38,7 +38,9 @@ def log(message: str, **fields: Any) -> None:
38
  def parse_args() -> argparse.Namespace:
39
  parser = argparse.ArgumentParser()
40
  parser.add_argument("--role", choices=["center", "warehouse"], required=True)
41
- parser.add_argument("--adapter-id", required=True)
 
 
42
  parser.add_argument("--task-id", default="v2_train_easy")
43
  parser.add_argument("--seeds", default="101,113,127")
44
  parser.add_argument("--max-new-tokens", type=int, default=256)
@@ -197,6 +199,8 @@ def evaluate(role: str, label: str, model: Any, tokenizer: Any, task_id: str, se
197
  def main() -> None:
198
  started = time.time()
199
  args = parse_args()
 
 
200
  prepare_repo()
201
  seeds = [int(value.strip()) for value in args.seeds.split(",") if value.strip()]
202
 
@@ -207,11 +211,23 @@ def main() -> None:
207
  if torch.cuda.is_available():
208
  torch.cuda.empty_cache()
209
 
210
- log("loading_adapter_model", adapter_id=args.adapter_id)
211
- adapter_model, tokenizer = load_model(args.adapter_id)
212
- trained = evaluate(args.role, "adapter", adapter_model, tokenizer, args.task_id, seeds, args.max_new_tokens)
213
-
214
- result = {"message": "eval_done", "elapsed_seconds": round(time.time() - started, 2), "base": base, "adapter": trained}
 
 
 
 
 
 
 
 
 
 
 
 
215
  log(**result)
216
 
217
 
 
38
  def parse_args() -> argparse.Namespace:
39
  parser = argparse.ArgumentParser()
40
  parser.add_argument("--role", choices=["center", "warehouse"], required=True)
41
+ parser.add_argument("--adapter-id", default="")
42
+ parser.add_argument("--sft-adapter-id", default="")
43
+ parser.add_argument("--grpo-adapter-id", default="")
44
  parser.add_argument("--task-id", default="v2_train_easy")
45
  parser.add_argument("--seeds", default="101,113,127")
46
  parser.add_argument("--max-new-tokens", type=int, default=256)
 
199
  def main() -> None:
200
  started = time.time()
201
  args = parse_args()
202
+ if not (args.adapter_id or args.sft_adapter_id or args.grpo_adapter_id):
203
+ raise SystemExit("Provide --adapter-id or --sft-adapter-id/--grpo-adapter-id.")
204
  prepare_repo()
205
  seeds = [int(value.strip()) for value in args.seeds.split(",") if value.strip()]
206
 
 
211
  if torch.cuda.is_available():
212
  torch.cuda.empty_cache()
213
 
214
+ evaluations: dict[str, Any] = {"base": base}
215
+ adapter_specs = []
216
+ if args.adapter_id:
217
+ adapter_specs.append(("adapter", args.adapter_id))
218
+ if args.sft_adapter_id:
219
+ adapter_specs.append(("sft", args.sft_adapter_id))
220
+ if args.grpo_adapter_id:
221
+ adapter_specs.append(("grpo", args.grpo_adapter_id))
222
+ for label, adapter_id in adapter_specs:
223
+ log("loading_adapter_model", label=label, adapter_id=adapter_id)
224
+ adapter_model, tokenizer = load_model(adapter_id)
225
+ evaluations[label] = evaluate(args.role, label, adapter_model, tokenizer, args.task_id, seeds, args.max_new_tokens)
226
+ del adapter_model
227
+ if torch.cuda.is_available():
228
+ torch.cuda.empty_cache()
229
+
230
+ result = {"message": "eval_done", "elapsed_seconds": round(time.time() - started, 2), **evaluations}
231
  log(**result)
232
 
233
 
scripts/hf_sft_supplymind_roles.py ADDED
@@ -0,0 +1,258 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # /// script
2
+ # dependencies = [
3
+ # "torch",
4
+ # "transformers>=4.45.0",
5
+ # "peft>=0.13.0",
6
+ # "accelerate",
7
+ # "datasets",
8
+ # "huggingface_hub",
9
+ # "pydantic",
10
+ # "pyyaml",
11
+ # ]
12
+ # ///
13
+ from __future__ import annotations
14
+
15
+ import argparse
16
+ import inspect
17
+ import json
18
+ import os
19
+ import sys
20
+ import time
21
+ from pathlib import Path
22
+ from statistics import mean
23
+ from typing import Any
24
+
25
+ import torch
26
+ from datasets import Dataset
27
+ from huggingface_hub import snapshot_download
28
+ from peft import LoraConfig, get_peft_model
29
+ from transformers import AutoModelForCausalLM, AutoTokenizer, DataCollatorForLanguageModeling, Trainer, TrainingArguments
30
+
31
+
32
+ REPO_ID = "rishavutk/supplymind"
33
+ MODEL_ID = "Qwen/Qwen2.5-0.5B-Instruct"
34
+
35
+
36
+ def log(message: str, **fields: Any) -> None:
37
+ print(json.dumps({"message": message, **fields}, sort_keys=True), flush=True)
38
+
39
+
40
+ def parse_args() -> argparse.Namespace:
41
+ parser = argparse.ArgumentParser()
42
+ parser.add_argument("--role", choices=["center", "warehouse"], required=True)
43
+ parser.add_argument("--task-id", default="v2_train_easy")
44
+ parser.add_argument("--seeds", default="101,113,127")
45
+ parser.add_argument("--max-steps", type=int, default=80)
46
+ parser.add_argument("--max-length", type=int, default=2048)
47
+ parser.add_argument("--hub-model-id", default="")
48
+ parser.add_argument("--output-dir", default="")
49
+ return parser.parse_args()
50
+
51
+
52
+ def prepare_repo() -> Path:
53
+ os.environ["HF_HUB_DISABLE_PROGRESS_BARS"] = "1"
54
+ os.environ["PYTHONUTF8"] = "1"
55
+ log("downloading_supplymind_space", repo_id=REPO_ID)
56
+ local_dir = Path(
57
+ snapshot_download(
58
+ repo_id=REPO_ID,
59
+ repo_type="space",
60
+ allow_patterns=["src/**", "configs/**"],
61
+ local_dir=Path("supplymind_snapshot").resolve(),
62
+ )
63
+ )
64
+ config_path = local_dir / "configs" / "supplymind_v2_rewards.yaml"
65
+ os.environ["SUPPLYMIND_REWARD_CONFIG"] = str(config_path)
66
+ sys.path.insert(0, str(local_dir / "src"))
67
+ log("repo_ready", path=str(local_dir), config_exists=config_path.exists())
68
+ return local_dir
69
+
70
+
71
+ def compact_observation(observation: Any, role: str) -> dict[str, Any]:
72
+ data = observation.model_dump(mode="json")
73
+ data["scenario_info"].pop("public_rules", None)
74
+ if role == "center":
75
+ return {
76
+ "role": "center",
77
+ "round_index": data["round_index"],
78
+ "remaining_rounds": data["remaining_rounds"],
79
+ "task_id": data["task_id"],
80
+ "scenario_info": data["scenario_info"],
81
+ "center": data["center"],
82
+ "warehouse_summaries": data["center"].get("warehouse_summaries", []),
83
+ "market_signals": data["center"].get("market_signals", []),
84
+ "feedback": data.get("feedback", {}),
85
+ }
86
+ return {
87
+ "role": "warehouse",
88
+ "round_index": data["round_index"],
89
+ "remaining_rounds": data["remaining_rounds"],
90
+ "task_id": data["task_id"],
91
+ "scenario_info": data["scenario_info"],
92
+ "warehouses": data["warehouses"],
93
+ "pending_transfer_proposals": data["center"].get("pending_transfer_proposals", []),
94
+ "feedback": data.get("feedback", {}),
95
+ }
96
+
97
+
98
+ def system_prompt(role: str) -> str:
99
+ if role == "center":
100
+ return (
101
+ "You are the center policy in SupplyMind. Return only strict JSON matching CenterAction: "
102
+ "central_procurements, central_liquidations, central_replenishments, inventory_transfer_proposals, offer_matches. "
103
+ "Warehouses are controlled by a fixed heuristic. Earn margin and a small share of realized service profit, "
104
+ "but avoid waste, stockouts, overpriced actions, and needless shipments."
105
+ )
106
+ return (
107
+ "You are the shared warehouse policy in SupplyMind, copied across all warehouses. "
108
+ "Return only strict JSON with key warehouse_actions mapping warehouse ids to actions. "
109
+ "Use order_decisions, inventory_offers, inventory_requests, transfer_responses, and local_priority. "
110
+ "The center is controlled by a fixed heuristic. Accept orders you can serve, request needed stock, "
111
+ "and reject bad or impossible commitments."
112
+ )
113
+
114
+
115
+ def action_completion(role: str, joint_action: Any) -> str:
116
+ if role == "center":
117
+ payload = joint_action.central_action.model_dump(mode="json")
118
+ else:
119
+ payload = {"warehouse_actions": {key: value.model_dump(mode="json") for key, value in joint_action.warehouse_actions.items()}}
120
+ return json.dumps(payload, separators=(",", ":"))
121
+
122
+
123
+ def build_rows(role: str, task_id: str, seeds: list[int], tokenizer: Any) -> list[dict[str, str]]:
124
+ from supplymind_env_v2.environment import V2SupplyMindEnv
125
+ from supplymind_env_v2.policies import heuristic_joint_policy
126
+
127
+ rows: list[dict[str, str]] = []
128
+ for seed in seeds:
129
+ env = V2SupplyMindEnv(default_task_id=task_id)
130
+ observation = env.reset_internal(task_id, seed)
131
+ while not env.done:
132
+ joint_action = heuristic_joint_policy(observation)
133
+ messages = [
134
+ {"role": "system", "content": system_prompt(role)},
135
+ {"role": "user", "content": json.dumps(compact_observation(observation, role), separators=(",", ":"))},
136
+ {"role": "assistant", "content": action_completion(role, joint_action)},
137
+ ]
138
+ rows.append(
139
+ {
140
+ "text": tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False),
141
+ "task_id": task_id,
142
+ "seed": seed,
143
+ "round_index": observation.round_index,
144
+ }
145
+ )
146
+ result = env.step(joint_action, grade_terminal=False)
147
+ observation = result.observation
148
+ return rows
149
+
150
+
151
+ def baseline_probe(role: str, task_id: str, seeds: list[int]) -> None:
152
+ from supplymind_env_v2.environment import V2SupplyMindEnv
153
+ from supplymind_env_v2.policies import heuristic_joint_policy, no_op_policy
154
+
155
+ for policy_name, policy_fn in (("no_op", no_op_policy), ("heuristic", heuristic_joint_policy)):
156
+ summaries: list[dict[str, Any]] = []
157
+ for seed in seeds:
158
+ env = V2SupplyMindEnv(default_task_id=task_id)
159
+ observation = env.reset_internal(task_id, seed)
160
+ while not env.done:
161
+ result = env.step(policy_fn(observation))
162
+ observation = result.observation
163
+ summaries.append(env.last_episode_summary or {})
164
+ log(
165
+ "baseline_probe",
166
+ role=role,
167
+ policy=policy_name,
168
+ mean_global_score=round(mean(float(row.get("graded_score", 0.0)) for row in summaries), 4),
169
+ mean_center_role_score=round(mean(float(row.get("center_role_score", 0.0)) for row in summaries), 4),
170
+ mean_warehouse_role_score=round(mean(float(row.get("warehouse_role_score", 0.0)) for row in summaries), 4),
171
+ mean_raw_reward=round(mean(float(row.get("raw_reward", 0.0)) for row in summaries), 3),
172
+ )
173
+
174
+
175
+ def tokenize_dataset(dataset: Dataset, tokenizer: Any, max_length: int) -> Dataset:
176
+ def tokenize(batch: dict[str, list[str]]) -> dict[str, Any]:
177
+ return tokenizer(batch["text"], truncation=True, max_length=max_length)
178
+
179
+ return dataset.map(tokenize, batched=True, remove_columns=list(dataset.column_names))
180
+
181
+
182
+ def make_training_args(output_dir: str, max_steps: int, hub_model_id: str, role: str) -> TrainingArguments:
183
+ requested = {
184
+ "output_dir": output_dir,
185
+ "max_steps": max_steps,
186
+ "per_device_train_batch_size": 1,
187
+ "gradient_accumulation_steps": 2,
188
+ "learning_rate": 2e-4,
189
+ "warmup_ratio": 0.03,
190
+ "logging_steps": 1,
191
+ "report_to": [],
192
+ "save_strategy": "no",
193
+ "push_to_hub": False,
194
+ "hub_model_id": hub_model_id,
195
+ "bf16": torch.cuda.is_available() and torch.cuda.is_bf16_supported(),
196
+ "fp16": torch.cuda.is_available() and not torch.cuda.is_bf16_supported(),
197
+ "run_name": f"{role}-sft-smoke",
198
+ }
199
+ signature = inspect.signature(TrainingArguments)
200
+ supported = {key: value for key, value in requested.items() if key in signature.parameters}
201
+ dropped = sorted(set(requested) - set(supported))
202
+ if dropped:
203
+ log("training_args_dropped_unsupported_keys", dropped=dropped)
204
+ return TrainingArguments(**supported)
205
+
206
+
207
+ def main() -> None:
208
+ started = time.time()
209
+ args = parse_args()
210
+ prepare_repo()
211
+ seeds = [int(value.strip()) for value in args.seeds.split(",") if value.strip()]
212
+ output_dir = args.output_dir or f"outputs/supplymind-{args.role}-qwen-sft"
213
+ hub_model_id = args.hub_model_id or f"rishavutk/supplymind-{args.role}-qwen-0.5b-sft"
214
+
215
+ log("loading_tokenizer", model_id=MODEL_ID)
216
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
217
+ if tokenizer.pad_token is None:
218
+ tokenizer.pad_token = tokenizer.eos_token
219
+
220
+ rows = build_rows(args.role, args.task_id, seeds, tokenizer)
221
+ dataset = Dataset.from_list(rows)
222
+ log("dataset_ready", role=args.role, rows=len(rows), task_id=args.task_id, seeds=seeds, hub_model_id=hub_model_id)
223
+ baseline_probe(args.role, args.task_id, seeds)
224
+
225
+ tokenized = tokenize_dataset(dataset, tokenizer, args.max_length)
226
+ log("tokenized_dataset_ready", rows=len(tokenized), max_length=args.max_length)
227
+
228
+ log("loading_model", model_id=MODEL_ID)
229
+ model = AutoModelForCausalLM.from_pretrained(MODEL_ID, torch_dtype="auto", device_map="auto")
230
+ model = get_peft_model(
231
+ model,
232
+ LoraConfig(
233
+ r=16,
234
+ lora_alpha=32,
235
+ lora_dropout=0.05,
236
+ target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
237
+ task_type="CAUSAL_LM",
238
+ ),
239
+ )
240
+ model.print_trainable_parameters()
241
+
242
+ trainer = Trainer(
243
+ model=model,
244
+ args=make_training_args(output_dir, args.max_steps, hub_model_id, args.role),
245
+ train_dataset=tokenized,
246
+ data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False),
247
+ )
248
+ log("training_start", role=args.role, max_steps=args.max_steps)
249
+ trainer.train()
250
+ log("training_done", elapsed_seconds=round(time.time() - started, 2))
251
+ log("pushing_model", hub_model_id=hub_model_id)
252
+ model.push_to_hub(hub_model_id)
253
+ tokenizer.push_to_hub(hub_model_id)
254
+ log("job_done", hub_model_id=hub_model_id, elapsed_seconds=round(time.time() - started, 2))
255
+
256
+
257
+ if __name__ == "__main__":
258
+ main()
scripts/hf_train_supplymind_roles.py CHANGED
@@ -28,7 +28,7 @@ from typing import Any
28
 
29
  from datasets import Dataset
30
  from huggingface_hub import snapshot_download
31
- from peft import LoraConfig
32
  from transformers import AutoModelForCausalLM, AutoTokenizer
33
  from trl import GRPOConfig, GRPOTrainer
34
 
@@ -38,6 +38,8 @@ MODEL_ID = "Qwen/Qwen2.5-0.5B-Instruct"
38
  REWARD_SCALE = 10.0
39
  REWARD_CLIP = 20.0
40
  REWARD_LOG_EVERY = 10
 
 
41
 
42
 
43
  def log(message: str, **fields: Any) -> None:
@@ -54,6 +56,7 @@ def parse_args() -> argparse.Namespace:
54
  parser.add_argument("--max-completion-length", type=int, default=256)
55
  parser.add_argument("--hub-model-id", default="")
56
  parser.add_argument("--output-dir", default="")
 
57
  return parser.parse_args()
58
 
59
 
@@ -204,7 +207,7 @@ def make_reward_fn(role: str):
204
  for completion, current_task, current_seed, current_round in zip(completions, task_id, seed, round_index, strict=True):
205
  payload = extract_json(completion)
206
  if payload is None:
207
- rewards.append(-8.0)
208
  invalid_payloads += 1
209
  continue
210
  env, observation = replay_to_round(current_task, int(current_seed), int(current_round))
@@ -222,7 +225,7 @@ def make_reward_fn(role: str):
222
  else:
223
  action = V2JointAction.model_validate(payload)
224
  except Exception:
225
- rewards.append(-8.0)
226
  invalid_payloads += 1
227
  continue
228
  result = env.step(action, grade_terminal=False)
@@ -236,7 +239,7 @@ def make_reward_fn(role: str):
236
  else:
237
  role_delta = float(result.reward.step_reward)
238
  scaled = max(-REWARD_CLIP, min(REWARD_CLIP, role_delta / REWARD_SCALE))
239
- rewards.append(scaled + 1.0 - 2.0 * invalid_count)
240
  if call_count == 1 or call_count % REWARD_LOG_EVERY == 0:
241
  log(
242
  "reward_batch",
@@ -338,22 +341,29 @@ def main() -> None:
338
  log("loading_model", model_id=MODEL_ID)
339
  tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
340
  model = AutoModelForCausalLM.from_pretrained(MODEL_ID, torch_dtype="auto", device_map="auto")
341
- log("model_loaded", model_id=MODEL_ID)
342
-
343
- trainer = GRPOTrainer(
344
- model=model,
345
- processing_class=tokenizer,
346
- reward_funcs=make_reward_fn(args.role),
347
- train_dataset=dataset,
348
- peft_config=LoraConfig(
349
- r=16,
350
- lora_alpha=32,
351
- lora_dropout=0.05,
352
- target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
353
- task_type="CAUSAL_LM",
354
- ),
355
- args=make_grpo_config(output_dir, args.max_steps, hub_model_id, args.role, args.max_completion_length),
356
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  log("training_start", role=args.role, max_steps=args.max_steps, max_completion_length=args.max_completion_length)
358
  trainer.train()
359
  log("training_done", elapsed_seconds=round(time.time() - started, 2))
 
28
 
29
  from datasets import Dataset
30
  from huggingface_hub import snapshot_download
31
+ from peft import LoraConfig, PeftModel
32
  from transformers import AutoModelForCausalLM, AutoTokenizer
33
  from trl import GRPOConfig, GRPOTrainer
34
 
 
38
  REWARD_SCALE = 10.0
39
  REWARD_CLIP = 20.0
40
  REWARD_LOG_EVERY = 10
41
+ MALFORMED_REWARD = -2.0
42
+ INVALID_ACTION_PENALTY = 0.5
43
 
44
 
45
  def log(message: str, **fields: Any) -> None:
 
56
  parser.add_argument("--max-completion-length", type=int, default=256)
57
  parser.add_argument("--hub-model-id", default="")
58
  parser.add_argument("--output-dir", default="")
59
+ parser.add_argument("--init-adapter-id", default="")
60
  return parser.parse_args()
61
 
62
 
 
207
  for completion, current_task, current_seed, current_round in zip(completions, task_id, seed, round_index, strict=True):
208
  payload = extract_json(completion)
209
  if payload is None:
210
+ rewards.append(MALFORMED_REWARD)
211
  invalid_payloads += 1
212
  continue
213
  env, observation = replay_to_round(current_task, int(current_seed), int(current_round))
 
225
  else:
226
  action = V2JointAction.model_validate(payload)
227
  except Exception:
228
+ rewards.append(MALFORMED_REWARD)
229
  invalid_payloads += 1
230
  continue
231
  result = env.step(action, grade_terminal=False)
 
239
  else:
240
  role_delta = float(result.reward.step_reward)
241
  scaled = max(-REWARD_CLIP, min(REWARD_CLIP, role_delta / REWARD_SCALE))
242
+ rewards.append(scaled + 1.0 - INVALID_ACTION_PENALTY * invalid_count)
243
  if call_count == 1 or call_count % REWARD_LOG_EVERY == 0:
244
  log(
245
  "reward_batch",
 
341
  log("loading_model", model_id=MODEL_ID)
342
  tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
343
  model = AutoModelForCausalLM.from_pretrained(MODEL_ID, torch_dtype="auto", device_map="auto")
344
+ peft_config = LoraConfig(
345
+ r=16,
346
+ lora_alpha=32,
347
+ lora_dropout=0.05,
348
+ target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
349
+ task_type="CAUSAL_LM",
 
 
 
 
 
 
 
 
 
350
  )
351
+ if args.init_adapter_id:
352
+ log("loading_initial_adapter", adapter_id=args.init_adapter_id)
353
+ model = PeftModel.from_pretrained(model, args.init_adapter_id, is_trainable=True)
354
+ peft_config = None
355
+ log("model_loaded", model_id=MODEL_ID, init_adapter_id=args.init_adapter_id or None)
356
+
357
+ trainer_kwargs = {
358
+ "model": model,
359
+ "processing_class": tokenizer,
360
+ "reward_funcs": make_reward_fn(args.role),
361
+ "train_dataset": dataset,
362
+ "args": make_grpo_config(output_dir, args.max_steps, hub_model_id, args.role, args.max_completion_length),
363
+ }
364
+ if peft_config is not None:
365
+ trainer_kwargs["peft_config"] = peft_config
366
+ trainer = GRPOTrainer(**trainer_kwargs)
367
  log("training_start", role=args.role, max_steps=args.max_steps, max_completion_length=args.max_completion_length)
368
  trainer.train()
369
  log("training_done", elapsed_seconds=round(time.time() - started, 2))
scripts/parse_training_logs.py ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Parse HF training job logs into the local training dashboard JSON."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import ast
7
+ import json
8
+ import re
9
+ from datetime import datetime
10
+ from pathlib import Path
11
+ from statistics import mean
12
+ from typing import Any
13
+
14
+
15
+ DEFAULT_OUTPUT = Path("results/training_dashboard.json")
16
+ ANSI_RE = re.compile(r"\x1b\[[0-?]*[ -/]*[@-~]")
17
+ ROLE_RE = re.compile(r"\b(center|warehouse)\b", re.IGNORECASE)
18
+
19
+
20
+ def read_text(path: Path) -> str:
21
+ """Read UTF-8 and PowerShell UTF-16 redirected logs."""
22
+ data = path.read_bytes()
23
+ if data.startswith((b"\xff\xfe", b"\xfe\xff")):
24
+ return data.decode("utf-16")
25
+ if data[:200].count(b"\x00") > 20:
26
+ return data.decode("utf-16-le")
27
+
28
+ for encoding in ("utf-8-sig", "utf-16", "utf-16-le", "utf-8", "cp1252"):
29
+ try:
30
+ return data.decode(encoding)
31
+ except UnicodeDecodeError:
32
+ continue
33
+ return data.decode("utf-8", errors="replace")
34
+
35
+
36
+ def load_json(path: Path) -> dict[str, Any]:
37
+ if not path.exists():
38
+ return {}
39
+
40
+ text = read_text(path).strip()
41
+ if not text:
42
+ return {}
43
+
44
+ loaded = json.loads(text)
45
+ if not isinstance(loaded, dict):
46
+ raise ValueError(f"{path} must contain a JSON object")
47
+ return loaded
48
+
49
+
50
+ def to_number(value: Any) -> Any:
51
+ if isinstance(value, (int, float)) or value is None:
52
+ return value
53
+ if not isinstance(value, str):
54
+ return value
55
+
56
+ stripped = value.strip()
57
+ if not stripped:
58
+ return value
59
+ try:
60
+ return float(stripped)
61
+ except ValueError:
62
+ return value
63
+
64
+
65
+ def normalize_mapping(values: dict[str, Any]) -> dict[str, Any]:
66
+ return {key: to_number(value) for key, value in values.items()}
67
+
68
+
69
+ def parse_json_line(line: str) -> dict[str, Any] | None:
70
+ try:
71
+ parsed = json.loads(line)
72
+ except json.JSONDecodeError:
73
+ return None
74
+ return parsed if isinstance(parsed, dict) else None
75
+
76
+
77
+ def parse_python_dict_line(line: str) -> dict[str, Any] | None:
78
+ if not (line.startswith("{") and line.endswith("}")):
79
+ return None
80
+ try:
81
+ parsed = ast.literal_eval(line)
82
+ except (SyntaxError, ValueError):
83
+ return None
84
+ return parsed if isinstance(parsed, dict) else None
85
+
86
+
87
+ def looks_like_step(record: dict[str, Any]) -> bool:
88
+ return any(
89
+ key in record
90
+ for key in (
91
+ "loss",
92
+ "reward",
93
+ "rewards/reward_completions/mean",
94
+ "completions/mean_length",
95
+ "completions/clipped_ratio",
96
+ )
97
+ ) and "train_runtime" not in record
98
+
99
+
100
+ def infer_role(path: Path, records: list[dict[str, Any]]) -> str:
101
+ for record in records:
102
+ role = record.get("role")
103
+ if isinstance(role, str) and role.lower() in {"center", "warehouse"}:
104
+ return role.lower()
105
+
106
+ match = ROLE_RE.search(path.stem)
107
+ if match:
108
+ return match.group(1).lower()
109
+
110
+ raise ValueError(f"Could not infer role for {path}; use --center-log or --warehouse-log")
111
+
112
+
113
+ def parse_log(path: Path, role_hint: str | None = None) -> tuple[str, dict[str, Any]]:
114
+ steps: list[dict[str, Any]] = []
115
+ reward_batches: list[dict[str, Any]] = []
116
+ role_records: list[dict[str, Any]] = []
117
+
118
+ for raw_line in read_text(path).splitlines():
119
+ line = ANSI_RE.sub("", raw_line).strip()
120
+ if not line:
121
+ continue
122
+
123
+ json_record = parse_json_line(line)
124
+ if json_record:
125
+ normalized = normalize_mapping(json_record)
126
+ role_records.append(normalized)
127
+ if normalized.get("message") == "reward_batch":
128
+ reward_batches.append(normalized)
129
+ continue
130
+
131
+ dict_record = parse_python_dict_line(line)
132
+ if dict_record and looks_like_step(dict_record):
133
+ step = normalize_mapping(dict_record)
134
+ step.setdefault("reward", step.get("rewards/reward_completions/mean"))
135
+ step.setdefault("completion_length", step.get("completions/mean_length"))
136
+ step.setdefault("clipped_ratio", step.get("completions/clipped_ratio"))
137
+ step["step"] = len(steps) + 1
138
+ steps.append(step)
139
+
140
+ role = role_hint or infer_role(path, role_records)
141
+ return role, {
142
+ "source_log": str(path),
143
+ "steps": steps,
144
+ "reward_batches": reward_batches,
145
+ }
146
+
147
+
148
+ def parse_eval_log(path: Path) -> list[dict[str, Any]]:
149
+ comparisons: list[dict[str, Any]] = []
150
+ for raw_line in read_text(path).splitlines():
151
+ line = ANSI_RE.sub("", raw_line).strip()
152
+ if not line:
153
+ continue
154
+ record = parse_json_line(line)
155
+ if not record or record.get("message") != "eval_result":
156
+ continue
157
+ comparisons.append(normalize_mapping({key: value for key, value in record.items() if key != "episodes"}))
158
+ return comparisons
159
+
160
+
161
+ def average(values: list[Any]) -> float | None:
162
+ numbers = [value for value in values if isinstance(value, (int, float))]
163
+ return mean(numbers) if numbers else None
164
+
165
+
166
+ def summarize(series: dict[str, Any]) -> dict[str, Any]:
167
+ steps = series.get("steps", [])
168
+ reward_batches = series.get("reward_batches", [])
169
+ rewards = [step.get("reward") for step in steps]
170
+ losses = [step.get("loss") for step in steps]
171
+ clipped = [step.get("completions/clipped_ratio") for step in steps]
172
+ lengths = [step.get("completions/mean_length") for step in steps]
173
+
174
+ summary: dict[str, Any] = {
175
+ "steps": len(steps),
176
+ "reward_batches": len(reward_batches),
177
+ "invalid_payloads": sum(int(batch.get("invalid_payloads") or 0) for batch in reward_batches),
178
+ "invalid_actions": sum(int(batch.get("invalid_actions") or 0) for batch in reward_batches),
179
+ }
180
+
181
+ numeric_rewards = [value for value in rewards if isinstance(value, (int, float))]
182
+ if numeric_rewards:
183
+ summary.update(
184
+ {
185
+ "first_reward": rewards[0],
186
+ "last_reward": rewards[-1],
187
+ "best_reward": max(numeric_rewards),
188
+ "mean_reward": average(rewards),
189
+ }
190
+ )
191
+ if losses:
192
+ summary.update(
193
+ {
194
+ "first_loss": losses[0],
195
+ "last_loss": losses[-1],
196
+ "mean_loss": average(losses),
197
+ }
198
+ )
199
+
200
+ mean_clipped = average(clipped)
201
+ mean_length = average(lengths)
202
+ if mean_clipped is not None:
203
+ summary["mean_clipped_ratio"] = mean_clipped
204
+ if mean_length is not None:
205
+ summary["mean_completion_length"] = mean_length
206
+
207
+ return summary
208
+
209
+
210
+ def discover_logs() -> list[tuple[str | None, Path]]:
211
+ return [(None, path) for path in sorted(Path("results").glob("*.log"))]
212
+
213
+
214
+ def build_arg_parser() -> argparse.ArgumentParser:
215
+ parser = argparse.ArgumentParser(description=__doc__)
216
+ parser.add_argument("--center-log", type=Path, help="HF training log for the center role")
217
+ parser.add_argument("--warehouse-log", type=Path, help="HF training log for the warehouse role")
218
+ parser.add_argument("--eval-log", action="append", type=Path, default=[], help="HF eval log containing eval_result JSON rows")
219
+ parser.add_argument("--output", type=Path, default=DEFAULT_OUTPUT, help="Dashboard JSON path")
220
+ parser.add_argument("--status", help="Optional top-level dashboard status")
221
+ parser.add_argument("--updated-at", help="Optional top-level dashboard updated_at value")
222
+ return parser
223
+
224
+
225
+ def main() -> None:
226
+ args = build_arg_parser().parse_args()
227
+
228
+ requested_logs: list[tuple[str | None, Path]] = []
229
+ if args.center_log:
230
+ requested_logs.append(("center", args.center_log))
231
+ if args.warehouse_log:
232
+ requested_logs.append(("warehouse", args.warehouse_log))
233
+ if not requested_logs:
234
+ requested_logs = discover_logs()
235
+
236
+ dashboard = load_json(args.output)
237
+ dashboard.setdefault("training_series", {})
238
+ dashboard.setdefault("training_summary", {})
239
+
240
+ parsed_roles: list[str] = []
241
+ for role_hint, log_path in requested_logs:
242
+ if not log_path.exists():
243
+ raise FileNotFoundError(log_path)
244
+ try:
245
+ role, series = parse_log(log_path, role_hint)
246
+ except ValueError:
247
+ if role_hint is None:
248
+ continue
249
+ raise
250
+ if role not in {"center", "warehouse"}:
251
+ continue
252
+ if not series.get("steps") and not series.get("reward_batches"):
253
+ continue
254
+ dashboard["training_series"][role] = series
255
+ dashboard["training_summary"][role] = summarize(series)
256
+ parsed_roles.append(role)
257
+
258
+ comparisons: list[dict[str, Any]] = []
259
+ for eval_log in args.eval_log:
260
+ if not eval_log.exists():
261
+ raise FileNotFoundError(eval_log)
262
+ comparisons.extend(parse_eval_log(eval_log))
263
+ if comparisons:
264
+ seen: set[tuple[str, str]] = set()
265
+ unique = []
266
+ for row in reversed(comparisons):
267
+ key = (str(row.get("role")), str(row.get("label")))
268
+ if key in seen:
269
+ continue
270
+ seen.add(key)
271
+ unique.append(row)
272
+ dashboard["comparisons"] = list(reversed(unique))
273
+
274
+ if args.status:
275
+ dashboard["status"] = args.status
276
+ if args.updated_at:
277
+ dashboard["updated_at"] = args.updated_at
278
+ elif parsed_roles and "updated_at" not in dashboard:
279
+ dashboard["updated_at"] = datetime.now().astimezone().isoformat(timespec="seconds")
280
+
281
+ args.output.parent.mkdir(parents=True, exist_ok=True)
282
+ args.output.write_text(json.dumps(dashboard, indent=2) + "\n", encoding="utf-8")
283
+ print(f"Wrote {args.output} with roles: {', '.join(parsed_roles) or 'none'}")
284
+
285
+
286
+ if __name__ == "__main__":
287
+ main()
static/dashboard.html CHANGED
@@ -3,46 +3,63 @@
3
  <head>
4
  <meta charset="utf-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <title>SupplyMind Training Dashboard</title>
7
  <style>
8
  :root {
9
- --bg:#eef5fb; --ink:#152033; --muted:#66768d; --panel:#ffffff; --line:#d6e0ea;
10
- --nav:#0f2535; --blue:#2563eb; --cyan:#0891b2; --green:#047857; --red:#b42318; --amber:#b7791f;
 
11
  }
12
  * { box-sizing:border-box; }
13
  body { margin:0; font-family:Inter, Segoe UI, Arial, sans-serif; background:var(--bg); color:var(--ink); }
14
- header { background:var(--nav); color:white; padding:16px 20px; display:flex; justify-content:space-between; align-items:center; gap:14px; flex-wrap:wrap; }
15
- h1 { margin:0; font-size:22px; font-weight:700; }
16
- h2 { margin:0 0 10px; font-size:15px; }
17
- main { padding:16px; display:grid; gap:14px; max-width:1360px; margin:0 auto; }
18
- section, .card { background:var(--panel); border:1px solid var(--line); border-radius:8px; padding:12px; }
19
- .top { display:grid; grid-template-columns:1fr 1fr 1fr 1fr; gap:10px; }
20
- .metric strong { display:block; font-size:24px; margin-top:4px; }
21
- .muted { color:var(--muted); }
22
- .grid { display:grid; grid-template-columns:1.1fr .9fr; gap:14px; }
23
- .plots { display:grid; grid-template-columns:1fr 1fr; gap:14px; }
24
- .status { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
25
- .pill { border-radius:999px; border:1px solid #bfdbfe; background:#eff6ff; color:#1d4ed8; padding:3px 9px; font-size:12px; }
26
- .pill.good { background:#ecfdf5; border-color:#a7f3d0; color:#047857; }
27
- .pill.bad { background:#fef2f2; border-color:#fecaca; color:#b42318; }
28
- .pill.warn { background:#fffbeb; border-color:#fde68a; color:#92400e; }
29
  button, a.button { height:34px; border-radius:6px; border:0; background:var(--blue); color:white; padding:8px 12px; cursor:pointer; text-decoration:none; font:inherit; display:inline-flex; align-items:center; }
30
- a.link { color:#bfdbfe; text-decoration:none; }
31
- table { width:100%; border-collapse:collapse; font-size:13px; }
32
- th,td { padding:8px; border-bottom:1px solid var(--line); text-align:left; vertical-align:top; }
33
- th { color:#42536a; font-weight:600; background:#f8fafc; }
34
- canvas { width:100%; height:300px; display:block; }
35
- .legend { display:flex; gap:12px; flex-wrap:wrap; margin-top:8px; font-size:12px; color:var(--muted); }
 
 
 
 
 
 
 
 
36
  .swatch { width:10px; height:10px; border-radius:2px; display:inline-block; margin-right:5px; }
37
- pre { background:#0f172a; color:#e2e8f0; padding:10px; border-radius:8px; max-height:260px; overflow:auto; font-size:12px; }
38
- @media (max-width:960px) { .top,.grid,.plots { grid-template-columns:1fr; } }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  </style>
40
  </head>
41
  <body>
42
  <header>
43
  <div>
44
- <h1>SupplyMind Training Dashboard</h1>
45
- <div class="muted" style="color:#cbd5e1">Role-specific GRPO smoke runs, adapter evals, and training signals</div>
46
  </div>
47
  <div class="status">
48
  <a class="link" href="/v2/ui">Episode UI</a>
@@ -52,151 +69,362 @@
52
  </header>
53
 
54
  <main>
55
- <section class="top" id="summary"></section>
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
- <div class="plots">
58
  <section>
59
- <h2>Before vs After Scores</h2>
60
- <canvas id="scorePlot" width="760" height="320"></canvas>
61
- <div class="legend">
62
- <span><span class="swatch" style="background:#2563eb"></span>Base</span>
63
- <span><span class="swatch" style="background:#0891b2"></span>Trained adapter</span>
 
64
  </div>
 
65
  </section>
 
66
  <section>
67
- <h2>Invalid Payloads / Actions</h2>
68
- <canvas id="invalidPlot" width="760" height="320"></canvas>
69
- <div class="legend">
70
- <span><span class="swatch" style="background:#b42318"></span>Invalid payloads</span>
71
- <span><span class="swatch" style="background:#b7791f"></span>Invalid actions</span>
 
72
  </div>
 
73
  </section>
74
- </div>
75
 
76
- <div class="grid">
77
  <section>
78
- <h2>Run Status</h2>
79
- <table>
80
- <thead><tr><th>Role</th><th>Job</th><th>Hardware</th><th>Status</th><th>Notes</th></tr></thead>
81
- <tbody id="runs"></tbody>
82
- </table>
 
 
 
83
  </section>
 
84
  <section>
85
- <h2>Eval Details</h2>
86
- <table>
87
- <thead><tr><th>Role</th><th>Model</th><th>Global</th><th>Role Score</th><th>Raw</th></tr></thead>
88
- <tbody id="comparisons"></tbody>
89
- </table>
 
 
 
90
  </section>
91
  </div>
92
 
93
  <section>
94
- <h2>Raw Dashboard JSON</h2>
95
- <pre id="raw">{}</pre>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  </section>
97
  </main>
98
 
99
  <script>
100
  const $ = id => document.getElementById(id);
 
 
 
 
 
 
 
 
 
 
 
101
  const roleScoreKey = role => role === "center" ? "mean_center_role_score" : "mean_warehouse_role_score";
102
- const fmt = value => value === null || value === undefined || Number.isNaN(Number(value)) ? "pending" : Number(value).toFixed(4);
103
- const statusClass = status => status === "completed" ? "good" : status === "error" || status === "canceled" ? "bad" : "warn";
 
 
 
 
104
 
105
  async function load() {
106
- const res = await fetch("/v2/training-results?ts=" + Date.now());
107
- const data = await res.json();
108
- $("loaded").textContent = data.updated_at || data.status || "loaded";
109
- $("raw").textContent = JSON.stringify(data, null, 2);
110
- renderSummary(data);
111
- renderRuns(data.runs || []);
112
- renderComparisons(data.comparisons || []);
113
- drawScorePlot(data.comparisons || []);
114
- drawInvalidPlot(data.comparisons || []);
115
- }
116
-
117
- function renderSummary(data) {
118
- const comps = data.comparisons || [];
119
- const completed = (data.runs || []).filter(r => r.status === "completed").length;
120
- const center = improvement(comps, "center");
121
- const warehouse = improvement(comps, "warehouse");
122
- $("summary").innerHTML = `
123
- <div class="card metric"><span class="muted">Completed jobs</span><strong>${completed}</strong></div>
124
- <div class="card metric"><span class="muted">Center role lift</span><strong>${center}</strong></div>
125
- <div class="card metric"><span class="muted">Warehouse role lift</span><strong>${warehouse}</strong></div>
126
- <div class="card metric"><span class="muted">Hardware</span><strong>${data.hardware || "a10g-small"}</strong></div>`;
127
- }
128
-
129
- function improvement(comps, role) {
130
- const base = comps.find(c => c.role === role && c.label === "base");
131
- const adapter = comps.find(c => c.role === role && c.label === "adapter");
132
- if (!base || !adapter) return "pending";
133
- const key = roleScoreKey(role);
134
- const delta = Number(adapter[key]) - Number(base[key]);
135
- return (delta >= 0 ? "+" : "") + delta.toFixed(4);
136
- }
137
-
138
- function renderRuns(runs) {
139
- $("runs").innerHTML = runs.map(r => `
140
- <tr>
141
- <td>${r.role || ""}</td>
142
- <td><span class="muted">${r.job_id || ""}</span></td>
143
- <td>${r.hardware || ""}</td>
144
- <td><span class="pill ${statusClass(r.status)}">${r.status || "pending"}</span></td>
145
- <td>${r.notes || ""}</td>
146
- </tr>`).join("");
147
  }
148
 
149
- function renderComparisons(comps) {
150
- $("comparisons").innerHTML = comps.map(c => `
151
- <tr>
152
- <td>${c.role}</td>
153
- <td>${c.label}</td>
154
- <td>${fmt(c.mean_global_score)}</td>
155
- <td>${fmt(c[roleScoreKey(c.role)])}</td>
156
- <td>${fmt(c.mean_raw_reward)}</td>
157
- </tr>`).join("");
158
- }
159
-
160
- function drawScorePlot(comps) {
161
- const rows = ["center", "warehouse"].flatMap(role => {
162
- const base = comps.find(c => c.role === role && c.label === "base");
163
- const adapter = comps.find(c => c.role === role && c.label === "adapter");
164
- return [{ label:`${role} base`, value:base?.[roleScoreKey(role)], color:"#2563eb" }, { label:`${role} trained`, value:adapter?.[roleScoreKey(role)], color:"#0891b2" }];
 
165
  });
166
- drawBars("scorePlot", rows, 1.0);
167
- }
168
-
169
- function drawInvalidPlot(comps) {
170
- const rows = comps.flatMap(c => [
171
- { label:`${c.role} ${c.label} payload`, value:c.invalid_payloads, color:"#b42318" },
172
- { label:`${c.role} ${c.label} action`, value:c.invalid_actions, color:"#b7791f" },
173
- ]);
174
- drawBars("invalidPlot", rows, Math.max(1, ...rows.map(r => Number(r.value || 0))));
175
- }
176
-
177
- function drawBars(id, rows, maxValue) {
178
- const canvas = $(id), ctx = canvas.getContext("2d");
179
- ctx.clearRect(0,0,canvas.width,canvas.height);
180
- ctx.font = "12px Segoe UI";
181
- ctx.fillStyle = "#64748b";
182
- ctx.fillText("0", 154, 292);
183
- ctx.fillText(String(maxValue.toFixed ? maxValue.toFixed(2) : maxValue), 690, 292);
184
- rows.forEach((row, i) => {
185
- const y = 26 + i * 34;
186
- const value = Number(row.value || 0);
187
- const width = Math.max(0, Math.min(520, (value / maxValue) * 520));
188
- ctx.fillStyle = "#42536a";
189
- ctx.fillText(row.label, 12, y + 17);
190
- ctx.fillStyle = "#e2e8f0";
191
- ctx.fillRect(155, y, 520, 18);
192
- ctx.fillStyle = row.color;
193
- ctx.fillRect(155, y, width, 18);
194
- ctx.fillStyle = "#172033";
195
- ctx.fillText(fmt(value), 688, y + 14);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  });
197
  }
198
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  $("refresh").onclick = load;
 
200
  load();
201
  </script>
202
  </body>
 
3
  <head>
4
  <meta charset="utf-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>SupplyMind Experiment Analysis</title>
7
  <style>
8
  :root {
9
+ --bg:#f4f7fb; --ink:#172033; --muted:#667085; --panel:#ffffff; --line:#d8e0ea;
10
+ --nav:#102236; --blue:#2563eb; --teal:#0f766e; --red:#c2410c; --amber:#b7791f;
11
+ --green:#047857; --grid:#e8edf3;
12
  }
13
  * { box-sizing:border-box; }
14
  body { margin:0; font-family:Inter, Segoe UI, Arial, sans-serif; background:var(--bg); color:var(--ink); }
15
+ header { background:var(--nav); color:white; padding:18px 22px; display:flex; justify-content:space-between; align-items:center; gap:14px; flex-wrap:wrap; }
16
+ h1 { margin:0; font-size:22px; font-weight:750; letter-spacing:0; }
17
+ h2 { margin:0; font-size:15px; font-weight:700; }
18
+ main { max-width:1440px; margin:0 auto; padding:16px; display:grid; gap:14px; }
19
+ section { background:var(--panel); border:1px solid var(--line); border-radius:8px; padding:14px; }
 
 
 
 
 
 
 
 
 
 
20
  button, a.button { height:34px; border-radius:6px; border:0; background:var(--blue); color:white; padding:8px 12px; cursor:pointer; text-decoration:none; font:inherit; display:inline-flex; align-items:center; }
21
+ a.link { color:#dbeafe; text-decoration:none; }
22
+ .muted { color:var(--muted); }
23
+ .subtle { color:#cbd5e1; font-size:13px; margin-top:4px; }
24
+ .status { display:flex; gap:9px; align-items:center; flex-wrap:wrap; }
25
+ .pill { border-radius:999px; border:1px solid #bfdbfe; background:#eff6ff; color:#1d4ed8; padding:4px 10px; font-size:12px; white-space:nowrap; }
26
+ .summary { display:grid; grid-template-columns:repeat(5, minmax(0, 1fr)); gap:10px; }
27
+ .metric { border:1px solid var(--line); border-radius:8px; padding:11px 12px; background:#fbfdff; min-height:82px; }
28
+ .metric span { display:block; color:var(--muted); font-size:12px; }
29
+ .metric strong { display:block; margin-top:8px; font-size:24px; line-height:1; }
30
+ .metric small { display:block; margin-top:7px; color:var(--muted); font-size:12px; }
31
+ .chart-grid { display:grid; grid-template-columns:1fr 1fr; gap:14px; }
32
+ .wide { grid-column:1 / -1; }
33
+ .chart-head { display:flex; justify-content:space-between; gap:12px; align-items:flex-start; margin-bottom:8px; }
34
+ .legend { display:flex; gap:12px; flex-wrap:wrap; font-size:12px; color:var(--muted); justify-content:flex-end; }
35
  .swatch { width:10px; height:10px; border-radius:2px; display:inline-block; margin-right:5px; }
36
+ canvas { display:block; width:100%; height:320px; }
37
+ .wide canvas { height:360px; }
38
+ table { width:100%; border-collapse:collapse; font-size:13px; }
39
+ th, td { padding:9px 8px; border-bottom:1px solid var(--line); text-align:left; vertical-align:top; }
40
+ th { background:#f8fafc; color:#42536a; font-weight:700; }
41
+ td.number { font-variant-numeric:tabular-nums; }
42
+ .delta.good { color:var(--green); font-weight:700; }
43
+ .delta.bad { color:var(--red); font-weight:700; }
44
+ .empty { color:var(--muted); padding:24px; text-align:center; border:1px dashed var(--line); border-radius:8px; background:#fbfdff; }
45
+ @media (max-width:1100px) {
46
+ .summary { grid-template-columns:repeat(2, minmax(0, 1fr)); }
47
+ .chart-grid { grid-template-columns:1fr; }
48
+ .wide { grid-column:auto; }
49
+ }
50
+ @media (max-width:640px) {
51
+ header { align-items:flex-start; }
52
+ main { padding:10px; }
53
+ .summary { grid-template-columns:1fr; }
54
+ canvas, .wide canvas { height:280px; }
55
+ }
56
  </style>
57
  </head>
58
  <body>
59
  <header>
60
  <div>
61
+ <h1>SupplyMind Experiment Analysis</h1>
62
+ <div class="subtle">Training curves, reward quality, and held-out adapter comparisons</div>
63
  </div>
64
  <div class="status">
65
  <a class="link" href="/v2/ui">Episode UI</a>
 
69
  </header>
70
 
71
  <main>
72
+ <section class="summary" id="summary"></section>
73
+
74
+ <div class="chart-grid">
75
+ <section class="wide">
76
+ <div class="chart-head">
77
+ <h2>Loss Over Step</h2>
78
+ <div class="legend">
79
+ <span><span class="swatch" style="background:#2563eb"></span>center</span>
80
+ <span><span class="swatch" style="background:#0f766e"></span>warehouse</span>
81
+ </div>
82
+ </div>
83
+ <canvas id="lossPlot" width="1200" height="360"></canvas>
84
+ </section>
85
 
 
86
  <section>
87
+ <div class="chart-head">
88
+ <h2>Reward Over Step</h2>
89
+ <div class="legend">
90
+ <span><span class="swatch" style="background:#2563eb"></span>center</span>
91
+ <span><span class="swatch" style="background:#0f766e"></span>warehouse</span>
92
+ </div>
93
  </div>
94
+ <canvas id="rewardPlot" width="760" height="320"></canvas>
95
  </section>
96
+
97
  <section>
98
+ <div class="chart-head">
99
+ <h2>Invalid Payload / Action Batches</h2>
100
+ <div class="legend">
101
+ <span><span class="swatch" style="background:#c2410c"></span>payloads</span>
102
+ <span><span class="swatch" style="background:#b7791f"></span>actions</span>
103
+ </div>
104
  </div>
105
+ <canvas id="invalidPlot" width="760" height="320"></canvas>
106
  </section>
 
107
 
 
108
  <section>
109
+ <div class="chart-head">
110
+ <h2>Completion Length</h2>
111
+ <div class="legend">
112
+ <span><span class="swatch" style="background:#2563eb"></span>center</span>
113
+ <span><span class="swatch" style="background:#0f766e"></span>warehouse</span>
114
+ </div>
115
+ </div>
116
+ <canvas id="lengthPlot" width="760" height="320"></canvas>
117
  </section>
118
+
119
  <section>
120
+ <div class="chart-head">
121
+ <h2>Clipped Ratio</h2>
122
+ <div class="legend">
123
+ <span><span class="swatch" style="background:#2563eb"></span>center</span>
124
+ <span><span class="swatch" style="background:#0f766e"></span>warehouse</span>
125
+ </div>
126
+ </div>
127
+ <canvas id="clipPlot" width="760" height="320"></canvas>
128
  </section>
129
  </div>
130
 
131
  <section>
132
+ <div class="chart-head">
133
+ <h2>Held-out Comparison</h2>
134
+ <div class="muted" id="comparisonNote"></div>
135
+ </div>
136
+ <table>
137
+ <thead>
138
+ <tr>
139
+ <th>Role</th>
140
+ <th>Variant</th>
141
+ <th>Base Global</th>
142
+ <th>Variant Global</th>
143
+ <th>Global Delta</th>
144
+ <th>Base Role</th>
145
+ <th>Variant Role</th>
146
+ <th>Role Delta</th>
147
+ <th>Invalids</th>
148
+ <th>Raw Reward Delta</th>
149
+ </tr>
150
+ </thead>
151
+ <tbody id="heldout"></tbody>
152
+ </table>
153
  </section>
154
  </main>
155
 
156
  <script>
157
  const $ = id => document.getElementById(id);
158
+ const roles = [
159
+ { key:"center", label:"center", color:"#2563eb" },
160
+ { key:"warehouse", label:"warehouse", color:"#0f766e" },
161
+ ];
162
+ const fmt = (value, digits = 3) => {
163
+ const n = Number(value);
164
+ if (!Number.isFinite(n)) return "pending";
165
+ if (Math.abs(n) >= 100) return n.toFixed(1);
166
+ if (Math.abs(n) >= 10) return n.toFixed(2);
167
+ return n.toFixed(digits);
168
+ };
169
  const roleScoreKey = role => role === "center" ? "mean_center_role_score" : "mean_warehouse_role_score";
170
+ const val = (row, keys) => {
171
+ for (const key of keys) {
172
+ if (row && row[key] !== undefined && row[key] !== null && Number.isFinite(Number(row[key]))) return Number(row[key]);
173
+ }
174
+ return null;
175
+ };
176
 
177
  async function load() {
178
+ try {
179
+ const res = await fetch("/v2/training-results?ts=" + Date.now());
180
+ if (!res.ok) throw new Error("HTTP " + res.status);
181
+ const data = await res.json();
182
+ $("loaded").textContent = data.updated_at || data.status || "loaded";
183
+ render(data);
184
+ } catch (error) {
185
+ $("loaded").textContent = "failed";
186
+ $("summary").innerHTML = `<div class="empty" style="grid-column:1/-1">Could not load /v2/training-results: ${escapeHtml(error.message)}</div>`;
187
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  }
189
 
190
+ function render(data) {
191
+ const series = data.training_series || {};
192
+ renderSummary(data, series);
193
+ drawLineChart("lossPlot", lineSeries(series, ["loss"]), "loss");
194
+ drawLineChart("rewardPlot", lineSeries(series, ["reward", "rewards/reward_completions/mean"]), "reward");
195
+ drawInvalidChart("invalidPlot", invalidSeries(series));
196
+ drawLineChart("lengthPlot", lineSeries(series, ["completions/mean_length", "completion_length", "mean_completion_length"]), "tokens");
197
+ drawLineChart("clipPlot", lineSeries(series, ["completions/clipped_ratio", "clipped_ratio"]), "ratio", { minY:0, maxY:1 });
198
+ renderHeldout(data.comparisons || []);
199
+ }
200
+
201
+ function renderSummary(data, series) {
202
+ const summary = data.training_summary || {};
203
+ const allSteps = roles.flatMap(role => (series[role.key]?.steps || []).map(step => ({ role:role.key, step })));
204
+ const lastRows = roles.map(role => {
205
+ const steps = series[role.key]?.steps || [];
206
+ return { role:role.key, row:steps[steps.length - 1], summary:summary[role.key] || {} };
207
  });
208
+ const bestReward = Math.max(...allSteps.map(item => val(item.step, ["reward", "rewards/reward_completions/mean"]) ?? -Infinity));
209
+ const meanClip = avg(lastRows.map(item => item.summary.mean_clipped_ratio));
210
+ const meanLength = avg(lastRows.map(item => item.summary.mean_completion_length));
211
+ const totalInvalidPayloads = roles.reduce((sum, role) => sum + (series[role.key]?.reward_batches || []).reduce((s, b) => s + Number(b.invalid_payloads || 0), 0), 0);
212
+ const totalInvalidActions = roles.reduce((sum, role) => sum + (series[role.key]?.reward_batches || []).reduce((s, b) => s + Number(b.invalid_actions || 0), 0), 0);
213
+ $("summary").innerHTML = [
214
+ metric("Status", data.status || "pending", data.summary || ""),
215
+ metric("Steps", String(Math.max(0, ...lastRows.map(item => Number(item.summary.steps || item.row?.step || 0)))), data.hardware || ""),
216
+ metric("Best reward", bestReward === -Infinity ? "pending" : fmt(bestReward), "highest training step reward"),
217
+ metric("Mean length", fmt(meanLength, 1), "completion tokens"),
218
+ metric("Invalid batches", `${totalInvalidPayloads} / ${totalInvalidActions}`, "payloads / actions"),
219
+ metric("Mean clipped", fmt(meanClip, 3), "across role summaries"),
220
+ ].join("");
221
+ }
222
+
223
+ function metric(label, value, note) {
224
+ return `<div class="metric"><span>${escapeHtml(label)}</span><strong>${escapeHtml(value)}</strong><small>${escapeHtml(note || "")}</small></div>`;
225
+ }
226
+
227
+ function lineSeries(trainingSeries, keys) {
228
+ return roles.map(role => ({
229
+ label: role.label,
230
+ color: role.color,
231
+ points: (trainingSeries[role.key]?.steps || [])
232
+ .map(row => ({ x:val(row, ["step", "global_step"]), y:val(row, keys) }))
233
+ .filter(point => point.x !== null && point.y !== null),
234
+ }));
235
+ }
236
+
237
+ function invalidSeries(trainingSeries) {
238
+ const out = [];
239
+ for (const role of roles) {
240
+ for (const kind of [
241
+ { key:"invalid_payloads", label:"payloads", color:"#c2410c" },
242
+ { key:"invalid_actions", label:"actions", color:"#b7791f" },
243
+ ]) {
244
+ out.push({
245
+ label: `${role.label} ${kind.label}`,
246
+ color: kind.color,
247
+ points: (trainingSeries[role.key]?.reward_batches || [])
248
+ .map(row => ({ x:val(row, ["call", "step"]), y:val(row, [kind.key]) }))
249
+ .filter(point => point.x !== null && point.y !== null),
250
+ });
251
+ }
252
+ }
253
+ return out;
254
+ }
255
+
256
+ function drawLineChart(id, series, yLabel, options = {}) {
257
+ const canvas = $(id);
258
+ const ctx = prepCanvas(canvas);
259
+ const bounds = chartBounds(canvas);
260
+ const points = series.flatMap(s => s.points);
261
+ if (!points.length) return drawEmpty(ctx, canvas, "No training series found");
262
+ const minX = Math.min(...points.map(p => p.x));
263
+ const maxX = Math.max(...points.map(p => p.x));
264
+ let minY = options.minY ?? Math.min(...points.map(p => p.y));
265
+ let maxY = options.maxY ?? Math.max(...points.map(p => p.y));
266
+ if (minY === maxY) { minY -= 1; maxY += 1; }
267
+ drawAxes(ctx, bounds, minX, maxX, minY, maxY, yLabel);
268
+ for (const item of series) {
269
+ drawPath(ctx, bounds, item.points, minX, maxX, minY, maxY, item.color);
270
+ }
271
+ }
272
+
273
+ function drawInvalidChart(id, series) {
274
+ const canvas = $(id);
275
+ const ctx = prepCanvas(canvas);
276
+ const bounds = chartBounds(canvas);
277
+ const points = series.flatMap(s => s.points);
278
+ if (!points.length) return drawEmpty(ctx, canvas, "No reward batch diagnostics found");
279
+ const minX = Math.min(...points.map(p => p.x));
280
+ const maxX = Math.max(...points.map(p => p.x));
281
+ const maxY = Math.max(1, ...points.map(p => p.y));
282
+ drawAxes(ctx, bounds, minX, maxX, 0, maxY, "count");
283
+ series.forEach((item, index) => {
284
+ const offset = (index - 1.5) * 5;
285
+ drawBars(ctx, bounds, item.points, minX, maxX, 0, maxY, item.color, offset);
286
  });
287
  }
288
 
289
+ function prepCanvas(canvas) {
290
+ const ratio = window.devicePixelRatio || 1;
291
+ const rect = canvas.getBoundingClientRect();
292
+ canvas.width = Math.max(320, Math.round(rect.width * ratio));
293
+ canvas.height = Math.max(220, Math.round(rect.height * ratio));
294
+ const ctx = canvas.getContext("2d");
295
+ ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
296
+ ctx.clearRect(0, 0, rect.width, rect.height);
297
+ ctx.font = "12px Segoe UI, Arial";
298
+ ctx.lineCap = "round";
299
+ ctx.lineJoin = "round";
300
+ return ctx;
301
+ }
302
+
303
+ function chartBounds(canvas) {
304
+ const rect = canvas.getBoundingClientRect();
305
+ return { left:52, top:18, right:rect.width - 18, bottom:rect.height - 34, width:rect.width, height:rect.height };
306
+ }
307
+
308
+ function drawAxes(ctx, b, minX, maxX, minY, maxY, yLabel) {
309
+ ctx.strokeStyle = "#d8e0ea";
310
+ ctx.lineWidth = 1;
311
+ ctx.fillStyle = "#667085";
312
+ for (let i = 0; i <= 4; i++) {
313
+ const y = b.bottom - ((b.bottom - b.top) * i / 4);
314
+ const value = minY + ((maxY - minY) * i / 4);
315
+ ctx.beginPath();
316
+ ctx.moveTo(b.left, y);
317
+ ctx.lineTo(b.right, y);
318
+ ctx.stroke();
319
+ ctx.fillText(fmt(value), 8, y + 4);
320
+ }
321
+ ctx.fillText(yLabel, b.left, 11);
322
+ ctx.fillText(String(minX), b.left, b.height - 12);
323
+ ctx.fillText(String(maxX), b.right - 22, b.height - 12);
324
+ }
325
+
326
+ function drawPath(ctx, b, points, minX, maxX, minY, maxY, color) {
327
+ if (!points.length) return;
328
+ ctx.strokeStyle = color;
329
+ ctx.lineWidth = 2.4;
330
+ ctx.beginPath();
331
+ points.forEach((point, index) => {
332
+ const x = scale(point.x, minX, maxX, b.left, b.right);
333
+ const y = scale(point.y, minY, maxY, b.bottom, b.top);
334
+ if (index === 0) ctx.moveTo(x, y);
335
+ else ctx.lineTo(x, y);
336
+ });
337
+ ctx.stroke();
338
+ ctx.fillStyle = color;
339
+ points.forEach(point => {
340
+ const x = scale(point.x, minX, maxX, b.left, b.right);
341
+ const y = scale(point.y, minY, maxY, b.bottom, b.top);
342
+ ctx.beginPath();
343
+ ctx.arc(x, y, 2.7, 0, Math.PI * 2);
344
+ ctx.fill();
345
+ });
346
+ }
347
+
348
+ function drawBars(ctx, b, points, minX, maxX, minY, maxY, color, offset) {
349
+ ctx.fillStyle = color;
350
+ const width = Math.max(3, Math.min(10, (b.right - b.left) / Math.max(12, points.length * 4)));
351
+ for (const point of points) {
352
+ const x = scale(point.x, minX, maxX, b.left, b.right) + offset;
353
+ const y = scale(point.y, minY, maxY, b.bottom, b.top);
354
+ ctx.globalAlpha = 0.82;
355
+ ctx.fillRect(x - width / 2, y, width, b.bottom - y);
356
+ ctx.globalAlpha = 1;
357
+ }
358
+ }
359
+
360
+ function renderHeldout(comparisons) {
361
+ const rows = [];
362
+ for (const role of roles) {
363
+ const base = comparisons.find(row => row.role === role.key && row.label === "base");
364
+ const variants = comparisons.filter(row => row.role === role.key && row.label !== "base");
365
+ for (const variant of variants) rows.push({ role:role.key, base, variant });
366
+ }
367
+ $("comparisonNote").textContent = rows.length ? "base vs SFT / GRPO variants" : "no held-out eval rows";
368
+ $("heldout").innerHTML = rows.length ? rows.map(row => heldoutRow(row)).join("") : `<tr><td colspan="10"><div class="empty">No held-out comparisons available.</div></td></tr>`;
369
+ }
370
+
371
+ function heldoutRow({ role, base, variant }) {
372
+ const roleKey = roleScoreKey(role);
373
+ const globalDelta = Number(variant?.mean_global_score) - Number(base?.mean_global_score);
374
+ const roleDelta = Number(variant?.[roleKey]) - Number(base?.[roleKey]);
375
+ const rawDelta = Number(variant?.mean_raw_reward) - Number(base?.mean_raw_reward);
376
+ const invalids = `${Number(variant?.invalid_payloads ?? 0)} / ${Number(variant?.invalid_actions ?? 0)}`;
377
+ return `
378
+ <tr>
379
+ <td>${escapeHtml(role)}</td>
380
+ <td>${escapeHtml(variant?.label || "variant")}</td>
381
+ <td class="number">${fmt(base?.mean_global_score)}</td>
382
+ <td class="number">${fmt(variant?.mean_global_score)}</td>
383
+ <td class="number ${deltaClass(globalDelta)}">${signed(globalDelta)}</td>
384
+ <td class="number">${fmt(base?.[roleKey])}</td>
385
+ <td class="number">${fmt(variant?.[roleKey])}</td>
386
+ <td class="number ${deltaClass(roleDelta)}">${signed(roleDelta)}</td>
387
+ <td class="number">${invalids}</td>
388
+ <td class="number ${deltaClass(rawDelta)}">${signed(rawDelta, 2)}</td>
389
+ </tr>`;
390
+ }
391
+
392
+ function deltaClass(value) {
393
+ if (!Number.isFinite(value) || value === 0) return "";
394
+ return value > 0 ? "delta good" : "delta bad";
395
+ }
396
+
397
+ function signed(value, digits = 3) {
398
+ if (!Number.isFinite(value)) return "pending";
399
+ return (value >= 0 ? "+" : "") + fmt(value, digits);
400
+ }
401
+
402
+ function scale(value, minIn, maxIn, minOut, maxOut) {
403
+ if (minIn === maxIn) return (minOut + maxOut) / 2;
404
+ return minOut + ((value - minIn) / (maxIn - minIn)) * (maxOut - minOut);
405
+ }
406
+
407
+ function avg(values) {
408
+ const nums = values.map(Number).filter(Number.isFinite);
409
+ return nums.length ? nums.reduce((sum, n) => sum + n, 0) / nums.length : null;
410
+ }
411
+
412
+ function drawEmpty(ctx, canvas, message) {
413
+ const rect = canvas.getBoundingClientRect();
414
+ ctx.fillStyle = "#667085";
415
+ ctx.textAlign = "center";
416
+ ctx.fillText(message, rect.width / 2, rect.height / 2);
417
+ ctx.textAlign = "left";
418
+ }
419
+
420
+ function escapeHtml(value) {
421
+ return String(value ?? "").replace(/[&<>"']/g, char => ({
422
+ "&":"&amp;", "<":"&lt;", ">":"&gt;", '"':"&quot;", "'":"&#39;"
423
+ })[char]);
424
+ }
425
+
426
  $("refresh").onclick = load;
427
+ window.addEventListener("resize", () => load());
428
  load();
429
  </script>
430
  </body>