Spaces:
Sleeping
Sleeping
| # ============================================================================= | |
| # π₯ CloudSRE v2 β ULTIMATE RELAY TRAINING NOTEBOOK | |
| # ============================================================================= | |
| # | |
| # WHO: For Hari's friends who are new to Colab + HF. | |
| # WHAT: Train a 1.5B model to fix cloud infrastructure incidents. | |
| # WHERE: Google Colab (free T4 GPU) OR HuggingFace Space (T4 GPU). | |
| # HOW: Copy-paste each cell. Don't change ANYTHING unless told to. | |
| # | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # β FRIEND ASSIGNMENT β READ THIS FIRST β | |
| # β β | |
| # β π¦ COLAB FRIEND (starts FIRST): β | |
| # β β Platform: Google Colab (free T4) β | |
| # β β Trains: warmup + single_fault (the easy tiers) β | |
| # β β Uses base model (no previous training needed) β | |
| # β β Pushes result as "leg1" when done β | |
| # β β In Cells 6, 7, 9: use the defaults (LEG 1) β | |
| # β β | |
| # β π§ HF FRIEND (starts AFTER Colab Friend says "pushed"): β | |
| # β β Platform: HuggingFace Space (T4 GPU β cheapest option) β | |
| # β β Trains: cascade + multi_cascade (the hard tiers) β | |
| # β β Downloads Colab Friend's model automatically β | |
| # β β Pushes result as "leg2" when done β | |
| # β β In Cells 6, 7, 9: UNCOMMENT the LEG 2 lines β | |
| # β β | |
| # β π© HARI (starts AFTER HF Friend says "pushed"): β | |
| # β β Trains: adversarial (the death spirals) β | |
| # β β In Cells 6, 7, 9: UNCOMMENT the LEG 3 lines β | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # | |
| # TIME ESTIMATE: ~45 min per leg on T4 | |
| # ============================================================================= | |
| # %% | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CELL 1: GPU CHECK | |
| # π₯ BOTH FRIENDS RUN THIS β Colab Friend AND HF Friend | |
| # If it says "No GPU", stop and fix before continuing. | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| import torch | |
| print("=" * 60) | |
| if torch.cuda.is_available(): | |
| gpu_name = torch.cuda.get_device_name(0) | |
| gpu_mem = torch.cuda.get_device_properties(0).total_memory / 1e9 | |
| print(f"β GPU FOUND: {gpu_name} ({gpu_mem:.1f} GB)") | |
| print(" You're good to go!") | |
| else: | |
| print("β NO GPU DETECTED!") | |
| print(" Colab: Runtime β Change runtime type β T4 GPU") | |
| print(" HF: Make sure you selected a T4 GPU Space") | |
| print(" Then re-run this cell.") | |
| print("=" * 60) | |
| # %% | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CELL 2: INSTALL EVERYTHING (takes ~3-4 minutes, be patient) | |
| # π₯ BOTH FRIENDS RUN THIS β Colab Friend AND HF Friend | |
| # DO NOT MODIFY THIS CELL. | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print("Installing dependencies... this takes 3-4 minutes...") | |
| # Install PyTorch first (Colab has it, HF Spaces may not) | |
| # Pin versions to avoid conflicts with unsloth (needs torch<2.11) | |
| !pip install "torch>=2.4.0,<2.11.0" "torchvision>=0.19.0,<0.26.0" 2>/dev/null | |
| # Install unsloth + all its dependencies | |
| !pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git" 2>/dev/null | |
| !pip install unsloth_zoo 2>/dev/null | |
| !pip install trl peft accelerate bitsandbytes 2>/dev/null | |
| !pip install xformers triton 2>/dev/null | |
| # Install training dependencies | |
| !pip install httpx wandb matplotlib 2>/dev/null | |
| print("\nβ All dependencies installed!") | |
| # %% | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CELL 3: LOGIN TO HUGGINGFACE + WANDB | |
| # π₯ BOTH FRIENDS RUN THIS β Colab Friend AND HF Friend | |
| # This will ask for your tokens. Paste them when prompted. | |
| # | |
| # HuggingFace token: https://huggingface.co/settings/tokens (create a WRITE token) | |
| # WandB token: https://wandb.ai/authorize | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| from huggingface_hub import login as hf_login | |
| import wandb | |
| print("=" * 60) | |
| print("STEP 1: HuggingFace Login") | |
| print(" Go to: https://huggingface.co/settings/tokens") | |
| print(" Create a token with WRITE permission") | |
| print(" Paste it below:") | |
| print("=" * 60) | |
| hf_login() | |
| print("\n" + "=" * 60) | |
| print("STEP 2: Weights & Biases Login") | |
| print(" Go to: https://wandb.ai/authorize") | |
| print(" Copy the API key and paste it below:") | |
| print("=" * 60) | |
| wandb.login() | |
| print("\nβ Both logins successful!") | |
| # %% | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CELL 4: CLONE THE REPO | |
| # π₯ BOTH FRIENDS RUN THIS β Colab Friend AND HF Friend | |
| # Auto-detects platform: works on Colab, HF Space, or local machine. | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| import os | |
| # Auto-detect platform | |
| if os.path.exists("/content"): # Google Colab | |
| BASE_DIR = "/content" | |
| PLATFORM = "Colab" | |
| elif os.path.exists("/home/user"): # HuggingFace Space | |
| BASE_DIR = "/home/user" | |
| PLATFORM = "HF Space" | |
| else: # Local / other | |
| BASE_DIR = os.path.expanduser("~") | |
| PLATFORM = "Local" | |
| REPO_DIR = os.path.join(BASE_DIR, "CloudSRE") | |
| print(f"Platform detected: {PLATFORM}") | |
| print(f"Working in: {BASE_DIR}") | |
| os.chdir(BASE_DIR) | |
| # Remove old copy if it exists | |
| !rm -rf CloudSRE | |
| # Clone fresh | |
| !git clone https://github.com/Harikishanth/CloudSRE.git | |
| os.chdir(REPO_DIR) | |
| print(f"\nβ Repo cloned. Working directory: {os.getcwd()}") | |
| !ls -la train_grpo.py # Verify the training script exists | |
| # %% | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CELL 5: VERIFY ENVIRONMENT IS ALIVE | |
| # π₯ BOTH FRIENDS RUN THIS β Colab Friend AND HF Friend | |
| # If this fails, the Space might be sleeping β go to the URL and wake it up. | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| import httpx | |
| ENV_URL = "https://dardrax-cloudsre-environment.hf.space" | |
| print(f"Checking environment at: {ENV_URL}") | |
| try: | |
| r = httpx.get(f"{ENV_URL}/health", timeout=30) | |
| print(f" Status: {r.status_code}") | |
| print(f" Response: {r.text[:200]}") | |
| print(f"\nβ Environment is ALIVE and responding!") | |
| except Exception as e: | |
| print(f"\nβ Environment is DOWN: {e}") | |
| print(f" Go to {ENV_URL} in your browser and wait for it to start") | |
| print(f" Then re-run this cell") | |
| # Quick smoke test β reset an episode | |
| try: | |
| r = httpx.post(f"{ENV_URL}/reset", json={"task_id": "warmup"}, timeout=60) | |
| data = r.json() | |
| obs = data.get("observation", data) | |
| n_services = len(obs.get("service_health", {})) | |
| print(f" Services running: {n_services}") | |
| print(f" Alert: {obs.get('alert', 'none')[:100]}") | |
| print(f"\nβ Smoke test passed β {n_services} services online!") | |
| except Exception as e: | |
| print(f"\nβ Smoke test FAILED: {e}") | |
| # %% | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CELL 6: LOAD THE MODEL | |
| # β οΈ READ CAREFULLY β different for each friend! | |
| # | |
| # π¦ COLAB FRIEND: Use the default (LEG 1 β base model). Don't change anything. | |
| # π§ HF FRIEND: COMMENT OUT the LEG 1 line, UNCOMMENT the LEG 2 line. | |
| # π© HARI: COMMENT OUT the LEG 1 line, UNCOMMENT the LEG 3 line. | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| MODEL_ID = "unsloth/Qwen2.5-1.5B-Instruct-bnb-4bit" # β π¦ COLAB FRIEND uses this (LEG 1) | |
| # MODEL_ID = "DarDrax/cloudsre-1.5B-leg1" # β π§ HF FRIEND uses this (LEG 2) | |
| # MODEL_ID = "DarDrax/cloudsre-1.5B-leg2" # β π© HARI uses this (LEG 3) | |
| print(f"Loading model: {MODEL_ID}") | |
| print("This takes 2-3 minutes on a T4...") | |
| from unsloth import FastLanguageModel | |
| model, tokenizer = FastLanguageModel.from_pretrained( | |
| model_name=MODEL_ID, | |
| max_seq_length=2048, | |
| load_in_4bit=True, | |
| ) | |
| # Add LoRA adapters for training | |
| model = FastLanguageModel.get_peft_model( | |
| model, | |
| r=16, | |
| lora_alpha=32, | |
| lora_dropout=0, | |
| target_modules=["q_proj", "k_proj", "v_proj", "o_proj", | |
| "gate_proj", "up_proj", "down_proj"], | |
| use_gradient_checkpointing="unsloth", | |
| ) | |
| trainable = sum(p.numel() for p in model.parameters() if p.requires_grad) | |
| total = sum(p.numel() for p in model.parameters()) | |
| print(f"\nβ Model loaded!") | |
| print(f" Total parameters: {total:,}") | |
| print(f" Trainable (LoRA): {trainable:,}") | |
| print(f" Memory used: {torch.cuda.memory_allocated()/1e9:.1f} GB") | |
| # %% | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CELL 7: π START TRAINING π | |
| # β οΈ READ CAREFULLY β different for each friend! | |
| # | |
| # π¦ COLAB FRIEND: Use the default (warmup,single_fault). Don't change anything. | |
| # π§ HF FRIEND: COMMENT OUT LEG 1 line, UNCOMMENT LEG 2 line. | |
| # π© HARI: COMMENT OUT LEG 1 line, UNCOMMENT LEG 3 line. | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| CURRICULUM = "warmup,single_fault" # β π¦ COLAB FRIEND uses this (LEG 1) | |
| # CURRICULUM = "cascade,multi_cascade" # β π§ HF FRIEND uses this (LEG 2) | |
| # CURRICULUM = "adversarial" # β π© HARI uses this (LEG 3) | |
| # ββββ DO NOT CHANGE ANYTHING BELOW THIS LINE ββββ | |
| ENV_URL = "https://dardrax-cloudsre-environment.hf.space" | |
| WANDB_PROJECT = "CloudSRE-Hackathon-Run" | |
| EPISODES = 25 # per tier | |
| GROUP_SIZE = 4 # parallel rollouts | |
| print("=" * 70) | |
| print(f" π₯ GRPO TRAINING β CloudSRE v2") | |
| print(f" Curriculum: {CURRICULUM}") | |
| print(f" Episodes/tier: {EPISODES}") | |
| print(f" Group size: {GROUP_SIZE} rollouts") | |
| print(f" Environment: {ENV_URL}") | |
| print(f" WandB project: {WANDB_PROJECT}") | |
| print("=" * 70) | |
| !cd {REPO_DIR} && python train_grpo.py \ | |
| --env-url "{ENV_URL}" \ | |
| --model-id "{MODEL_ID}" \ | |
| --curriculum "{CURRICULUM}" \ | |
| --episodes-per-tier {EPISODES} \ | |
| --group-size {GROUP_SIZE} \ | |
| --max-turns 10 \ | |
| --lr 5e-6 \ | |
| --save-every 10 \ | |
| --wandb-project "{WANDB_PROJECT}" \ | |
| --output-dir "./cloudsre-grpo" | |
| # %% | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CELL 8: π PLOT TRAINING RESULTS (run after training finishes) | |
| # π₯ BOTH FRIENDS RUN THIS β Colab Friend AND HF Friend | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| import json | |
| import matplotlib.pyplot as plt | |
| log_path = os.path.join(REPO_DIR, "grpo_training_log.json") | |
| graph_path = os.path.join(REPO_DIR, "grpo_reward_curve.png") | |
| try: | |
| with open(log_path) as f: | |
| log = json.load(f) | |
| rewards = [ep["reward"] for ep in log["per_episode"]] | |
| episodes = list(range(1, len(rewards) + 1)) | |
| # Rolling average | |
| window = min(5, len(rewards)) | |
| rolling = [] | |
| for i in range(len(rewards)): | |
| start = max(0, i - window + 1) | |
| rolling.append(sum(rewards[start:i+1]) / (i - start + 1)) | |
| fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5)) | |
| # Reward curve | |
| ax1.plot(episodes, rewards, alpha=0.4, color='#3498db', linewidth=1, label='Per-episode') | |
| ax1.plot(episodes, rolling, color='#e74c3c', linewidth=2.5, label=f'{window}-ep avg') | |
| ax1.set_xlabel('Episode', fontsize=12) | |
| ax1.set_ylabel('Reward', fontsize=12) | |
| ax1.set_title('CloudSRE v2 β GRPO Training Reward', fontsize=14, fontweight='bold') | |
| ax1.legend(fontsize=10) | |
| ax1.grid(True, alpha=0.3) | |
| # Resolution rate per tier | |
| tiers = log.get("tier_results", {}) | |
| if tiers: | |
| names = list(tiers.keys()) | |
| rates = [tiers[t]["resolution_rate"] for t in names] | |
| colors = ['#2ecc71', '#3498db', '#e74c3c', '#9b59b6', '#f39c12'] | |
| bars = ax2.bar(names, rates, color=colors[:len(names)], alpha=0.85, edgecolor='white') | |
| ax2.set_ylabel('Resolution Rate (%)', fontsize=12) | |
| ax2.set_title('Resolution Rate by Tier', fontsize=14, fontweight='bold') | |
| ax2.set_ylim(0, 100) | |
| for bar, rate in zip(bars, rates): | |
| ax2.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 2, | |
| f'{rate:.0f}%', ha='center', va='bottom', fontweight='bold') | |
| ax2.grid(True, alpha=0.3, axis='y') | |
| plt.tight_layout() | |
| plt.savefig(graph_path, dpi=150, bbox_inches='tight') | |
| plt.show() | |
| print(f"β Graph saved to {graph_path}") | |
| except FileNotFoundError: | |
| print("β Training log not found β did training complete?") | |
| # %% | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CELL 9: π PUSH MODEL TO HUGGINGFACE | |
| # β οΈ READ CAREFULLY β different for each friend! | |
| # | |
| # π¦ COLAB FRIEND: Use the default (leg1). Don't change anything. | |
| # After this finishes, TEXT THE GROUP: "Pushed! π§ HF Friend go!" | |
| # | |
| # π§ HF FRIEND: COMMENT OUT LEG 1 line, UNCOMMENT LEG 2 line. | |
| # After this finishes, TEXT THE GROUP: "Pushed! π© Hari go!" | |
| # | |
| # π© HARI: COMMENT OUT LEG 1 line, UNCOMMENT LEG 3 line. | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| PUSH_REPO = "DarDrax/cloudsre-1.5B-leg1" # β π¦ COLAB FRIEND pushes this | |
| # PUSH_REPO = "DarDrax/cloudsre-1.5B-leg2" # β π§ HF FRIEND pushes this | |
| # PUSH_REPO = "DarDrax/cloudsre-1.5B-FINAL" # β π© HARI pushes this | |
| from unsloth import FastLanguageModel | |
| model_path = os.path.join(REPO_DIR, "cloudsre-grpo") | |
| print(f"Loading trained model from {model_path} ...") | |
| model, tokenizer = FastLanguageModel.from_pretrained( | |
| model_name=model_path, | |
| max_seq_length=2048, | |
| load_in_4bit=True, | |
| ) | |
| print(f"Pushing to HuggingFace: {PUSH_REPO} ...") | |
| model.push_to_hub(PUSH_REPO) | |
| tokenizer.push_to_hub(PUSH_REPO) | |
| print(f"\nβ MODEL PUSHED TO: https://huggingface.co/{PUSH_REPO}") | |
| print(f"\nπ£ Tell your friend: 'Pushed! Start your leg!'") | |
| # %% | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CELL 10: πΈ SAVE WANDB SCREENSHOT (for README) | |
| # π₯ BOTH FRIENDS RUN THIS β Colab Friend AND HF Friend | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print("=" * 60) | |
| print("π Your WandB graphs are at:") | |
| print(f" https://wandb.ai/YOUR_USERNAME/{WANDB_PROJECT}") | |
| print() | |
| print("TO PUT THE GRAPH IN README:") | |
| print(" 1. Go to your WandB run page") | |
| print(" 2. Screenshot the reward curve") | |
| print(" 3. Save it as 'grpo_reward_curve.png'") | |
| print(" 4. Or use the local one we just saved!") | |
| print("=" * 60) | |
| # Download the graph (Colab only β on HF Space, just find it in the file browser) | |
| try: | |
| from google.colab import files | |
| files.download(os.path.join(REPO_DIR, 'grpo_reward_curve.png')) | |
| print("β Downloaded graph to your computer!") | |
| except ImportError: | |
| print(f"Not on Colab β find the graph at: {os.path.join(REPO_DIR, 'grpo_reward_curve.png')}") | |
| except: | |
| print("Graph file not found β run Cell 8 first") | |