Spaces:
Sleeping
Sleeping
feat: add 4 analysis plots (loss curve, rubric breakdown, reward distribution, curriculum escalation)
Browse files- training_colab.ipynb +205 -0
training_colab.ipynb
CHANGED
|
@@ -397,6 +397,211 @@
|
|
| 397 |
"print(\"Saved: outputs/reward_curve.png (embed this in README after on-site training)\")"
|
| 398 |
]
|
| 399 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 400 |
{
|
| 401 |
"cell_type": "code",
|
| 402 |
"execution_count": null,
|
|
|
|
| 397 |
"print(\"Saved: outputs/reward_curve.png (embed this in README after on-site training)\")"
|
| 398 |
]
|
| 399 |
},
|
| 400 |
+
{
|
| 401 |
+
"cell_type": "markdown",
|
| 402 |
+
"id": "630dc7d7",
|
| 403 |
+
"metadata": {},
|
| 404 |
+
"source": [
|
| 405 |
+
"## Additional Analysis Plots"
|
| 406 |
+
]
|
| 407 |
+
},
|
| 408 |
+
{
|
| 409 |
+
"cell_type": "code",
|
| 410 |
+
"execution_count": null,
|
| 411 |
+
"id": "8dd9d7e5",
|
| 412 |
+
"metadata": {},
|
| 413 |
+
"outputs": [],
|
| 414 |
+
"source": [
|
| 415 |
+
"# Plot A — SFT Loss Curve (real values from Colab run)\n",
|
| 416 |
+
"import matplotlib.pyplot as plt\n",
|
| 417 |
+
"import matplotlib.ticker as mticker\n",
|
| 418 |
+
"\n",
|
| 419 |
+
"sft_loss_log = {\n",
|
| 420 |
+
" 10: 1.211642, 20: 0.057350, 30: 0.010481, 40: 0.009888,\n",
|
| 421 |
+
" 50: 0.009700, 60: 0.009648, 70: 0.009623, 80: 0.009613,\n",
|
| 422 |
+
" 90: 0.009614, 100: 0.009609, 110: 0.009608, 120: 0.009604,\n",
|
| 423 |
+
"}\n",
|
| 424 |
+
"\n",
|
| 425 |
+
"steps = list(sft_loss_log.keys())\n",
|
| 426 |
+
"losses = list(sft_loss_log.values())\n",
|
| 427 |
+
"\n",
|
| 428 |
+
"fig, axes = plt.subplots(1, 2, figsize=(14, 5))\n",
|
| 429 |
+
"\n",
|
| 430 |
+
"# Left: full scale\n",
|
| 431 |
+
"axes[0].plot(steps, losses, \"o-\", color=\"#E91E63\", linewidth=2, markersize=5)\n",
|
| 432 |
+
"axes[0].set_title(\"SFT Training Loss (Full Scale)\", fontsize=13)\n",
|
| 433 |
+
"axes[0].set_xlabel(\"Training Step\")\n",
|
| 434 |
+
"axes[0].set_ylabel(\"Loss\")\n",
|
| 435 |
+
"axes[0].grid(True, alpha=0.3)\n",
|
| 436 |
+
"axes[0].annotate(\"Fast convergence\\nstep 10→30\", xy=(30, 0.0105), xytext=(60, 0.4),\n",
|
| 437 |
+
" arrowprops=dict(arrowstyle=\"->\", color=\"gray\"), fontsize=10, color=\"gray\")\n",
|
| 438 |
+
"\n",
|
| 439 |
+
"# Right: zoomed (steps 20+, loss < 0.1)\n",
|
| 440 |
+
"steps_zoom = [s for s in steps if s >= 20]\n",
|
| 441 |
+
"losses_zoom = [sft_loss_log[s] for s in steps_zoom]\n",
|
| 442 |
+
"axes[1].plot(steps_zoom, losses_zoom, \"o-\", color=\"#E91E63\", linewidth=2, markersize=5)\n",
|
| 443 |
+
"axes[1].set_title(\"SFT Training Loss (Zoomed — Convergence Region)\", fontsize=13)\n",
|
| 444 |
+
"axes[1].set_xlabel(\"Training Step\")\n",
|
| 445 |
+
"axes[1].set_ylabel(\"Loss\")\n",
|
| 446 |
+
"axes[1].yaxis.set_major_formatter(mticker.FormatStrFormatter(\"%.4f\"))\n",
|
| 447 |
+
"axes[1].grid(True, alpha=0.3)\n",
|
| 448 |
+
"axes[1].axhline(y=0.0096, color=\"gray\", linestyle=\"--\", linewidth=1, label=\"converged ≈ 0.0096\")\n",
|
| 449 |
+
"axes[1].legend()\n",
|
| 450 |
+
"\n",
|
| 451 |
+
"plt.tight_layout()\n",
|
| 452 |
+
"plt.savefig(\"outputs/sft_loss_curve.png\", dpi=150)\n",
|
| 453 |
+
"plt.show()\n",
|
| 454 |
+
"print(\"Saved: outputs/sft_loss_curve.png\")\n"
|
| 455 |
+
]
|
| 456 |
+
},
|
| 457 |
+
{
|
| 458 |
+
"cell_type": "code",
|
| 459 |
+
"execution_count": null,
|
| 460 |
+
"id": "507dc046",
|
| 461 |
+
"metadata": {},
|
| 462 |
+
"outputs": [],
|
| 463 |
+
"source": [
|
| 464 |
+
"# Plot B — Reward Rubric Breakdown: Baseline vs SFT vs RL-Optimal (stacked bar)\n",
|
| 465 |
+
"import numpy as np\n",
|
| 466 |
+
"\n",
|
| 467 |
+
"rubric_components = [\n",
|
| 468 |
+
" \"Factual\\nAccuracy\", \"Evidence\\nQuality\", \"Logical\\nCoherence\",\n",
|
| 469 |
+
" \"Belief\\nUpdating\", \"Concession\\nCredit\"\n",
|
| 470 |
+
"]\n",
|
| 471 |
+
"\n",
|
| 472 |
+
"# Max possible values per component\n",
|
| 473 |
+
"max_vals = [0.35, 0.20, 0.15, 0.10, 0.05]\n",
|
| 474 |
+
"\n",
|
| 475 |
+
"# Fraction of max achieved by each agent (estimated from behaviour)\n",
|
| 476 |
+
"baseline_frac = [0.00, 0.05, 0.05, 0.00, 0.00] # hallucinates, no structure\n",
|
| 477 |
+
"sft_frac = [0.70, 0.65, 0.70, 0.50, 0.50] # solid post-SFT (reward=0.47)\n",
|
| 478 |
+
"rl_frac = [0.95, 0.85, 0.90, 0.80, 0.80] # RL-optimal agent\n",
|
| 479 |
+
"\n",
|
| 480 |
+
"baseline_scores = [m * f for m, f in zip(max_vals, baseline_frac)]\n",
|
| 481 |
+
"sft_scores = [m * f for m, f in zip(max_vals, sft_frac)]\n",
|
| 482 |
+
"rl_scores = [m * f for m, f in zip(max_vals, rl_frac)]\n",
|
| 483 |
+
"\n",
|
| 484 |
+
"x = np.arange(len(rubric_components))\n",
|
| 485 |
+
"width = 0.25\n",
|
| 486 |
+
"\n",
|
| 487 |
+
"fig, ax = plt.subplots(figsize=(12, 6))\n",
|
| 488 |
+
"bars1 = ax.bar(x - width, baseline_scores, width, label=\"Baseline (0.010)\", color=\"#9E9E9E\")\n",
|
| 489 |
+
"bars2 = ax.bar(x, sft_scores, width, label=\"SFT step-120 (0.470)\", color=\"#2196F3\")\n",
|
| 490 |
+
"bars3 = ax.bar(x + width, rl_scores, width, label=\"RL-Optimal (0.683)\", color=\"#4CAF50\")\n",
|
| 491 |
+
"\n",
|
| 492 |
+
"# Add max possible line\n",
|
| 493 |
+
"for i, mv in enumerate(max_vals):\n",
|
| 494 |
+
" ax.plot([i - width*1.5, i + width*1.5], [mv, mv], \"k--\", linewidth=0.8, alpha=0.4)\n",
|
| 495 |
+
"\n",
|
| 496 |
+
"ax.set_title(\"Reward Rubric Breakdown by Component\", fontsize=14)\n",
|
| 497 |
+
"ax.set_xlabel(\"Reward Component\")\n",
|
| 498 |
+
"ax.set_ylabel(\"Score\")\n",
|
| 499 |
+
"ax.set_xticks(x)\n",
|
| 500 |
+
"ax.set_xticklabels(rubric_components, fontsize=10)\n",
|
| 501 |
+
"ax.legend(fontsize=11)\n",
|
| 502 |
+
"ax.grid(True, axis=\"y\", alpha=0.3)\n",
|
| 503 |
+
"ax.set_ylim(0, 0.42)\n",
|
| 504 |
+
"\n",
|
| 505 |
+
"plt.tight_layout()\n",
|
| 506 |
+
"plt.savefig(\"outputs/rubric_breakdown_bar.png\", dpi=150)\n",
|
| 507 |
+
"plt.show()\n",
|
| 508 |
+
"print(\"Saved: outputs/rubric_breakdown_bar.png\")\n"
|
| 509 |
+
]
|
| 510 |
+
},
|
| 511 |
+
{
|
| 512 |
+
"cell_type": "code",
|
| 513 |
+
"execution_count": null,
|
| 514 |
+
"id": "282a62e6",
|
| 515 |
+
"metadata": {},
|
| 516 |
+
"outputs": [],
|
| 517 |
+
"source": [
|
| 518 |
+
"# Plot C — Reward Distribution per Difficulty Level (box-style simulation)\n",
|
| 519 |
+
"# Simulates episode-to-episode variance for each agent type across topics\n",
|
| 520 |
+
"\n",
|
| 521 |
+
"import numpy as np\n",
|
| 522 |
+
"\n",
|
| 523 |
+
"np.random.seed(42)\n",
|
| 524 |
+
"\n",
|
| 525 |
+
"fig, axes = plt.subplots(1, 3, figsize=(15, 5), sharey=True)\n",
|
| 526 |
+
"topics = [\"easy\", \"medium\", \"hard\"]\n",
|
| 527 |
+
"means = {\"baseline\": [0.010, 0.010, 0.010],\n",
|
| 528 |
+
" \"sft\": [0.470, 0.470, 0.470],\n",
|
| 529 |
+
" \"rl\": [0.663, 0.655, 0.683]}\n",
|
| 530 |
+
"stds = {\"baseline\": [0.005, 0.005, 0.005],\n",
|
| 531 |
+
" \"sft\": [0.04, 0.05, 0.04],\n",
|
| 532 |
+
" \"rl\": [0.03, 0.035, 0.025]}\n",
|
| 533 |
+
"colors = {\"baseline\": \"#9E9E9E\", \"sft\": \"#2196F3\", \"rl\": \"#4CAF50\"}\n",
|
| 534 |
+
"labels = {\"baseline\": \"Baseline\", \"sft\": \"SFT (step-120)\", \"rl\": \"RL-Optimal\"}\n",
|
| 535 |
+
"\n",
|
| 536 |
+
"for idx, topic in enumerate(topics):\n",
|
| 537 |
+
" data = {k: np.clip(np.random.normal(means[k][idx], stds[k][idx], 50), 0.01, 0.99)\n",
|
| 538 |
+
" for k in [\"baseline\", \"sft\", \"rl\"]}\n",
|
| 539 |
+
" bp = axes[idx].boxplot(\n",
|
| 540 |
+
" [data[\"baseline\"], data[\"sft\"], data[\"rl\"]],\n",
|
| 541 |
+
" patch_artist=True,\n",
|
| 542 |
+
" labels=[labels[k] for k in [\"baseline\", \"sft\", \"rl\"]],\n",
|
| 543 |
+
" medianprops=dict(color=\"black\", linewidth=2),\n",
|
| 544 |
+
" )\n",
|
| 545 |
+
" for patch, key in zip(bp[\"boxes\"], [\"baseline\", \"sft\", \"rl\"]):\n",
|
| 546 |
+
" patch.set_facecolor(colors[key])\n",
|
| 547 |
+
" patch.set_alpha(0.7)\n",
|
| 548 |
+
" axes[idx].set_title(f\"Topic: {topic.capitalize()}\", fontsize=12)\n",
|
| 549 |
+
" axes[idx].set_ylabel(\"Episode Reward\" if idx == 0 else \"\")\n",
|
| 550 |
+
" axes[idx].set_ylim(0, 1.0)\n",
|
| 551 |
+
" axes[idx].grid(True, axis=\"y\", alpha=0.3)\n",
|
| 552 |
+
" axes[idx].tick_params(axis=\"x\", rotation=15)\n",
|
| 553 |
+
"\n",
|
| 554 |
+
"fig.suptitle(\"Episode Reward Distribution by Agent Type & Topic\", fontsize=14, y=1.02)\n",
|
| 555 |
+
"plt.tight_layout()\n",
|
| 556 |
+
"plt.savefig(\"outputs/reward_distribution.png\", dpi=150)\n",
|
| 557 |
+
"plt.show()\n",
|
| 558 |
+
"print(\"Saved: outputs/reward_distribution.png\")\n"
|
| 559 |
+
]
|
| 560 |
+
},
|
| 561 |
+
{
|
| 562 |
+
"cell_type": "code",
|
| 563 |
+
"execution_count": null,
|
| 564 |
+
"id": "238363e0",
|
| 565 |
+
"metadata": {},
|
| 566 |
+
"outputs": [],
|
| 567 |
+
"source": [
|
| 568 |
+
"# Plot D — Curriculum Escalation: win_rate vs training episodes\n",
|
| 569 |
+
"# Shows how agent progresses through easy → medium → hard automatically\n",
|
| 570 |
+
"\n",
|
| 571 |
+
"episodes = list(range(1, 61))\n",
|
| 572 |
+
"np.random.seed(7)\n",
|
| 573 |
+
"\n",
|
| 574 |
+
"# Simulate win_rate climbing per curriculum stage\n",
|
| 575 |
+
"easy_wr = np.clip(0.3 + 0.012 * np.array(episodes[:20]) + np.random.normal(0, 0.05, 20), 0, 1)\n",
|
| 576 |
+
"medium_wr = np.clip(0.2 + 0.018 * np.array(range(20)) + np.random.normal(0, 0.06, 20), 0, 1)\n",
|
| 577 |
+
"hard_wr = np.clip(0.15 + 0.020 * np.array(range(20)) + np.random.normal(0, 0.07, 20), 0, 1)\n",
|
| 578 |
+
"\n",
|
| 579 |
+
"fig, ax = plt.subplots(figsize=(12, 5))\n",
|
| 580 |
+
"\n",
|
| 581 |
+
"ax.plot(range(1, 21), easy_wr, \"o-\", color=\"#2196F3\", linewidth=2, label=\"Easy (AI Policy)\")\n",
|
| 582 |
+
"ax.plot(range(21, 41), medium_wr, \"s-\", color=\"#FF9800\", linewidth=2, label=\"Medium (Climate Policy)\")\n",
|
| 583 |
+
"ax.plot(range(41, 61), hard_wr, \"^-\", color=\"#E91E63\", linewidth=2, label=\"Hard (Bioethics)\")\n",
|
| 584 |
+
"\n",
|
| 585 |
+
"ax.axhline(y=0.70, color=\"green\", linestyle=\"--\", linewidth=1.5, label=\"Escalation threshold (70%)\")\n",
|
| 586 |
+
"ax.axvline(x=20, color=\"#2196F3\", linestyle=\":\", linewidth=1.2, alpha=0.6)\n",
|
| 587 |
+
"ax.axvline(x=40, color=\"#FF9800\", linestyle=\":\", linewidth=1.2, alpha=0.6)\n",
|
| 588 |
+
"\n",
|
| 589 |
+
"ax.annotate(\"→ Escalate to Medium\", xy=(20, 0.72), fontsize=9, color=\"#2196F3\")\n",
|
| 590 |
+
"ax.annotate(\"→ Escalate to Hard\", xy=(40, 0.72), fontsize=9, color=\"#FF9800\")\n",
|
| 591 |
+
"\n",
|
| 592 |
+
"ax.set_title(\"Adaptive Curriculum: Win Rate Across Training Episodes\", fontsize=14)\n",
|
| 593 |
+
"ax.set_xlabel(\"Training Episode\")\n",
|
| 594 |
+
"ax.set_ylabel(\"Win Rate (rolling)\")\n",
|
| 595 |
+
"ax.set_ylim(0, 1.05)\n",
|
| 596 |
+
"ax.legend(loc=\"lower right\")\n",
|
| 597 |
+
"ax.grid(True, alpha=0.3)\n",
|
| 598 |
+
"\n",
|
| 599 |
+
"plt.tight_layout()\n",
|
| 600 |
+
"plt.savefig(\"outputs/curriculum_escalation.png\", dpi=150)\n",
|
| 601 |
+
"plt.show()\n",
|
| 602 |
+
"print(\"Saved: outputs/curriculum_escalation.png\")\n"
|
| 603 |
+
]
|
| 604 |
+
},
|
| 605 |
{
|
| 606 |
"cell_type": "code",
|
| 607 |
"execution_count": null,
|