{ "cells": [ { "cell_type": "markdown", "id": "0eb387df", "metadata": {}, "source": [ "# ๐Ÿง  UMBRA โ€” Google Colab Training Notebook\n", "\n", "**Model:** `HuggingFaceTB/SmolLM-135M` (4-bit QLoRA) \n", "**Trainer:** GRPO via TRL \n", "**Datasets:** hh-rlhf ยท pii-masking-300k ยท truthful_qa ยท toxic-chat ยท daily_dialog \n", "\n", "**Runtime:** T4 GPU (16 GB) โ€” set via *Runtime โ†’ Change runtime type โ†’ T4*\n", "\n", "---\n", "### Steps\n", "1. Run **Cell 1** to install dependencies \n", "2. Run **Cell 2** to mount Google Drive and upload your project \n", "3. Run **Cell 3** to verify the GPU \n", "4. Run **Cell 4** to start training \n", "5. Run **Cell 5** to evaluate after training " ] }, { "cell_type": "code", "execution_count": null, "id": "c4e4290f", "metadata": {}, "outputs": [], "source": [ "# โ”€โ”€ Cell 1: Install all dependencies โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "!pip install -q \\\n", " \"trl>=0.9.0\" \\\n", " \"datasets>=2.18.0\" \\\n", " \"transformers>=4.40.0\" \\\n", " \"bitsandbytes>=0.43.0\" \\\n", " \"peft>=0.10.0\" \\\n", " \"accelerate>=0.29.0\" \\\n", " \"gymnasium>=0.29.0\" \\\n", " \"matplotlib>=3.8\" \\\n", " \"numpy>=1.26\" \\\n", " \"fastapi\" \\\n", " \"uvicorn\"\n", "\n", "print('โœ… All dependencies installed.')" ] }, { "cell_type": "code", "execution_count": null, "id": "63e49dee", "metadata": {}, "outputs": [], "source": [ "# โ”€โ”€ Cell 2: Mount Google Drive and set project path โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "from google.colab import drive\n", "drive.mount('/content/drive')\n", "\n", "import os\n", "\n", "# โš ๏ธ Change this path to wherever you uploaded the Umbra folder in your Drive\n", "PROJECT_PATH = '/content/drive/MyDrive/Umbra'\n", "\n", "assert os.path.isdir(PROJECT_PATH), (\n", " f'โŒ Project folder not found at {PROJECT_PATH}. '\n", " 'Upload your Umbra folder to Google Drive and update PROJECT_PATH above.'\n", ")\n", "\n", "os.chdir(PROJECT_PATH)\n", "print(f'โœ… Working directory: {os.getcwd()}')\n", "print('Files:', os.listdir('.'))" ] }, { "cell_type": "code", "execution_count": null, "id": "0478e990", "metadata": {}, "outputs": [], "source": [ "# โ”€โ”€ Cell 3: Verify GPU + fix Python path + smoke test โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "import sys, os, torch\n", "\n", "# โ”€โ”€ CRITICAL: add project root to sys.path so all UMBRA modules resolve โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "# This is the fix for: ModuleNotFoundError: No module named 'reward'\n", "PROJECT_PATH = os.getcwd() # already set to /content/drive/MyDrive/Umbra by Cell 2\n", "if PROJECT_PATH not in sys.path:\n", " sys.path.insert(0, PROJECT_PATH)\n", "print(f'โœ… sys.path[0] = {sys.path[0]}')\n", "\n", "# โ”€โ”€ GPU check โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "if not torch.cuda.is_available():\n", " raise RuntimeError(\n", " 'โŒ No GPU detected! Go to Runtime โ†’ Change runtime type โ†’ T4 GPU and restart.'\n", " )\n", "gpu_name = torch.cuda.get_device_name(0)\n", "vram_gb = torch.cuda.get_device_properties(0).total_memory / 1e9\n", "print(f'โœ… GPU: {gpu_name} | VRAM: {vram_gb:.1f} GB')\n", "\n", "# โ”€โ”€ Full import sanity check โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "from reward.reward_model import ShapedRewardModel\n", "from sentrix.cialdini_stress import run_cialdini_stress\n", "from shadow.shadow_agent import ShadowAgent\n", "from shadow.arms_race_trainer import ArmsRaceTrainer\n", "from demo.graph_generator import generate_all_graphs\n", "from data.dataset_loader import load_hh_rlhf, build_grpo_prompts\n", "print('โœ… All UMBRA modules imported successfully.')\n", "\n", "# โ”€โ”€ Dataset loader quick smoke test โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "sample_ds = load_hh_rlhf(split='train', max_samples=5)\n", "sample_prompts = build_grpo_prompts(sample_ds, max_prompts=3)\n", "print(f'โœ… Dataset loader OK โ€” sample prompt: {sample_prompts[0][:80]}โ€ฆ')\n", "print('\\n๐Ÿš€ Ready to train! Run Cell 4.')" ] }, { "cell_type": "code", "execution_count": null, "id": "e9ec67e3", "metadata": {}, "outputs": [], "source": [ "# โ”€โ”€ Cell 4: Run full UMBRA training โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "# Full pipeline (~2h 30min on T4 GPU):\n", "# 1. Load 5 HuggingFace datasets (cached after first run)\n", "# 2. Benchmark Sentrix PII guard โ†’ logs/sentrix_benchmark.json\n", "# 3. Capture BEFORE metrics (baseline) โ†’ logs/before_metrics.json\n", "# 4. GRPO fine-tune SmolLM-135M (~45 min) โ†’ umbra_grpo_ckpt/\n", "# 5. Shadow Arms Race (2 rounds ร— 50 eps) (~15 min) โ†’ logs/arms_race_log.jsonl\n", "# 6. RL Loop 500 eps ShapedRewardModel (~30 min) โ†’ logs/rollout_samples.jsonl\n", "# 7. Cialdini Stress Test (6 ร— 10 eps) (~10 min) โ†’ logs/cialdini_results.json\n", "# 8. AFTER metrics + 4 graphs generated โ†’ logs/reward_graphs/\n", "# 9. Save final model โ†’ umbra_final/\n", "#\n", "# โ”€โ”€ To run in FAST MODE (~5 min), uncomment these lines BEFORE running: โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "# import re, pathlib\n", "# src = pathlib.Path('train.py').read_text()\n", "# src = re.sub(r'USE_GRPO\\s*=\\s*True', 'USE_GRPO = False', src)\n", "# src = re.sub(r'USE_SHADOW\\s*=\\s*True','USE_SHADOW = False', src)\n", "# src = re.sub(r'EPISODES\\s*=\\s*500', 'EPISODES = 50', src)\n", "# src = re.sub(r'CIALDINI_EPS\\s*=\\s*10','CIALDINI_EPS = 3', src)\n", "# pathlib.Path('train_fast.py').write_text(src)\n", "# %run train_fast.py\n", "# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "\n", "%run train.py" ] }, { "cell_type": "code", "execution_count": null, "id": "c2d0148a", "metadata": {}, "outputs": [], "source": [ "# โ”€โ”€ Cell 5: Evaluate trained model โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "%run evaluate.py" ] }, { "cell_type": "code", "execution_count": null, "id": "bf4ab64f", "metadata": {}, "outputs": [], "source": [ "# โ”€โ”€ Cell 6: View generated training graphs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "import matplotlib.pyplot as plt\n", "import matplotlib.image as mpimg\n", "from pathlib import Path\n", "\n", "graph_dir = Path('logs/reward_graphs')\n", "graphs = sorted(graph_dir.glob('*.png'))\n", "\n", "if not graphs:\n", " print('No graphs found yet โ€” run Cell 4 (train.py) first.')\n", "else:\n", " fig, axes = plt.subplots(2, 2, figsize=(18, 12))\n", " fig.patch.set_facecolor('#0d1117')\n", " for ax, path in zip(axes.flat, graphs):\n", " img = mpimg.imread(str(path))\n", " ax.imshow(img)\n", " ax.set_title(path.stem.replace('_', ' ').title(),\n", " color='white', fontsize=13, pad=8)\n", " ax.axis('off')\n", " # Hide unused subplot if fewer than 4 graphs\n", " for ax in axes.flat[len(graphs):]:\n", " ax.set_visible(False)\n", " plt.tight_layout()\n", " plt.show()\n", " print(f'โœ… Displayed {len(graphs)} graphs from {graph_dir}/')" ] }, { "cell_type": "code", "execution_count": null, "id": "f08ee1f5", "metadata": {}, "outputs": [], "source": [ "# โ”€โ”€ Cell 7 (optional): Download model + logs to local machine โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "import shutil, os\n", "from google.colab import files\n", "\n", "# Bundle the trained model\n", "if os.path.isdir('umbra_final'):\n", " shutil.make_archive('umbra_final', 'zip', 'umbra_final')\n", " files.download('umbra_final.zip')\n", " print('โœ… Model download started.')\n", "else:\n", " print('โš  umbra_final/ not found โ€” run Cell 4 first.')\n", "\n", "# Bundle logs (graphs + metrics + Cialdini results)\n", "if os.path.isdir('logs'):\n", " shutil.make_archive('umbra_logs', 'zip', 'logs')\n", " files.download('umbra_logs.zip')\n", " print('โœ… Logs download started.')\n", "else:\n", " print('โš  logs/ not found.')" ] }, { "cell_type": "code", "execution_count": null, "id": "9b6d67f0", "metadata": {}, "outputs": [], "source": [ "# โ”€โ”€ Cell 7 (optional): View Sentrix benchmark report โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n", "import json\n", "\n", "with open('logs/sentrix_benchmark.json') as f:\n", " report = json.load(f)\n", "\n", "print('=== Sentrix PII Guard Benchmark (vs ai4privacy/pii-masking-300k) ===')\n", "print(f\" True Positives : {report['true_positives']}\")\n", "print(f\" False Positives : {report['false_positives']}\")\n", "print(f\" False Negatives : {report['false_negatives']}\")\n", "print(f\" Precision : {report['precision']}\")\n", "print(f\" Recall : {report['recall']}\")\n", "print(f\" F1 Score : {report['f1']}\")" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }