{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "9you219PQC5E" }, "source": [ "# FairRecovery++: Fair-GRPO-RLVR Training Notebook\n", "\n", "Research-level training pipeline implementing multi-objective optimization for equitable disaster recovery." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "id": "-gx3UakxQC5G" }, "outputs": [], "source": [ "# =========================================\n", "# 1. INSTALL\n", "# =========================================\n", "!pip install -q unsloth trl transformers accelerate requests matplotlib pandas pydantic structlog\n", "\n" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "id": "99e5mIVaQC5H" }, "outputs": [], "source": [ "# =========================================\n", "# 2. CONFIG\n", "# =========================================\n", "import os\n", "import sys\n", "import random\n", "import matplotlib.pyplot as plt\n", "import pandas as pd\n", "import json, re\n", "\n", "# Clone repo to get local environment\n", "REPO_URL = 'https://github.com/joshua400/FairRecovery-PlusPlus.git'\n", "REPO_DIR = '/content/FairRecovery-PlusPlus'\n", "if not os.path.exists(REPO_DIR):\n", " !git clone {REPO_URL} {REPO_DIR}\n", "sys.path.insert(0, REPO_DIR)\n", "os.chdir(REPO_DIR)\n", "\n", "MODEL_NAME = \"unsloth/Llama-3.2-1B-Instruct-bnb-4bit\"\n", "MAX_STEPS = 20\n", "\n" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "id": "kvtAdWKlQC5I" }, "outputs": [], "source": [ "# =========================================\n", "# 3. ENV HELPERS (LOCAL FOR SPEED & RELIABILITY)\n", "# =========================================\n", "from server.fairrecovery_environment import FairRecoveryEnvironment\n", "from fairrecovery_env.models import FairRecoveryAction\n", "\n", "def reset_env(seed=None, difficulty=None):\n", " if difficulty is None:\n", " difficulty = random.choice([\"easy\", \"medium\", \"hard\"])\n", " env = FairRecoveryEnvironment()\n", " obs = env.reset(difficulty=difficulty, seed=seed)\n", " return env, obs\n", "\n", "def step_env(env, action_dict):\n", " try:\n", " if \"action_type\" not in action_dict:\n", " action_dict[\"action_type\"] = \"submit\"\n", " if action_dict[\"action_type\"] == \"analyze\" and \"critical_zones\" not in action_dict:\n", " action_dict[\"critical_zones\"] = [4, 3]\n", " if action_dict[\"action_type\"] == \"allocate\" and \"allocations\" not in action_dict:\n", " action_dict[\"allocations\"] = [{\"zone\": 4, \"resource\": \"power\"}]\n", "\n", " action = FairRecoveryAction(**action_dict)\n", " obs = env.step(action)\n", " return obs\n", " except Exception as e:\n", " return env.step(FairRecoveryAction(action_type=\"submit\"))\n", "\n" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "id": "GcyKmIsDQC5I" }, "outputs": [], "source": [ "# =========================================\n", "# 4. BASELINE (GREEDY POLICY)\n", "# =========================================\n", "from inference import greedy_policy\n", "\n", "def run_baseline(seed=None):\n", " # Ensure baseline is evaluated on 'hard' to show the 'Fairness Trap'\n", " env, obs = reset_env(seed=seed, difficulty=\"hard\")\n", " total = 0\n", "\n", " for _ in range(MAX_STEPS):\n", " action = greedy_policy(obs)\n", " obs = env.step(action)\n", " total += obs.reward\n", "\n", " if obs.done:\n", " break\n", "\n", " # Honest comparison: return raw total\n", " return total, obs.fairness_score\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 170, "referenced_widgets": [ "158e355936fb48c19b10a82098c3d0b8", "a93fc625933a40798df735a3ff438438", "05869d84913a49bdabdc546a7f8e1084", "d783fe3762e14974932b54ded02c4c01", "4a41b45f79314ab5945af366082c1811", "f39122df14a041d5a0adc3d335d05e07", "56135965433b472db8ef44457a8b56ac", "15a9443782b14c0a8abe9ed11fb06786", "d087fc944aaf488480988a7d276a811d", "8e86cfcf3bb94d01a485f187c813b01d", "060c89bb8a2844d091077e9688cd2ab2" ] }, "id": "MJ5gR4KmQC5J", "outputId": "e19c7ea5-60b4-4bff-f4f4-3cc2704b9508" }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "==((====))== Unsloth 2026.4.8: Fast Llama patching. Transformers: 5.5.0.\n", " \\\\ /| Tesla T4. Num GPUs = 1. Max memory: 14.563 GB. Platform: Linux.\n", "O^O/ \\_/ \\ Torch: 2.10.0+cu128. CUDA: 7.5. CUDA Toolkit: 12.8. Triton: 3.6.0\n", "\\ / Bfloat16 = FALSE. FA [Xformers = 0.0.35. FA2 = False]\n", " \"-____-\" Free license: http://github.com/unslothai/unsloth\n", "Unsloth: Fast downloading is enabled - ignore downloading bars which are red colored!\n" ] }, { "output_type": "display_data", "data": { "text/plain": [ "Loading weights: 0%| | 0/146 [00:00 0 and improvement_f > 0:\n", " print(\"\\n✅ Model improved on BOTH reward and fairness.\")\n", "elif improvement_r > 0:\n", " print(f\"\\n⚠️ Reward improved but fairness REGRESSED by {abs(improvement_f):.3f}. Check reward weights.\")\n", "elif improvement_f > 0:\n", " print(f\"\\n⚠️ Fairness improved but reward REGRESSED by {abs(improvement_r):.3f}.\")\n", "else:\n", " print(\"\\n❌ Model did not outperform baseline. Consider more training steps or larger dataset.\")\n", "\n", "print(\"\\n🏆 Key Insight:\")\n", "print(\"Optimizing for fairness improves long-term recovery efficiency.\")\n", "\n", "print(\"\\n🚀 FINAL TAKEAWAY:\")\n", "print(\"Fair-GRPO-RLVR learns policies that outperform greedy baselines by optimizing both efficiency and fairness simultaneously.\")\n", "\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "name": "python3" }, "language_info": { "name": "python", "version": "3.11.0" }, "accelerator": "GPU", "colab": { "provenance": [], "gpuType": "T4" }, "widgets": { "application/vnd.jupyter.widget-state+json": { "158e355936fb48c19b10a82098c3d0b8": { "model_module": "@jupyter-widgets/controls", "model_name": "HBoxModel", "model_module_version": "1.5.0", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "HBoxModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "HBoxView", "box_style": "", "children": [ "IPY_MODEL_a93fc625933a40798df735a3ff438438", "IPY_MODEL_05869d84913a49bdabdc546a7f8e1084", "IPY_MODEL_d783fe3762e14974932b54ded02c4c01" ], "layout": "IPY_MODEL_4a41b45f79314ab5945af366082c1811" } }, "a93fc625933a40798df735a3ff438438": { "model_module": "@jupyter-widgets/controls", "model_name": "HTMLModel", "model_module_version": "1.5.0", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "HTMLModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "HTMLView", "description": "", "description_tooltip": null, "layout": "IPY_MODEL_f39122df14a041d5a0adc3d335d05e07", "placeholder": "​", "style": "IPY_MODEL_56135965433b472db8ef44457a8b56ac", "value": "Loading weights: 100%" } }, "05869d84913a49bdabdc546a7f8e1084": { "model_module": "@jupyter-widgets/controls", "model_name": "FloatProgressModel", "model_module_version": "1.5.0", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "FloatProgressModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "ProgressView", "bar_style": "success", "description": "", "description_tooltip": null, "layout": "IPY_MODEL_15a9443782b14c0a8abe9ed11fb06786", "max": 146, "min": 0, "orientation": "horizontal", "style": "IPY_MODEL_d087fc944aaf488480988a7d276a811d", "value": 146 } }, "d783fe3762e14974932b54ded02c4c01": { "model_module": "@jupyter-widgets/controls", "model_name": "HTMLModel", "model_module_version": "1.5.0", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "HTMLModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "HTMLView", "description": "", "description_tooltip": null, "layout": "IPY_MODEL_8e86cfcf3bb94d01a485f187c813b01d", "placeholder": "​", "style": "IPY_MODEL_060c89bb8a2844d091077e9688cd2ab2", "value": " 146/146 [00:01<00:00, 54.04it/s]" } }, "4a41b45f79314ab5945af366082c1811": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "model_module_version": "1.2.0", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } }, "f39122df14a041d5a0adc3d335d05e07": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "model_module_version": "1.2.0", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } }, "56135965433b472db8ef44457a8b56ac": { "model_module": "@jupyter-widgets/controls", "model_name": "DescriptionStyleModel", "model_module_version": "1.5.0", "state": { "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "DescriptionStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "description_width": "" } }, "15a9443782b14c0a8abe9ed11fb06786": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "model_module_version": "1.2.0", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } }, "d087fc944aaf488480988a7d276a811d": { "model_module": "@jupyter-widgets/controls", "model_name": "ProgressStyleModel", "model_module_version": "1.5.0", "state": { "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "ProgressStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "bar_color": null, "description_width": "" } }, "8e86cfcf3bb94d01a485f187c813b01d": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "model_module_version": "1.2.0", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } }, "060c89bb8a2844d091077e9688cd2ab2": { "model_module": "@jupyter-widgets/controls", "model_name": "DescriptionStyleModel", "model_module_version": "1.5.0", "state": { "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "DescriptionStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "description_width": "" } } } } }, "nbformat": 4, "nbformat_minor": 0 }