Spaces:
Sleeping
Sleeping
joshua400 commited on
Commit Β·
4a433cc
1
Parent(s): ae506d1
π FINAL TRUTH: Honest metrics, full model rollout, and 60-sample dataset
Browse files- 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
|
| 157 |
-
action_dict =
|
| 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 =
|
| 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 |
-
|
| 172 |
-
|
| 173 |
-
|
| 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(
|
| 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 |
-
|
|
|
|
|
|
|
| 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(
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 296 |
# Trained
|
| 297 |
t_res = run_trained(seed=test_seed)
|
| 298 |
|
| 299 |
results.append({
|
| 300 |
-
"baseline_reward":
|
| 301 |
-
"baseline_fairness":
|
| 302 |
-
"baseline_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(
|
| 376 |
-
print(f"Reward
|
| 377 |
-
print(f"Fairness
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
print("
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
""")
|