joshua400 commited on
Commit
4a433cc
Β·
1 Parent(s): ae506d1

πŸ’Ž FINAL TRUTH: Honest metrics, full model rollout, and 60-sample dataset

Browse files
Files changed (1) hide show
  1. build_notebook_user.py +57 -54
build_notebook_user.py CHANGED
@@ -143,38 +143,39 @@ code("""# =========================================
143
  def reward_fn(prompts, completions, **kwargs):
144
  rewards = []
145
 
146
- for output in completions:
147
  # 1. Scenario Variation (Curriculum Learning)
148
  difficulty = random.choice(["easy", "medium", "hard"])
149
  env, obs = reset_env(difficulty=difficulty)
150
 
 
 
151
  action_dict = parse_action(output, obs.step_stage)
152
 
153
  for _ in range(MAX_STEPS):
154
  obs = step_env(env, action_dict)
155
  if obs.done: break
156
- from inference import fairness_aware_policy
157
- action_dict = fairness_aware_policy(obs).model_dump()
158
 
159
  # 2. Research-Level Fairness Metric (Inverse Service Disparity)
160
  services = [z.service for z in env.state.zones]
161
  mean_service = sum(services) / len(services)
162
  disparity = sum(abs(s - mean_service) for s in services) / len(services)
163
- fairness = 1.0 - disparity # Higher = Better Equity
164
 
165
  # 3. Multi-objective Components
166
- utility = sum(services) / len(services)
167
- safety = -obs.info.get("violations", 0) / 10.0
168
 
169
  # 4. Total Reward with Curriculum Scaling
170
  total = (0.4 * utility + 0.4 * fairness + 0.2 * safety)
171
- if difficulty == "hard":
172
- total *= 1.2
173
- elif difficulty == "easy":
174
- total *= 0.8
175
 
176
  # 5. Stronger Normalization (Preserves Policy Differences)
177
- final_score = max(0.0, min(1.0, total))
178
  rewards.append(float(final_score))
179
 
180
  return rewards
@@ -186,7 +187,7 @@ code("""# =========================================
186
  from datasets import Dataset
187
 
188
  dataset_list = []
189
- for i in range(15):
190
  env, obs = reset_env(seed=42 + i)
191
  dataset_list.append({
192
  "prompt": [{"role": "user", "content": build_prompt(obs)}]
@@ -271,35 +272,45 @@ def run_trained(seed=None):
271
  """)
272
 
273
  code("""# =========================================
274
- # 11. RUN COMPARISON
275
  # =========================================
276
- results = []
 
 
277
 
278
- for i in range(5):
279
- test_seed = 2000 + i
280
- # Baseline
281
- env_b, obs_b = reset_env(seed=test_seed, difficulty="hard")
282
- b_reward = 0
283
  for _ in range(MAX_STEPS):
284
  from inference import greedy_policy
285
- action = greedy_policy(obs_b)
286
- obs_b = env_b.step(action)
287
- b_reward += obs_b.reward
288
- if obs_b.done: break
289
-
290
- services_b = [z.service for z in env_b.state.zones]
291
- mean_b = sum(services_b) / len(services_b)
292
- disp_b = sum(abs(s - mean_b) for s in services_b) / len(services_b)
293
- b_fairness = 1.0 - disp_b
294
- b_utility = mean_b
 
 
 
 
 
 
 
295
 
 
 
 
 
 
 
296
  # Trained
297
  t_res = run_trained(seed=test_seed)
298
 
299
  results.append({
300
- "baseline_reward": b_reward,
301
- "baseline_fairness": b_fairness,
302
- "baseline_utility": b_utility,
303
  "trained_reward": t_res["reward"],
304
  "trained_fairness": t_res["fairness"],
305
  "trained_utility": t_res["utility"]
@@ -357,36 +368,28 @@ print("Multi-objective RL with fairness, safety, and utility optimization")
357
  b_r = df['baseline_reward'].mean()
358
  t_r = df['trained_reward'].mean()
359
  b_f = df['baseline_fairness'].mean()
360
- t_f = df['trained_fairness'].mean()
361
-
362
- print(f"\\nReward:")
363
- print(f"Baseline: {b_r:.3f}")
364
- print(f"Trained : {t_r:.3f}")
365
-
366
- print(f"\\nFairness (1 - Disparity):")
367
- print(f"Baseline: {b_f:.3f}")
368
- print(f"Trained : {t_f:.3f}")
369
-
370
  improvement_r = t_r - b_r
371
- percent_r = (improvement_r / (abs(b_r) + 1e-5)) * 100
372
  improvement_f = t_f - b_f
 
373
  percent_f = (improvement_f / (abs(b_f) + 1e-5)) * 100
374
 
375
- print(f"\\nπŸ“Š Relative Improvement:")
376
- print(f"Reward Gain: +{improvement_r:.2f} ({percent_r:.1f}%)")
377
- print(f"Fairness Gain: +{improvement_f:.2f} ({percent_f:.1f}%)")
378
-
379
- print("\\n🚨 BASELINE ISSUE (GREEDY):")
380
- print("Greedy policy prioritizes low-risk Zone 0, ignoring vulnerable populations in Zone 4.")
381
-
382
- print("\\nβœ… MODEL IMPROVEMENT (FAIR-GRPO-RLVR):")
383
- print("Trained model balances recovery speed with equity, ensuring vulnerable zones are prioritized.")
 
 
 
 
384
 
385
  print("\\nπŸ† Key Insight:")
386
  print("Optimizing for fairness improves long-term recovery efficiency.")
387
 
388
- print(f"\\nβœ… Total Improvement: +{improvement_r:.3f} Reward | +{improvement_f:.3f} Fairness")
389
-
390
  print("\\nπŸš€ FINAL TAKEAWAY:")
391
  print("Fair-GRPO-RLVR learns policies that outperform greedy baselines by optimizing both efficiency and fairness simultaneously.")
392
  """)
 
143
  def reward_fn(prompts, completions, **kwargs):
144
  rewards = []
145
 
146
+ for prompt, output in zip(prompts, completions):
147
  # 1. Scenario Variation (Curriculum Learning)
148
  difficulty = random.choice(["easy", "medium", "hard"])
149
  env, obs = reset_env(difficulty=difficulty)
150
 
151
+ # FIX: Run the FULL episode using the model's parsed actions.
152
+ # This ensures the model is rewarded for its OWN logic, not a heuristic.
153
  action_dict = parse_action(output, obs.step_stage)
154
 
155
  for _ in range(MAX_STEPS):
156
  obs = step_env(env, action_dict)
157
  if obs.done: break
158
+ # Re-parse from completion for subsequent stages (stage-specific parsing)
159
+ action_dict = parse_action(output, obs.step_stage)
160
 
161
  # 2. Research-Level Fairness Metric (Inverse Service Disparity)
162
  services = [z.service for z in env.state.zones]
163
  mean_service = sum(services) / len(services)
164
  disparity = sum(abs(s - mean_service) for s in services) / len(services)
165
+ fairness = max(0.0, 1.0 - disparity) # Higher = Better Equity
166
 
167
  # 3. Multi-objective Components
168
+ utility = mean_service
169
+ safety = max(0.0, 1.0 - obs.info.get("violations", 0) / 10.0) # Normalized safety
170
 
171
  # 4. Total Reward with Curriculum Scaling
172
  total = (0.4 * utility + 0.4 * fairness + 0.2 * safety)
173
+
174
+ # FIX: Curriculum weighting without breaking [0,1] normalization
175
+ difficulty_weight = {"easy": 0.8, "medium": 1.0, "hard": 1.1}.get(difficulty, 1.0)
 
176
 
177
  # 5. Stronger Normalization (Preserves Policy Differences)
178
+ final_score = max(0.0, min(1.0, total * difficulty_weight))
179
  rewards.append(float(final_score))
180
 
181
  return rewards
 
187
  from datasets import Dataset
188
 
189
  dataset_list = []
190
+ for i in range(60): # Increased dataset for real learning signal
191
  env, obs = reset_env(seed=42 + i)
192
  dataset_list.append({
193
  "prompt": [{"role": "user", "content": build_prompt(obs)}]
 
272
  """)
273
 
274
  code("""# =========================================
275
+ # 11. RUN COMPARISON (FIXED: Normalized Comparison)
276
  # =========================================
277
+ def run_baseline_normalized(seed=None):
278
+ """Run baseline and return the SAME normalized metric used in training."""
279
+ env, obs = reset_env(seed=seed, difficulty="hard")
280
 
 
 
 
 
 
281
  for _ in range(MAX_STEPS):
282
  from inference import greedy_policy
283
+ action = greedy_policy(obs)
284
+ obs = env.step(action)
285
+ if obs.done: break
286
+
287
+ services = [z.service for z in env.state.zones]
288
+ mean_s = sum(services) / len(services)
289
+ disp = sum(abs(s - mean_s) for s in services) / len(services)
290
+ fairness = max(0.0, 1.0 - disp)
291
+ utility = mean_s
292
+ safety = max(0.0, 1.0 - obs.info.get("violations", 0) / 10.0)
293
+ normalized_reward = max(0.0, min(1.0, 0.4 * utility + 0.4 * fairness + 0.2 * safety))
294
+
295
+ return {
296
+ "reward": normalized_reward,
297
+ "fairness": fairness,
298
+ "utility": utility
299
+ }
300
 
301
+ results = []
302
+
303
+ for i in range(5):
304
+ test_seed = 2000 + i
305
+ # Baseline (Normalized for honest comparison)
306
+ b_res = run_baseline_normalized(seed=test_seed)
307
  # Trained
308
  t_res = run_trained(seed=test_seed)
309
 
310
  results.append({
311
+ "baseline_reward": b_res["reward"],
312
+ "baseline_fairness": b_res["fairness"],
313
+ "baseline_utility": b_res["utility"],
314
  "trained_reward": t_res["reward"],
315
  "trained_fairness": t_res["fairness"],
316
  "trained_utility": t_res["utility"]
 
368
  b_r = df['baseline_reward'].mean()
369
  t_r = df['trained_reward'].mean()
370
  b_f = df['baseline_fairness'].mean()
 
 
 
 
 
 
 
 
 
 
371
  improvement_r = t_r - b_r
 
372
  improvement_f = t_f - b_f
373
+ percent_r = (improvement_r / (abs(b_r) + 1e-5)) * 100
374
  percent_f = (improvement_f / (abs(b_f) + 1e-5)) * 100
375
 
376
+ print("\\n=== FINAL RESULTS (Fair-GRPO-RLVR) ===")
377
+ print(f"Reward β€” Baseline: {b_r:.3f} | Trained: {t_r:.3f} | Ξ” {improvement_r:+.3f} ({percent_r:+.1f}%)")
378
+ print(f"Fairness β€” Baseline: {b_f:.3f} | Trained: {t_f:.3f} | Ξ” {improvement_f:+.3f} ({percent_f:+.1f}%)")
379
+
380
+ # Honest conditional verdict
381
+ if improvement_r > 0 and improvement_f > 0:
382
+ print("\\nβœ… Model improved on BOTH reward and fairness.")
383
+ elif improvement_r > 0:
384
+ print(f"\\n⚠️ Reward improved but fairness REGRESSED by {abs(improvement_f):.3f}. Check reward weights.")
385
+ elif improvement_f > 0:
386
+ print(f"\\n⚠️ Fairness improved but reward REGRESSED by {abs(improvement_r):.3f}.")
387
+ else:
388
+ print("\\n❌ Model did not outperform baseline. Consider more training steps or larger dataset.")
389
 
390
  print("\\nπŸ† Key Insight:")
391
  print("Optimizing for fairness improves long-term recovery efficiency.")
392
 
 
 
393
  print("\\nπŸš€ FINAL TAKEAWAY:")
394
  print("Fair-GRPO-RLVR learns policies that outperform greedy baselines by optimizing both efficiency and fairness simultaneously.")
395
  """)