Spaces:
Running
Running
r1cksync commited on
Commit ·
0fa8055
1
Parent(s): 423678c
feat: hand-written 3 Kaggle ipynbs with unsloth install attempt; train_lib disables actor grad-checkpoint + filters Phi3 warning spam (2x faster + clean logs)
Browse files- colab/train_lib.py +38 -1
- kaggle/generate_notebooks.py +0 -272
- kaggle/kaggle_train_shard1.ipynb +88 -141
- kaggle/kaggle_train_shard2.ipynb +86 -146
- kaggle/kaggle_train_shard3.ipynb +86 -146
colab/train_lib.py
CHANGED
|
@@ -22,16 +22,47 @@ T4. If a non-T4 GPU is available it will be used automatically.
|
|
| 22 |
from __future__ import annotations
|
| 23 |
|
| 24 |
import json
|
|
|
|
| 25 |
import os
|
| 26 |
import re
|
| 27 |
import sys
|
| 28 |
import time
|
|
|
|
| 29 |
from dataclasses import asdict, dataclass, field
|
| 30 |
from pathlib import Path
|
| 31 |
from typing import Any, Iterable
|
| 32 |
|
| 33 |
import torch
|
| 34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
# ---------------------------------------------------------------------------
|
| 36 |
# Repository wiring — assumes you cloned the repo and the notebook lives in
|
| 37 |
# /content/incident-commander/ on Colab.
|
|
@@ -314,7 +345,13 @@ class QwenActor:
|
|
| 314 |
base = AutoModelForCausalLM.from_pretrained(
|
| 315 |
hf_name, quantization_config=bnb, device_map="auto",
|
| 316 |
trust_remote_code=False)
|
| 317 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 318 |
# Pick LoRA target modules that actually exist in this arch.
|
| 319 |
# Qwen / Llama use split q/k/v/gate/up. Phi-3 uses fused
|
| 320 |
# qkv_proj + gate_up_proj. Detect by introspecting param names.
|
|
|
|
| 22 |
from __future__ import annotations
|
| 23 |
|
| 24 |
import json
|
| 25 |
+
import logging
|
| 26 |
import os
|
| 27 |
import re
|
| 28 |
import sys
|
| 29 |
import time
|
| 30 |
+
import warnings
|
| 31 |
from dataclasses import asdict, dataclass, field
|
| 32 |
from pathlib import Path
|
| 33 |
from typing import Any, Iterable
|
| 34 |
|
| 35 |
import torch
|
| 36 |
|
| 37 |
+
# ---------------------------------------------------------------------------
|
| 38 |
+
# Silence the noisy per-token warnings emitted by Phi-3 and friends during
|
| 39 |
+
# PPO updates (gradient checkpointing × cache interaction). They are harmless
|
| 40 |
+
# but produce thousands of identical lines that hide actual progress.
|
| 41 |
+
# ---------------------------------------------------------------------------
|
| 42 |
+
warnings.filterwarnings(
|
| 43 |
+
"ignore", message=".*Caching is incompatible with gradient checkpointing.*")
|
| 44 |
+
warnings.filterwarnings(
|
| 45 |
+
"ignore", message=".*None of the inputs have requires_grad=True.*")
|
| 46 |
+
warnings.filterwarnings(
|
| 47 |
+
"ignore", message=".*use_reentrant parameter should be passed explicitly.*")
|
| 48 |
+
warnings.filterwarnings(
|
| 49 |
+
"ignore", message=".*AccumulateGrad node's stream does not match.*")
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
class _Phi3CacheFilter(logging.Filter):
|
| 53 |
+
def filter(self, record: logging.LogRecord) -> bool: # noqa: D401
|
| 54 |
+
msg = record.getMessage()
|
| 55 |
+
if "Caching is incompatible with gradient checkpointing" in msg:
|
| 56 |
+
return False
|
| 57 |
+
if "None of the inputs have requires_grad" in msg:
|
| 58 |
+
return False
|
| 59 |
+
return True
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
for _name in ("transformers", "transformers.models.phi3.modeling_phi3",
|
| 63 |
+
"torch.utils.checkpoint", "torch.autograd.graph"):
|
| 64 |
+
logging.getLogger(_name).addFilter(_Phi3CacheFilter())
|
| 65 |
+
|
| 66 |
# ---------------------------------------------------------------------------
|
| 67 |
# Repository wiring — assumes you cloned the repo and the notebook lives in
|
| 68 |
# /content/incident-commander/ on Colab.
|
|
|
|
| 345 |
base = AutoModelForCausalLM.from_pretrained(
|
| 346 |
hf_name, quantization_config=bnb, device_map="auto",
|
| 347 |
trust_remote_code=False)
|
| 348 |
+
# NOTE: gradient checkpointing is OFF for the 3.8B actor — it
|
| 349 |
+
# fits in T4 16 GB without it, and disabling it 1) eliminates
|
| 350 |
+
# the per-token "Caching is incompatible with gradient
|
| 351 |
+
# checkpointing in Phi3DecoderLayer" warning spam, and 2) speeds
|
| 352 |
+
# up the PPO backward pass roughly 2x by avoiding recompute.
|
| 353 |
+
base = prepare_model_for_kbit_training(
|
| 354 |
+
base, use_gradient_checkpointing=False)
|
| 355 |
# Pick LoRA target modules that actually exist in this arch.
|
| 356 |
# Qwen / Llama use split q/k/v/gate/up. Phi-3 uses fused
|
| 357 |
# qkv_proj + gate_up_proj. Detect by introspecting param names.
|
kaggle/generate_notebooks.py
DELETED
|
@@ -1,272 +0,0 @@
|
|
| 1 |
-
"""Generate the 3 Kaggle notebooks for sharded IncidentCommander training.
|
| 2 |
-
|
| 3 |
-
Each notebook is identical except for the IC_TASK_SHARD value (0/1/2) and
|
| 4 |
-
the run_name. Re-run this script if you want to tweak the template.
|
| 5 |
-
"""
|
| 6 |
-
from __future__ import annotations
|
| 7 |
-
|
| 8 |
-
import json
|
| 9 |
-
from pathlib import Path
|
| 10 |
-
|
| 11 |
-
NOTEBOOK_DIR = Path(__file__).resolve().parent
|
| 12 |
-
|
| 13 |
-
# Kaggle Models mount paths (read-only, mounted at /kaggle/input/, do NOT
|
| 14 |
-
# consume the 20 GB /kaggle/working/ quota). Exact paths the user pinned:
|
| 15 |
-
#
|
| 16 |
-
# Actor : /kaggle/input/models/Microsoft/phi-3/pytorch/phi-3.5-mini-instruct/2
|
| 17 |
-
# Critic: /kaggle/input/models/deepseek-ai/deepseek-r1-0528/transformers/deepseek-r1-0528-qwen3-8b/1
|
| 18 |
-
#
|
| 19 |
-
# In the Kaggle notebook sidebar ("+ Add Input" → Models):
|
| 20 |
-
# • search `phi-3` → publisher Microsoft → framework PyTorch → variation `phi-3.5-mini-instruct` → version 2 → Add
|
| 21 |
-
# • search `deepseek-r1` → publisher deepseek-ai → framework Transformers → variation `deepseek-r1-0528-qwen3-8b` → version 1 → Add
|
| 22 |
-
ACTOR_PATH_LITERAL = "/kaggle/input/models/Microsoft/phi-3/pytorch/phi-3.5-mini-instruct/2"
|
| 23 |
-
CRITIC_PATH_LITERAL = "/kaggle/input/models/deepseek-ai/deepseek-r1-0528/transformers/deepseek-r1-0528-qwen3-8b/1"
|
| 24 |
-
|
| 25 |
-
ACTOR_NAME = "microsoft/Phi-3.5-mini-instruct"
|
| 26 |
-
CRITIC_NAME = "deepseek-ai/DeepSeek-R1-0528-Qwen3-8B"
|
| 27 |
-
|
| 28 |
-
REPO_URL = "https://github.com/r1cksync/meta-rl-hack.git"
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
def cell_md(text: str) -> dict:
|
| 32 |
-
return {"cell_type": "markdown", "metadata": {},
|
| 33 |
-
"source": text.splitlines(keepends=True)}
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
def cell_code(text: str) -> dict:
|
| 37 |
-
return {"cell_type": "code", "metadata": {}, "execution_count": None,
|
| 38 |
-
"outputs": [], "source": text.splitlines(keepends=True)}
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
def build(shard: int, total_shards: int = 3) -> dict:
|
| 42 |
-
title = f"# IncidentCommander RL — Kaggle shard {shard + 1} / {total_shards}"
|
| 43 |
-
intro = f"""
|
| 44 |
-
**Workload:** every {total_shards}rd task starting at index {shard}
|
| 45 |
-
(~127 of 381 scenarios). Trains a LoRA on **{ACTOR_NAME}** using a local
|
| 46 |
-
**{CRITIC_NAME}** critic — both attached as Kaggle Models so they live in
|
| 47 |
-
the read-only `/kaggle/input/` mount and DO NOT eat the 20 GB working quota.
|
| 48 |
-
|
| 49 |
-
**REQUIRED — attach these 2 Kaggle Models before running** (right sidebar →
|
| 50 |
-
`+ Add Input` → `Models` tab). Both are open / no access request:
|
| 51 |
-
1. `Microsoft / phi-3` → framework `PyTorch` → variation `phi-3.5-mini-instruct` → version `2`
|
| 52 |
-
2. `deepseek-ai / deepseek-r1-0528` → framework `Transformers` → variation `deepseek-r1-0528-qwen3-8b` → version `1`
|
| 53 |
-
|
| 54 |
-
Expected mount paths after attach (cell 3 verifies):
|
| 55 |
-
- `{ACTOR_PATH_LITERAL}`
|
| 56 |
-
- `{CRITIC_PATH_LITERAL}`
|
| 57 |
-
|
| 58 |
-
**Required notebook settings** (right-hand sidebar):
|
| 59 |
-
- Accelerator: `GPU T4 x2` or `GPU P100`
|
| 60 |
-
- Persistence: `Files only`
|
| 61 |
-
- Internet: `On` (for `git clone` and optional HF Hub upload)
|
| 62 |
-
|
| 63 |
-
**Optional** (only if you want intermediate checkpoint upload to your HF
|
| 64 |
-
repo): Add-ons → Secrets → add `HF_TOKEN` and toggle it on.
|
| 65 |
-
|
| 66 |
-
**Output:** `/kaggle/working/adapter_kaggle{shard + 1}.zip` — download from
|
| 67 |
-
the sidebar after the run finishes. Combine all 3 with
|
| 68 |
-
`scripts/merge_lora_adapters.py` on your laptop.
|
| 69 |
-
"""
|
| 70 |
-
cells = [
|
| 71 |
-
cell_md(title + "\n" + intro),
|
| 72 |
-
|
| 73 |
-
cell_md("## 1. GPU + path sanity"),
|
| 74 |
-
cell_code(f"""\
|
| 75 |
-
import subprocess
|
| 76 |
-
print('--- GPU ---')
|
| 77 |
-
subprocess.run(['nvidia-smi', '-L'], check=False)
|
| 78 |
-
import torch
|
| 79 |
-
print('CUDA OK?', torch.cuda.is_available(), '| device:',
|
| 80 |
-
torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'none')
|
| 81 |
-
""".strip()),
|
| 82 |
-
|
| 83 |
-
cell_md("## 2. Install deps (Kaggle has torch/transformers preinstalled — we just pin compatible versions)"),
|
| 84 |
-
cell_code("""\
|
| 85 |
-
# Qwen3 architecture (used inside DeepSeek-R1-0528-Qwen3-8B) requires
|
| 86 |
-
# transformers >= 4.51. Bump the whole stack to a known-compatible set.
|
| 87 |
-
%pip install -q -U \\
|
| 88 |
-
"transformers>=4.51,<4.55" \\
|
| 89 |
-
"peft>=0.13,<0.16" \\
|
| 90 |
-
"accelerate>=1.1,<1.5" \\
|
| 91 |
-
"bitsandbytes>=0.45.5" \\
|
| 92 |
-
"huggingface_hub>=0.25,<1.0" \\
|
| 93 |
-
"pydantic>=2,<3" \\
|
| 94 |
-
"datasets" "sentencepiece" "protobuf" "safetensors"
|
| 95 |
-
""".strip()),
|
| 96 |
-
|
| 97 |
-
cell_md("## 3. Resolve attached Kaggle Models (read-only, no download)"),
|
| 98 |
-
cell_code(f"""\
|
| 99 |
-
import os, pathlib
|
| 100 |
-
|
| 101 |
-
ACTOR_PATH = '{ACTOR_PATH_LITERAL}'
|
| 102 |
-
CRITIC_PATH = '{CRITIC_PATH_LITERAL}'
|
| 103 |
-
|
| 104 |
-
def verify(path, label):
|
| 105 |
-
p = pathlib.Path(path)
|
| 106 |
-
if not p.exists():
|
| 107 |
-
raise SystemExit(
|
| 108 |
-
f'{{label}} not found at {{path}}. Open the right sidebar → '
|
| 109 |
-
f'"+ Add Input" → Models → attach the model with the matching '
|
| 110 |
-
f'publisher/framework/variation/version (see the markdown above).')
|
| 111 |
-
has_weights = any(p.glob('*.safetensors')) or any(p.glob('*.bin'))
|
| 112 |
-
if not has_weights:
|
| 113 |
-
raise SystemExit(f'{{label}} found at {{path}} but no *.safetensors / *.bin inside.')
|
| 114 |
-
print(f'{{label}}: OK → {{path}}')
|
| 115 |
-
|
| 116 |
-
verify(ACTOR_PATH, 'actor (Phi-3.5-mini-instruct)')
|
| 117 |
-
verify(CRITIC_PATH, 'critic (DeepSeek-R1-0528-Qwen3-8B)')
|
| 118 |
-
|
| 119 |
-
# Push HF Hub cache out of /kaggle/working so an accidental snapshot_download
|
| 120 |
-
# (e.g. by a tokenizer) writes to /tmp instead of eating the 20 GB quota.
|
| 121 |
-
os.environ['HF_HOME'] = '/tmp/hf-cache'
|
| 122 |
-
os.environ['HUGGINGFACE_HUB_CACHE'] = '/tmp/hf-cache'
|
| 123 |
-
os.environ['TRANSFORMERS_CACHE'] = '/tmp/hf-cache'
|
| 124 |
-
pathlib.Path('/tmp/hf-cache').mkdir(parents=True, exist_ok=True)
|
| 125 |
-
|
| 126 |
-
# Optional HF_TOKEN — only used if you want to upload checkpoints.
|
| 127 |
-
try:
|
| 128 |
-
from kaggle_secrets import UserSecretsClient
|
| 129 |
-
os.environ['HF_TOKEN'] = UserSecretsClient().get_secret('HF_TOKEN')
|
| 130 |
-
print('HF_TOKEN attached from Kaggle Secrets')
|
| 131 |
-
except Exception:
|
| 132 |
-
print('No HF_TOKEN — that is fine, training works fully offline now.')
|
| 133 |
-
|
| 134 |
-
# IMPORTANT: do NOT set TRANSFORMERS_TRUST_REMOTE_CODE here. Phi-3 (>=4.40)
|
| 135 |
-
# and Qwen3 (>=4.51) are natively supported by transformers — using the
|
| 136 |
-
# custom modeling_*.py shipped inside the Kaggle Models mount triggers an
|
| 137 |
-
# `AttributeError: 'DynamicCache' object has no attribute 'get_max_length'`
|
| 138 |
-
# because that custom code targets transformers <4.48. We force native impl
|
| 139 |
-
# by NOT enabling trust_remote_code (train_lib.py also passes it as False).
|
| 140 |
-
# Clear any previously-downloaded custom modeling code that an earlier run
|
| 141 |
-
# may have cached, otherwise from_pretrained reuses it from the cache.
|
| 142 |
-
import shutil as _sh, pathlib as _pl
|
| 143 |
-
_modules = _pl.Path('/tmp/hf-cache/modules')
|
| 144 |
-
if _modules.exists():
|
| 145 |
-
_sh.rmtree(_modules, ignore_errors=True)
|
| 146 |
-
print('cleared cached custom modeling code at', _modules)
|
| 147 |
-
""".strip()),
|
| 148 |
-
|
| 149 |
-
cell_md("## 4. Clone the repo (public GitHub) — always pull latest"),
|
| 150 |
-
cell_code(f"""\
|
| 151 |
-
import os, subprocess, pathlib, shutil
|
| 152 |
-
WORK = '/kaggle/working/incident-commander'
|
| 153 |
-
# IMPORTANT: chdir OUT of WORK before deleting it, otherwise git clone fails
|
| 154 |
-
# with "Unable to read current working directory" on a re-run.
|
| 155 |
-
os.chdir('/kaggle/working')
|
| 156 |
-
p = pathlib.Path(WORK)
|
| 157 |
-
if p.exists():
|
| 158 |
-
# Wipe any stale clone from a previous session/run so we always get the
|
| 159 |
-
# newest scripts/run_training.py + colab/train_lib.py from main.
|
| 160 |
-
shutil.rmtree(WORK, ignore_errors=True)
|
| 161 |
-
subprocess.run(['git', 'clone', '--depth', '1',
|
| 162 |
-
'{REPO_URL}', WORK], check=True)
|
| 163 |
-
os.chdir(WORK)
|
| 164 |
-
# Show the commit we are running so it is obvious in the logs.
|
| 165 |
-
subprocess.run(['git', '-C', WORK, 'log', '-1', '--oneline'], check=False)
|
| 166 |
-
print('cwd =', os.getcwd())
|
| 167 |
-
""".strip()),
|
| 168 |
-
|
| 169 |
-
cell_md("## 5. Configure run (shard, paths, env vars)"),
|
| 170 |
-
cell_code(f"""\
|
| 171 |
-
import os
|
| 172 |
-
|
| 173 |
-
os.environ['INCIDENT_COMMANDER_MOCK'] = 'true'
|
| 174 |
-
os.environ['IC_ACTOR_MODEL'] = ACTOR_PATH
|
| 175 |
-
os.environ['IC_CRITIC_PROVIDER'] = 'local' # 7B critic on the same GPU
|
| 176 |
-
os.environ['IC_CRITIC_MODEL'] = CRITIC_PATH
|
| 177 |
-
os.environ['IC_TASK_MODE'] = 'all' # full 381 corpus
|
| 178 |
-
os.environ['IC_TASK_SHARDS'] = '{total_shards}'
|
| 179 |
-
os.environ['IC_TASK_SHARD'] = '{shard}'
|
| 180 |
-
os.environ['IC_TOTAL_UPDATES'] = '60' # ~6h on T4 / P100
|
| 181 |
-
os.environ['IC_ROLLOUTS'] = '3'
|
| 182 |
-
os.environ['IC_MAX_STEPS'] = '12'
|
| 183 |
-
os.environ['IC_CKPT_EVERY'] = '15'
|
| 184 |
-
os.environ['IC_RUN_NAME'] = 'kaggle{shard + 1}'
|
| 185 |
-
|
| 186 |
-
print('actor :', os.environ['IC_ACTOR_MODEL'])
|
| 187 |
-
print('critic:', os.environ['IC_CRITIC_MODEL'])
|
| 188 |
-
print('shard :', os.environ['IC_TASK_SHARD'], '/', os.environ['IC_TASK_SHARDS'])
|
| 189 |
-
""".strip()),
|
| 190 |
-
|
| 191 |
-
cell_md("## 6. Train"),
|
| 192 |
-
cell_code("""\
|
| 193 |
-
# The training script runs to completion. tqdm progress + ETA are streamed
|
| 194 |
-
# to stdout. Kaggle truncates very long outputs — adapter checkpoints are
|
| 195 |
-
# always written to /kaggle/working/incident-commander/colab/logs/ regardless.
|
| 196 |
-
import subprocess, sys
|
| 197 |
-
result = subprocess.run([sys.executable, 'scripts/run_training.py'],
|
| 198 |
-
check=False)
|
| 199 |
-
print('exit code:', result.returncode)
|
| 200 |
-
""".strip()),
|
| 201 |
-
|
| 202 |
-
cell_md("## 7. Package outputs for download"),
|
| 203 |
-
cell_code(f"""\
|
| 204 |
-
import shutil, glob, pathlib
|
| 205 |
-
|
| 206 |
-
LOGS = pathlib.Path('colab/logs')
|
| 207 |
-
finals = sorted(LOGS.glob('adapter_kaggle{shard + 1}_final'))
|
| 208 |
-
ckpts = sorted(LOGS.glob('adapter_kaggle{shard + 1}_u*'))
|
| 209 |
-
keep = (finals or ckpts)
|
| 210 |
-
assert keep, 'No adapter directories found — check the training cell output for errors.'
|
| 211 |
-
src = keep[-1]
|
| 212 |
-
print('packaging', src)
|
| 213 |
-
|
| 214 |
-
dst = pathlib.Path('/kaggle/working/adapter_kaggle{shard + 1}.zip')
|
| 215 |
-
shutil.make_archive(str(dst.with_suffix('')), 'zip', root_dir=src)
|
| 216 |
-
print('zipped to', dst, 'size:', dst.stat().st_size, 'bytes')
|
| 217 |
-
|
| 218 |
-
# Also copy the JSON training log for plotting on your laptop.
|
| 219 |
-
for j in glob.glob('colab/logs/training_kaggle{shard + 1}*.json'):
|
| 220 |
-
shutil.copy(j, '/kaggle/working/')
|
| 221 |
-
print('files in /kaggle/working/:')
|
| 222 |
-
for f in sorted(pathlib.Path('/kaggle/working/').iterdir()):
|
| 223 |
-
if f.name == 'hf-cache': continue # don't list the model cache
|
| 224 |
-
print(' ', f.name, f.stat().st_size if f.is_file() else '<dir>')
|
| 225 |
-
""".strip()),
|
| 226 |
-
|
| 227 |
-
cell_md(f"""\
|
| 228 |
-
## Done
|
| 229 |
-
|
| 230 |
-
Download `adapter_kaggle{shard + 1}.zip` from the **Output** tab on the
|
| 231 |
-
right. Repeat for the other two shards (notebooks 2 and 3), then on your
|
| 232 |
-
laptop run:
|
| 233 |
-
|
| 234 |
-
```powershell
|
| 235 |
-
python scripts/merge_lora_adapters.py `
|
| 236 |
-
--inputs ./adapter_kaggle1 ./adapter_kaggle2 ./adapter_kaggle3 `
|
| 237 |
-
--output ./adapter_merged
|
| 238 |
-
```
|
| 239 |
-
|
| 240 |
-
The merged adapter loads with the standard `peft` API on top of
|
| 241 |
-
`{ACTOR_NAME}`.
|
| 242 |
-
"""),
|
| 243 |
-
]
|
| 244 |
-
|
| 245 |
-
return {
|
| 246 |
-
"cells": cells,
|
| 247 |
-
"metadata": {
|
| 248 |
-
"kernelspec": {"display_name": "Python 3",
|
| 249 |
-
"language": "python",
|
| 250 |
-
"name": "python3"},
|
| 251 |
-
"language_info": {"name": "python", "version": "3.10"},
|
| 252 |
-
"kaggle": {"accelerator": "nvidiaTeslaT4",
|
| 253 |
-
"dataSources": [],
|
| 254 |
-
"isInternetEnabled": True,
|
| 255 |
-
"language": "python",
|
| 256 |
-
"sourceType": "notebook"},
|
| 257 |
-
},
|
| 258 |
-
"nbformat": 4,
|
| 259 |
-
"nbformat_minor": 5,
|
| 260 |
-
}
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
def main() -> None:
|
| 264 |
-
for shard in range(3):
|
| 265 |
-
nb = build(shard)
|
| 266 |
-
path = NOTEBOOK_DIR / f"kaggle_train_shard{shard + 1}.ipynb"
|
| 267 |
-
path.write_text(json.dumps(nb, indent=1), encoding="utf-8")
|
| 268 |
-
print("wrote", path)
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
if __name__ == "__main__":
|
| 272 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
kaggle/kaggle_train_shard1.ipynb
CHANGED
|
@@ -6,94 +6,78 @@
|
|
| 6 |
"source": [
|
| 7 |
"# IncidentCommander RL — Kaggle shard 1 / 3\n",
|
| 8 |
"\n",
|
| 9 |
-
"**Workload:** every 3rd task starting at index 0\n",
|
| 10 |
-
"
|
| 11 |
-
"**deepseek-ai/DeepSeek-R1-0528-Qwen3-8B** critic — both attached as Kaggle Models so they live in\n",
|
| 12 |
-
"the read-only `/kaggle/input/` mount and DO NOT eat the 20 GB working quota.\n",
|
| 13 |
"\n",
|
| 14 |
-
"
|
| 15 |
-
"`+ Add Input` → `Models` tab
|
| 16 |
-
"1.
|
| 17 |
-
"2.
|
| 18 |
"\n",
|
| 19 |
-
"
|
| 20 |
-
"- `/kaggle/input/models/Microsoft/phi-3/pytorch/phi-3.5-mini-instruct/2`\n",
|
| 21 |
-
"- `/kaggle/input/models/deepseek-ai/deepseek-r1-0528/transformers/deepseek-r1-0528-qwen3-8b/1`\n",
|
| 22 |
-
"\n",
|
| 23 |
-
"**Required notebook settings** (right-hand sidebar):\n",
|
| 24 |
"- Accelerator: `GPU T4 x2` or `GPU P100`\n",
|
|
|
|
| 25 |
"- Persistence: `Files only`\n",
|
| 26 |
-
"- Internet: `On` (for `git clone` and optional HF Hub upload)\n",
|
| 27 |
-
"\n",
|
| 28 |
-
"**Optional** (only if you want intermediate checkpoint upload to your HF\n",
|
| 29 |
-
"repo): Add-ons → Secrets → add `HF_TOKEN` and toggle it on.\n",
|
| 30 |
"\n",
|
| 31 |
-
"**Output:** `/kaggle/working/adapter_kaggle1.zip` — download from
|
| 32 |
-
"the sidebar after the run finishes. Combine all 3 with\n",
|
| 33 |
-
"`scripts/merge_lora_adapters.py` on your laptop.\n"
|
| 34 |
]
|
| 35 |
},
|
| 36 |
{
|
| 37 |
-
"cell_type": "
|
|
|
|
|
|
|
| 38 |
"metadata": {},
|
|
|
|
| 39 |
"source": [
|
| 40 |
-
"#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
]
|
| 42 |
},
|
| 43 |
{
|
| 44 |
"cell_type": "code",
|
| 45 |
"execution_count": null,
|
|
|
|
| 46 |
"metadata": {},
|
| 47 |
"outputs": [],
|
| 48 |
"source": [
|
|
|
|
| 49 |
"import subprocess\n",
|
| 50 |
"print('--- GPU ---')\n",
|
| 51 |
"subprocess.run(['nvidia-smi', '-L'], check=False)\n",
|
| 52 |
"import torch\n",
|
| 53 |
-
"print('CUDA OK?', torch.cuda.is_available(),
|
| 54 |
-
" torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'none')"
|
| 55 |
-
]
|
| 56 |
-
},
|
| 57 |
-
{
|
| 58 |
-
"cell_type": "markdown",
|
| 59 |
-
"metadata": {},
|
| 60 |
-
"source": [
|
| 61 |
-
"## 2. Install deps (Kaggle has torch/transformers preinstalled — we just pin compatible versions)"
|
| 62 |
]
|
| 63 |
},
|
| 64 |
{
|
| 65 |
"cell_type": "code",
|
| 66 |
"execution_count": null,
|
|
|
|
| 67 |
"metadata": {},
|
| 68 |
"outputs": [],
|
| 69 |
"source": [
|
| 70 |
-
"#
|
| 71 |
-
"
|
| 72 |
-
"%pip install -q -U \\\n",
|
| 73 |
-
" \"transformers>=4.51,<4.55\" \\\n",
|
| 74 |
-
" \"peft>=0.13,<0.16\" \\\n",
|
| 75 |
-
" \"accelerate>=1.1,<1.5\" \\\n",
|
| 76 |
-
" \"bitsandbytes>=0.45.5\" \\\n",
|
| 77 |
-
" \"huggingface_hub>=0.25,<1.0\" \\\n",
|
| 78 |
-
" \"pydantic>=2,<3\" \\\n",
|
| 79 |
-
" \"datasets\" \"sentencepiece\" \"protobuf\" \"safetensors\""
|
| 80 |
-
]
|
| 81 |
-
},
|
| 82 |
-
{
|
| 83 |
-
"cell_type": "markdown",
|
| 84 |
-
"metadata": {},
|
| 85 |
-
"source": [
|
| 86 |
-
"## 3. Resolve attached Kaggle Models (read-only, no download)"
|
| 87 |
-
]
|
| 88 |
-
},
|
| 89 |
-
{
|
| 90 |
-
"cell_type": "code",
|
| 91 |
-
"execution_count": null,
|
| 92 |
-
"id": "4e224033",
|
| 93 |
-
"metadata": {},
|
| 94 |
-
"outputs": [],
|
| 95 |
-
"source": [
|
| 96 |
-
"import os, pathlib\n",
|
| 97 |
"\n",
|
| 98 |
"ACTOR_PATH = '/kaggle/input/models/Microsoft/phi-3/pytorch/phi-3.5-mini-instruct/2'\n",
|
| 99 |
"CRITIC_PATH = '/kaggle/input/models/deepseek-ai/deepseek-r1-0528/transformers/deepseek-r1-0528-qwen3-8b/1'\n",
|
|
@@ -101,179 +85,143 @@
|
|
| 101 |
"def verify(path, label):\n",
|
| 102 |
" p = pathlib.Path(path)\n",
|
| 103 |
" if not p.exists():\n",
|
| 104 |
-
" raise SystemExit(\n",
|
| 105 |
-
"
|
| 106 |
-
"
|
| 107 |
-
"
|
| 108 |
-
" has_weights = any(p.glob('*.safetensors')) or any(p.glob('*.bin'))\n",
|
| 109 |
-
" if not has_weights:\n",
|
| 110 |
-
" raise SystemExit(f'{label} found at {path} but no *.safetensors / *.bin inside.')\n",
|
| 111 |
-
" print(f'{label}: OK → {path}')\n",
|
| 112 |
"\n",
|
| 113 |
"verify(ACTOR_PATH, 'actor (Phi-3.5-mini-instruct)')\n",
|
| 114 |
"verify(CRITIC_PATH, 'critic (DeepSeek-R1-0528-Qwen3-8B)')\n",
|
| 115 |
"\n",
|
| 116 |
-
"# Push HF Hub cache out of /kaggle/working so an accidental snapshot_download\n",
|
| 117 |
-
"# (e.g. by a tokenizer) writes to /tmp instead of eating the 20 GB quota.\n",
|
| 118 |
"os.environ['HF_HOME'] = '/tmp/hf-cache'\n",
|
| 119 |
"os.environ['HUGGINGFACE_HUB_CACHE'] = '/tmp/hf-cache'\n",
|
| 120 |
"os.environ['TRANSFORMERS_CACHE'] = '/tmp/hf-cache'\n",
|
| 121 |
"pathlib.Path('/tmp/hf-cache').mkdir(parents=True, exist_ok=True)\n",
|
| 122 |
"\n",
|
| 123 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
"try:\n",
|
| 125 |
" from kaggle_secrets import UserSecretsClient\n",
|
| 126 |
" os.environ['HF_TOKEN'] = UserSecretsClient().get_secret('HF_TOKEN')\n",
|
| 127 |
" print('HF_TOKEN attached from Kaggle Secrets')\n",
|
| 128 |
"except Exception:\n",
|
| 129 |
-
" print('No HF_TOKEN
|
| 130 |
"\n",
|
| 131 |
-
"
|
| 132 |
-
"
|
| 133 |
-
"
|
| 134 |
-
"
|
| 135 |
-
"
|
| 136 |
-
"
|
| 137 |
-
"
|
| 138 |
-
"
|
| 139 |
-
"
|
| 140 |
-
"
|
| 141 |
-
"
|
| 142 |
-
"
|
| 143 |
-
"
|
| 144 |
-
]
|
| 145 |
-
},
|
| 146 |
-
{
|
| 147 |
-
"cell_type": "markdown",
|
| 148 |
-
"metadata": {},
|
| 149 |
-
"source": [
|
| 150 |
-
"## 4. Clone the repo (public GitHub) — always pull latest"
|
| 151 |
]
|
| 152 |
},
|
| 153 |
{
|
| 154 |
"cell_type": "code",
|
| 155 |
"execution_count": null,
|
|
|
|
| 156 |
"metadata": {},
|
| 157 |
"outputs": [],
|
| 158 |
"source": [
|
|
|
|
| 159 |
"import os, subprocess, pathlib, shutil\n",
|
| 160 |
"WORK = '/kaggle/working/incident-commander'\n",
|
| 161 |
-
"# IMPORTANT: chdir OUT of WORK before deleting it, otherwise git clone fails\n",
|
| 162 |
-
"# with \"Unable to read current working directory\" on a re-run.\n",
|
| 163 |
"os.chdir('/kaggle/working')\n",
|
| 164 |
-
"
|
| 165 |
-
"if p.exists():\n",
|
| 166 |
-
" # Wipe any stale clone from a previous session/run so we always get the\n",
|
| 167 |
-
" # newest scripts/run_training.py + colab/train_lib.py from main.\n",
|
| 168 |
" shutil.rmtree(WORK, ignore_errors=True)\n",
|
| 169 |
"subprocess.run(['git', 'clone', '--depth', '1',\n",
|
| 170 |
-
" 'https://github.com/r1cksync/meta-rl-hack.git', WORK],
|
|
|
|
| 171 |
"os.chdir(WORK)\n",
|
| 172 |
-
"# Show the commit we are running so it is obvious in the logs.\n",
|
| 173 |
"subprocess.run(['git', '-C', WORK, 'log', '-1', '--oneline'], check=False)\n",
|
| 174 |
"print('cwd =', os.getcwd())"
|
| 175 |
]
|
| 176 |
},
|
| 177 |
-
{
|
| 178 |
-
"cell_type": "markdown",
|
| 179 |
-
"metadata": {},
|
| 180 |
-
"source": [
|
| 181 |
-
"## 5. Configure run (shard, paths, env vars)"
|
| 182 |
-
]
|
| 183 |
-
},
|
| 184 |
{
|
| 185 |
"cell_type": "code",
|
| 186 |
"execution_count": null,
|
|
|
|
| 187 |
"metadata": {},
|
| 188 |
"outputs": [],
|
| 189 |
"source": [
|
|
|
|
| 190 |
"import os\n",
|
| 191 |
-
"\n",
|
| 192 |
"os.environ['INCIDENT_COMMANDER_MOCK'] = 'true'\n",
|
| 193 |
"os.environ['IC_ACTOR_MODEL'] = ACTOR_PATH\n",
|
| 194 |
-
"os.environ['IC_CRITIC_PROVIDER'] = 'local'
|
| 195 |
"os.environ['IC_CRITIC_MODEL'] = CRITIC_PATH\n",
|
| 196 |
-
"os.environ['IC_TASK_MODE'] = 'all'
|
| 197 |
"os.environ['IC_TASK_SHARDS'] = '3'\n",
|
| 198 |
"os.environ['IC_TASK_SHARD'] = '0'\n",
|
| 199 |
-
"os.environ['IC_TOTAL_UPDATES'] = '60'
|
| 200 |
"os.environ['IC_ROLLOUTS'] = '3'\n",
|
| 201 |
"os.environ['IC_MAX_STEPS'] = '12'\n",
|
| 202 |
"os.environ['IC_CKPT_EVERY'] = '15'\n",
|
| 203 |
"os.environ['IC_RUN_NAME'] = 'kaggle1'\n",
|
| 204 |
-
"\n",
|
| 205 |
"print('actor :', os.environ['IC_ACTOR_MODEL'])\n",
|
| 206 |
"print('critic:', os.environ['IC_CRITIC_MODEL'])\n",
|
| 207 |
"print('shard :', os.environ['IC_TASK_SHARD'], '/', os.environ['IC_TASK_SHARDS'])"
|
| 208 |
]
|
| 209 |
},
|
| 210 |
-
{
|
| 211 |
-
"cell_type": "markdown",
|
| 212 |
-
"metadata": {},
|
| 213 |
-
"source": [
|
| 214 |
-
"## 6. Train"
|
| 215 |
-
]
|
| 216 |
-
},
|
| 217 |
{
|
| 218 |
"cell_type": "code",
|
| 219 |
"execution_count": null,
|
|
|
|
| 220 |
"metadata": {},
|
| 221 |
"outputs": [],
|
| 222 |
"source": [
|
| 223 |
-
"#
|
| 224 |
-
"# to stdout. Kaggle truncates very long outputs — adapter checkpoints are\n",
|
| 225 |
-
"# always written to /kaggle/working/incident-commander/colab/logs/ regardless.\n",
|
| 226 |
"import subprocess, sys\n",
|
| 227 |
-
"result = subprocess.run([sys.executable, 'scripts/run_training.py'],\n",
|
| 228 |
-
" check=False)\n",
|
| 229 |
"print('exit code:', result.returncode)"
|
| 230 |
]
|
| 231 |
},
|
| 232 |
-
{
|
| 233 |
-
"cell_type": "markdown",
|
| 234 |
-
"metadata": {},
|
| 235 |
-
"source": [
|
| 236 |
-
"## 7. Package outputs for download"
|
| 237 |
-
]
|
| 238 |
-
},
|
| 239 |
{
|
| 240 |
"cell_type": "code",
|
| 241 |
"execution_count": null,
|
|
|
|
| 242 |
"metadata": {},
|
| 243 |
"outputs": [],
|
| 244 |
"source": [
|
|
|
|
| 245 |
"import shutil, glob, pathlib\n",
|
| 246 |
-
"\n",
|
| 247 |
"LOGS = pathlib.Path('colab/logs')\n",
|
| 248 |
"finals = sorted(LOGS.glob('adapter_kaggle1_final'))\n",
|
| 249 |
"ckpts = sorted(LOGS.glob('adapter_kaggle1_u*'))\n",
|
| 250 |
-
"keep
|
| 251 |
-
"assert keep, 'No adapter directories found
|
| 252 |
"src = keep[-1]\n",
|
| 253 |
"print('packaging', src)\n",
|
| 254 |
-
"\n",
|
| 255 |
"dst = pathlib.Path('/kaggle/working/adapter_kaggle1.zip')\n",
|
| 256 |
"shutil.make_archive(str(dst.with_suffix('')), 'zip', root_dir=src)\n",
|
| 257 |
"print('zipped to', dst, 'size:', dst.stat().st_size, 'bytes')\n",
|
| 258 |
-
"\n",
|
| 259 |
-
"# Also copy the JSON training log for plotting on your laptop.\n",
|
| 260 |
"for j in glob.glob('colab/logs/training_kaggle1*.json'):\n",
|
| 261 |
" shutil.copy(j, '/kaggle/working/')\n",
|
| 262 |
"print('files in /kaggle/working/:')\n",
|
| 263 |
"for f in sorted(pathlib.Path('/kaggle/working/').iterdir()):\n",
|
| 264 |
-
" if f.name == 'hf-cache':
|
|
|
|
| 265 |
" print(' ', f.name, f.stat().st_size if f.is_file() else '<dir>')"
|
| 266 |
]
|
| 267 |
},
|
| 268 |
{
|
| 269 |
"cell_type": "markdown",
|
|
|
|
| 270 |
"metadata": {},
|
| 271 |
"source": [
|
| 272 |
"## Done\n",
|
| 273 |
"\n",
|
| 274 |
-
"Download `adapter_kaggle1.zip` from the **Output** tab on the\n",
|
| 275 |
-
"
|
| 276 |
-
"laptop run:\n",
|
| 277 |
"\n",
|
| 278 |
"```powershell\n",
|
| 279 |
"python scripts/merge_lora_adapters.py `\n",
|
|
@@ -281,8 +229,7 @@
|
|
| 281 |
" --output ./adapter_merged\n",
|
| 282 |
"```\n",
|
| 283 |
"\n",
|
| 284 |
-
"The merged adapter loads with the standard `peft` API on top of
|
| 285 |
-
"`microsoft/Phi-3.5-mini-instruct`.\n"
|
| 286 |
]
|
| 287 |
}
|
| 288 |
],
|
|
|
|
| 6 |
"source": [
|
| 7 |
"# IncidentCommander RL — Kaggle shard 1 / 3\n",
|
| 8 |
"\n",
|
| 9 |
+
"**Workload:** every 3rd task starting at index **0** (~127 of 381 scenarios).\n",
|
| 10 |
+
"Trains a LoRA on **Phi-3.5-mini-instruct** using a local **DeepSeek-R1-0528-Qwen3-8B** critic.\n",
|
|
|
|
|
|
|
| 11 |
"\n",
|
| 12 |
+
"## REQUIRED — attach these 2 Kaggle Models before running\n",
|
| 13 |
+
"Right sidebar → `+ Add Input` → `Models` tab:\n",
|
| 14 |
+
"1. `Microsoft / phi-3` → framework `PyTorch` → variation `phi-3.5-mini-instruct` → version `2`\n",
|
| 15 |
+
"2. `deepseek-ai / deepseek-r1-0528` → framework `Transformers` → variation `deepseek-r1-0528-qwen3-8b` → version `1`\n",
|
| 16 |
"\n",
|
| 17 |
+
"## Required notebook settings\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
"- Accelerator: `GPU T4 x2` or `GPU P100`\n",
|
| 19 |
+
"- Internet: `On`\n",
|
| 20 |
"- Persistence: `Files only`\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
"\n",
|
| 22 |
+
"**Output:** `/kaggle/working/adapter_kaggle1.zip` — download from the sidebar after the run finishes."
|
|
|
|
|
|
|
| 23 |
]
|
| 24 |
},
|
| 25 |
{
|
| 26 |
+
"cell_type": "code",
|
| 27 |
+
"execution_count": null,
|
| 28 |
+
"id": "1c28582e",
|
| 29 |
"metadata": {},
|
| 30 |
+
"outputs": [],
|
| 31 |
"source": [
|
| 32 |
+
"# === 1. Install deps + unsloth (best-effort) ===\n",
|
| 33 |
+
"# Qwen3 (in DeepSeek-R1-0528) needs transformers >= 4.51. Unsloth speeds up\n",
|
| 34 |
+
"# the actor ~2x; if its install fails on this Kaggle image we fall back to\n",
|
| 35 |
+
"# pure HF transformers automatically (train_lib.py handles both paths).\n",
|
| 36 |
+
"import subprocess, sys\n",
|
| 37 |
+
"\n",
|
| 38 |
+
"def pip(*args):\n",
|
| 39 |
+
" return subprocess.run([sys.executable, '-m', 'pip', 'install', '-q', *args],\n",
|
| 40 |
+
" check=False).returncode\n",
|
| 41 |
+
"\n",
|
| 42 |
+
"rc = pip('-U', 'unsloth')\n",
|
| 43 |
+
"print('[install] unsloth rc =', rc, '(non-zero is fine, HF fallback works)')\n",
|
| 44 |
+
"\n",
|
| 45 |
+
"pip('-U',\n",
|
| 46 |
+
" 'transformers>=4.51,<4.55',\n",
|
| 47 |
+
" 'peft>=0.13,<0.16',\n",
|
| 48 |
+
" 'accelerate>=1.1,<1.5',\n",
|
| 49 |
+
" 'bitsandbytes>=0.45.5',\n",
|
| 50 |
+
" 'huggingface_hub>=0.25,<1.0',\n",
|
| 51 |
+
" 'pydantic>=2,<3',\n",
|
| 52 |
+
" 'datasets', 'sentencepiece', 'protobuf', 'safetensors')\n",
|
| 53 |
+
"print('[install] pinned stack done')"
|
| 54 |
]
|
| 55 |
},
|
| 56 |
{
|
| 57 |
"cell_type": "code",
|
| 58 |
"execution_count": null,
|
| 59 |
+
"id": "37a868c2",
|
| 60 |
"metadata": {},
|
| 61 |
"outputs": [],
|
| 62 |
"source": [
|
| 63 |
+
"# === 2. GPU sanity ===\n",
|
| 64 |
"import subprocess\n",
|
| 65 |
"print('--- GPU ---')\n",
|
| 66 |
"subprocess.run(['nvidia-smi', '-L'], check=False)\n",
|
| 67 |
"import torch\n",
|
| 68 |
+
"print('CUDA OK?', torch.cuda.is_available(),\n",
|
| 69 |
+
" '| device:', torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'none')"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
]
|
| 71 |
},
|
| 72 |
{
|
| 73 |
"cell_type": "code",
|
| 74 |
"execution_count": null,
|
| 75 |
+
"id": "fa14ea90",
|
| 76 |
"metadata": {},
|
| 77 |
"outputs": [],
|
| 78 |
"source": [
|
| 79 |
+
"# === 3. Verify attached Kaggle Models + suppress warning spam ===\n",
|
| 80 |
+
"import os, pathlib, shutil, warnings, logging\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
"\n",
|
| 82 |
"ACTOR_PATH = '/kaggle/input/models/Microsoft/phi-3/pytorch/phi-3.5-mini-instruct/2'\n",
|
| 83 |
"CRITIC_PATH = '/kaggle/input/models/deepseek-ai/deepseek-r1-0528/transformers/deepseek-r1-0528-qwen3-8b/1'\n",
|
|
|
|
| 85 |
"def verify(path, label):\n",
|
| 86 |
" p = pathlib.Path(path)\n",
|
| 87 |
" if not p.exists():\n",
|
| 88 |
+
" raise SystemExit(f'{label} not found at {path}. Attach the matching Kaggle Model.')\n",
|
| 89 |
+
" if not (any(p.glob('*.safetensors')) or any(p.glob('*.bin'))):\n",
|
| 90 |
+
" raise SystemExit(f'{label} found at {path} but no weight files inside.')\n",
|
| 91 |
+
" print(f'{label}: OK -> {path}')\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
"\n",
|
| 93 |
"verify(ACTOR_PATH, 'actor (Phi-3.5-mini-instruct)')\n",
|
| 94 |
"verify(CRITIC_PATH, 'critic (DeepSeek-R1-0528-Qwen3-8B)')\n",
|
| 95 |
"\n",
|
|
|
|
|
|
|
| 96 |
"os.environ['HF_HOME'] = '/tmp/hf-cache'\n",
|
| 97 |
"os.environ['HUGGINGFACE_HUB_CACHE'] = '/tmp/hf-cache'\n",
|
| 98 |
"os.environ['TRANSFORMERS_CACHE'] = '/tmp/hf-cache'\n",
|
| 99 |
"pathlib.Path('/tmp/hf-cache').mkdir(parents=True, exist_ok=True)\n",
|
| 100 |
"\n",
|
| 101 |
+
"modules_dir = pathlib.Path('/tmp/hf-cache/modules')\n",
|
| 102 |
+
"if modules_dir.exists():\n",
|
| 103 |
+
" shutil.rmtree(modules_dir, ignore_errors=True)\n",
|
| 104 |
+
" print('cleared cached custom modeling code at', modules_dir)\n",
|
| 105 |
+
"\n",
|
| 106 |
"try:\n",
|
| 107 |
" from kaggle_secrets import UserSecretsClient\n",
|
| 108 |
" os.environ['HF_TOKEN'] = UserSecretsClient().get_secret('HF_TOKEN')\n",
|
| 109 |
" print('HF_TOKEN attached from Kaggle Secrets')\n",
|
| 110 |
"except Exception:\n",
|
| 111 |
+
" print('No HF_TOKEN -- training runs fully offline (that is fine).')\n",
|
| 112 |
"\n",
|
| 113 |
+
"for pat in ('.*Caching is incompatible with gradient checkpointing.*',\n",
|
| 114 |
+
" '.*None of the inputs have requires_grad=True.*',\n",
|
| 115 |
+
" '.*use_reentrant parameter should be passed explicitly.*',\n",
|
| 116 |
+
" \".*AccumulateGrad node's stream does not match.*\"):\n",
|
| 117 |
+
" warnings.filterwarnings('ignore', message=pat)\n",
|
| 118 |
+
"\n",
|
| 119 |
+
"class _PhiFilter(logging.Filter):\n",
|
| 120 |
+
" def filter(self, r):\n",
|
| 121 |
+
" return 'Caching is incompatible' not in r.getMessage()\n",
|
| 122 |
+
"for n in ('transformers', 'transformers.models.phi3.modeling_phi3',\n",
|
| 123 |
+
" 'torch.utils.checkpoint'):\n",
|
| 124 |
+
" logging.getLogger(n).addFilter(_PhiFilter())\n",
|
| 125 |
+
"print('warning filters installed')"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
]
|
| 127 |
},
|
| 128 |
{
|
| 129 |
"cell_type": "code",
|
| 130 |
"execution_count": null,
|
| 131 |
+
"id": "b83c7a39",
|
| 132 |
"metadata": {},
|
| 133 |
"outputs": [],
|
| 134 |
"source": [
|
| 135 |
+
"# === 4. Clone the repo (fresh every run, prints commit hash) ===\n",
|
| 136 |
"import os, subprocess, pathlib, shutil\n",
|
| 137 |
"WORK = '/kaggle/working/incident-commander'\n",
|
|
|
|
|
|
|
| 138 |
"os.chdir('/kaggle/working')\n",
|
| 139 |
+
"if pathlib.Path(WORK).exists():\n",
|
|
|
|
|
|
|
|
|
|
| 140 |
" shutil.rmtree(WORK, ignore_errors=True)\n",
|
| 141 |
"subprocess.run(['git', 'clone', '--depth', '1',\n",
|
| 142 |
+
" 'https://github.com/r1cksync/meta-rl-hack.git', WORK],\n",
|
| 143 |
+
" check=True)\n",
|
| 144 |
"os.chdir(WORK)\n",
|
|
|
|
| 145 |
"subprocess.run(['git', '-C', WORK, 'log', '-1', '--oneline'], check=False)\n",
|
| 146 |
"print('cwd =', os.getcwd())"
|
| 147 |
]
|
| 148 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 149 |
{
|
| 150 |
"cell_type": "code",
|
| 151 |
"execution_count": null,
|
| 152 |
+
"id": "81701d83",
|
| 153 |
"metadata": {},
|
| 154 |
"outputs": [],
|
| 155 |
"source": [
|
| 156 |
+
"# === 5. Configure run (shard 1 / 3) ===\n",
|
| 157 |
"import os\n",
|
|
|
|
| 158 |
"os.environ['INCIDENT_COMMANDER_MOCK'] = 'true'\n",
|
| 159 |
"os.environ['IC_ACTOR_MODEL'] = ACTOR_PATH\n",
|
| 160 |
+
"os.environ['IC_CRITIC_PROVIDER'] = 'local'\n",
|
| 161 |
"os.environ['IC_CRITIC_MODEL'] = CRITIC_PATH\n",
|
| 162 |
+
"os.environ['IC_TASK_MODE'] = 'all'\n",
|
| 163 |
"os.environ['IC_TASK_SHARDS'] = '3'\n",
|
| 164 |
"os.environ['IC_TASK_SHARD'] = '0'\n",
|
| 165 |
+
"os.environ['IC_TOTAL_UPDATES'] = '60'\n",
|
| 166 |
"os.environ['IC_ROLLOUTS'] = '3'\n",
|
| 167 |
"os.environ['IC_MAX_STEPS'] = '12'\n",
|
| 168 |
"os.environ['IC_CKPT_EVERY'] = '15'\n",
|
| 169 |
"os.environ['IC_RUN_NAME'] = 'kaggle1'\n",
|
|
|
|
| 170 |
"print('actor :', os.environ['IC_ACTOR_MODEL'])\n",
|
| 171 |
"print('critic:', os.environ['IC_CRITIC_MODEL'])\n",
|
| 172 |
"print('shard :', os.environ['IC_TASK_SHARD'], '/', os.environ['IC_TASK_SHARDS'])"
|
| 173 |
]
|
| 174 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
{
|
| 176 |
"cell_type": "code",
|
| 177 |
"execution_count": null,
|
| 178 |
+
"id": "5fecb57e",
|
| 179 |
"metadata": {},
|
| 180 |
"outputs": [],
|
| 181 |
"source": [
|
| 182 |
+
"# === 6. Train ===\n",
|
|
|
|
|
|
|
| 183 |
"import subprocess, sys\n",
|
| 184 |
+
"result = subprocess.run([sys.executable, 'scripts/run_training.py'], check=False)\n",
|
|
|
|
| 185 |
"print('exit code:', result.returncode)"
|
| 186 |
]
|
| 187 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
{
|
| 189 |
"cell_type": "code",
|
| 190 |
"execution_count": null,
|
| 191 |
+
"id": "ed71f261",
|
| 192 |
"metadata": {},
|
| 193 |
"outputs": [],
|
| 194 |
"source": [
|
| 195 |
+
"# === 7. Package outputs for download ===\n",
|
| 196 |
"import shutil, glob, pathlib\n",
|
|
|
|
| 197 |
"LOGS = pathlib.Path('colab/logs')\n",
|
| 198 |
"finals = sorted(LOGS.glob('adapter_kaggle1_final'))\n",
|
| 199 |
"ckpts = sorted(LOGS.glob('adapter_kaggle1_u*'))\n",
|
| 200 |
+
"keep = (finals or ckpts)\n",
|
| 201 |
+
"assert keep, 'No adapter directories found -- check the training cell output.'\n",
|
| 202 |
"src = keep[-1]\n",
|
| 203 |
"print('packaging', src)\n",
|
|
|
|
| 204 |
"dst = pathlib.Path('/kaggle/working/adapter_kaggle1.zip')\n",
|
| 205 |
"shutil.make_archive(str(dst.with_suffix('')), 'zip', root_dir=src)\n",
|
| 206 |
"print('zipped to', dst, 'size:', dst.stat().st_size, 'bytes')\n",
|
|
|
|
|
|
|
| 207 |
"for j in glob.glob('colab/logs/training_kaggle1*.json'):\n",
|
| 208 |
" shutil.copy(j, '/kaggle/working/')\n",
|
| 209 |
"print('files in /kaggle/working/:')\n",
|
| 210 |
"for f in sorted(pathlib.Path('/kaggle/working/').iterdir()):\n",
|
| 211 |
+
" if f.name == 'hf-cache':\n",
|
| 212 |
+
" continue\n",
|
| 213 |
" print(' ', f.name, f.stat().st_size if f.is_file() else '<dir>')"
|
| 214 |
]
|
| 215 |
},
|
| 216 |
{
|
| 217 |
"cell_type": "markdown",
|
| 218 |
+
"id": "1be8077f",
|
| 219 |
"metadata": {},
|
| 220 |
"source": [
|
| 221 |
"## Done\n",
|
| 222 |
"\n",
|
| 223 |
+
"Download `adapter_kaggle1.zip` from the **Output** tab on the right.\n",
|
| 224 |
+
"Run shard 2 and shard 3 in parallel browser tabs, then on your laptop:\n",
|
|
|
|
| 225 |
"\n",
|
| 226 |
"```powershell\n",
|
| 227 |
"python scripts/merge_lora_adapters.py `\n",
|
|
|
|
| 229 |
" --output ./adapter_merged\n",
|
| 230 |
"```\n",
|
| 231 |
"\n",
|
| 232 |
+
"The merged adapter loads with the standard `peft` API on top of `microsoft/Phi-3.5-mini-instruct`."
|
|
|
|
| 233 |
]
|
| 234 |
}
|
| 235 |
],
|
kaggle/kaggle_train_shard2.ipynb
CHANGED
|
@@ -4,95 +4,77 @@
|
|
| 4 |
"cell_type": "markdown",
|
| 5 |
"metadata": {},
|
| 6 |
"source": [
|
| 7 |
-
"# IncidentCommander RL
|
| 8 |
"\n",
|
| 9 |
-
"**Workload:** every 3rd task starting at index 1\n",
|
| 10 |
-
"
|
| 11 |
-
"**deepseek-ai/DeepSeek-R1-0528-Qwen3-8B** critic \u2014 both attached as Kaggle Models so they live in\n",
|
| 12 |
-
"the read-only `/kaggle/input/` mount and DO NOT eat the 20 GB working quota.\n",
|
| 13 |
"\n",
|
| 14 |
-
"
|
| 15 |
-
"`+ Add Input`
|
| 16 |
-
"1.
|
| 17 |
-
"2.
|
| 18 |
"\n",
|
| 19 |
-
"
|
| 20 |
-
"- `/kaggle/input/models/Microsoft/phi-3/pytorch/phi-3.5-mini-instruct/2`\n",
|
| 21 |
-
"- `/kaggle/input/models/deepseek-ai/deepseek-r1-0528/transformers/deepseek-r1-0528-qwen3-8b/1`\n",
|
| 22 |
-
"\n",
|
| 23 |
-
"**Required notebook settings** (right-hand sidebar):\n",
|
| 24 |
"- Accelerator: `GPU T4 x2` or `GPU P100`\n",
|
|
|
|
| 25 |
"- Persistence: `Files only`\n",
|
| 26 |
-
"- Internet: `On` (for `git clone` and optional HF Hub upload)\n",
|
| 27 |
-
"\n",
|
| 28 |
-
"**Optional** (only if you want intermediate checkpoint upload to your HF\n",
|
| 29 |
-
"repo): Add-ons \u2192 Secrets \u2192 add `HF_TOKEN` and toggle it on.\n",
|
| 30 |
"\n",
|
| 31 |
-
"**Output:** `/kaggle/working/adapter_kaggle2.zip`
|
| 32 |
-
"the sidebar after the run finishes. Combine all 3 with\n",
|
| 33 |
-
"`scripts/merge_lora_adapters.py` on your laptop.\n"
|
| 34 |
]
|
| 35 |
},
|
| 36 |
{
|
| 37 |
-
"cell_type": "
|
|
|
|
| 38 |
"metadata": {},
|
|
|
|
| 39 |
"source": [
|
| 40 |
-
"#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
]
|
| 42 |
},
|
| 43 |
{
|
| 44 |
"cell_type": "code",
|
| 45 |
-
"metadata": {},
|
| 46 |
"execution_count": null,
|
|
|
|
| 47 |
"outputs": [],
|
| 48 |
"source": [
|
|
|
|
| 49 |
"import subprocess\n",
|
| 50 |
"print('--- GPU ---')\n",
|
| 51 |
"subprocess.run(['nvidia-smi', '-L'], check=False)\n",
|
| 52 |
"import torch\n",
|
| 53 |
-
"print('CUDA OK?', torch.cuda.is_available(),
|
| 54 |
-
" torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'none')"
|
| 55 |
-
]
|
| 56 |
-
},
|
| 57 |
-
{
|
| 58 |
-
"cell_type": "markdown",
|
| 59 |
-
"metadata": {},
|
| 60 |
-
"source": [
|
| 61 |
-
"## 2. Install deps (Kaggle has torch/transformers preinstalled \u2014 we just pin compatible versions)"
|
| 62 |
]
|
| 63 |
},
|
| 64 |
{
|
| 65 |
"cell_type": "code",
|
| 66 |
-
"metadata": {},
|
| 67 |
"execution_count": null,
|
| 68 |
-
"outputs": [],
|
| 69 |
-
"source": [
|
| 70 |
-
"# Qwen3 architecture (used inside DeepSeek-R1-0528-Qwen3-8B) requires\n",
|
| 71 |
-
"# transformers >= 4.51. Bump the whole stack to a known-compatible set.\n",
|
| 72 |
-
"%pip install -q -U \\\n",
|
| 73 |
-
" \"transformers>=4.51,<4.55\" \\\n",
|
| 74 |
-
" \"peft>=0.13,<0.16\" \\\n",
|
| 75 |
-
" \"accelerate>=1.1,<1.5\" \\\n",
|
| 76 |
-
" \"bitsandbytes>=0.45.5\" \\\n",
|
| 77 |
-
" \"huggingface_hub>=0.25,<1.0\" \\\n",
|
| 78 |
-
" \"pydantic>=2,<3\" \\\n",
|
| 79 |
-
" \"datasets\" \"sentencepiece\" \"protobuf\" \"safetensors\""
|
| 80 |
-
]
|
| 81 |
-
},
|
| 82 |
-
{
|
| 83 |
-
"cell_type": "markdown",
|
| 84 |
-
"metadata": {},
|
| 85 |
-
"source": [
|
| 86 |
-
"## 3. Resolve attached Kaggle Models (read-only, no download)"
|
| 87 |
-
]
|
| 88 |
-
},
|
| 89 |
-
{
|
| 90 |
-
"cell_type": "code",
|
| 91 |
"metadata": {},
|
| 92 |
-
"execution_count": null,
|
| 93 |
"outputs": [],
|
| 94 |
"source": [
|
| 95 |
-
"
|
|
|
|
| 96 |
"\n",
|
| 97 |
"ACTOR_PATH = '/kaggle/input/models/Microsoft/phi-3/pytorch/phi-3.5-mini-instruct/2'\n",
|
| 98 |
"CRITIC_PATH = '/kaggle/input/models/deepseek-ai/deepseek-r1-0528/transformers/deepseek-r1-0528-qwen3-8b/1'\n",
|
|
@@ -100,167 +82,127 @@
|
|
| 100 |
"def verify(path, label):\n",
|
| 101 |
" p = pathlib.Path(path)\n",
|
| 102 |
" if not p.exists():\n",
|
| 103 |
-
" raise SystemExit(\n",
|
| 104 |
-
"
|
| 105 |
-
"
|
| 106 |
-
"
|
| 107 |
-
" has_weights = any(p.glob('*.safetensors')) or any(p.glob('*.bin'))\n",
|
| 108 |
-
" if not has_weights:\n",
|
| 109 |
-
" raise SystemExit(f'{label} found at {path} but no *.safetensors / *.bin inside.')\n",
|
| 110 |
-
" print(f'{label}: OK \u2192 {path}')\n",
|
| 111 |
"\n",
|
| 112 |
"verify(ACTOR_PATH, 'actor (Phi-3.5-mini-instruct)')\n",
|
| 113 |
"verify(CRITIC_PATH, 'critic (DeepSeek-R1-0528-Qwen3-8B)')\n",
|
| 114 |
"\n",
|
| 115 |
-
"# Push HF Hub cache out of /kaggle/working so an accidental snapshot_download\n",
|
| 116 |
-
"# (e.g. by a tokenizer) writes to /tmp instead of eating the 20 GB quota.\n",
|
| 117 |
"os.environ['HF_HOME'] = '/tmp/hf-cache'\n",
|
| 118 |
"os.environ['HUGGINGFACE_HUB_CACHE'] = '/tmp/hf-cache'\n",
|
| 119 |
"os.environ['TRANSFORMERS_CACHE'] = '/tmp/hf-cache'\n",
|
| 120 |
"pathlib.Path('/tmp/hf-cache').mkdir(parents=True, exist_ok=True)\n",
|
| 121 |
"\n",
|
| 122 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
"try:\n",
|
| 124 |
" from kaggle_secrets import UserSecretsClient\n",
|
| 125 |
" os.environ['HF_TOKEN'] = UserSecretsClient().get_secret('HF_TOKEN')\n",
|
| 126 |
" print('HF_TOKEN attached from Kaggle Secrets')\n",
|
| 127 |
"except Exception:\n",
|
| 128 |
-
" print('No HF_TOKEN
|
| 129 |
"\n",
|
| 130 |
-
"
|
| 131 |
-
"
|
| 132 |
-
"
|
| 133 |
-
"
|
| 134 |
-
"
|
| 135 |
-
"
|
| 136 |
-
"
|
| 137 |
-
"
|
| 138 |
-
"
|
| 139 |
-
"
|
| 140 |
-
"
|
| 141 |
-
"
|
| 142 |
-
"
|
| 143 |
-
]
|
| 144 |
-
},
|
| 145 |
-
{
|
| 146 |
-
"cell_type": "markdown",
|
| 147 |
-
"metadata": {},
|
| 148 |
-
"source": [
|
| 149 |
-
"## 4. Clone the repo (public GitHub) \u2014 always pull latest"
|
| 150 |
]
|
| 151 |
},
|
| 152 |
{
|
| 153 |
"cell_type": "code",
|
| 154 |
-
"metadata": {},
|
| 155 |
"execution_count": null,
|
|
|
|
| 156 |
"outputs": [],
|
| 157 |
"source": [
|
|
|
|
| 158 |
"import os, subprocess, pathlib, shutil\n",
|
| 159 |
"WORK = '/kaggle/working/incident-commander'\n",
|
| 160 |
-
"# IMPORTANT: chdir OUT of WORK before deleting it, otherwise git clone fails\n",
|
| 161 |
-
"# with \"Unable to read current working directory\" on a re-run.\n",
|
| 162 |
"os.chdir('/kaggle/working')\n",
|
| 163 |
-
"
|
| 164 |
-
"if p.exists():\n",
|
| 165 |
-
" # Wipe any stale clone from a previous session/run so we always get the\n",
|
| 166 |
-
" # newest scripts/run_training.py + colab/train_lib.py from main.\n",
|
| 167 |
" shutil.rmtree(WORK, ignore_errors=True)\n",
|
| 168 |
"subprocess.run(['git', 'clone', '--depth', '1',\n",
|
| 169 |
-
" 'https://github.com/r1cksync/meta-rl-hack.git', WORK],
|
|
|
|
| 170 |
"os.chdir(WORK)\n",
|
| 171 |
-
"# Show the commit we are running so it is obvious in the logs.\n",
|
| 172 |
"subprocess.run(['git', '-C', WORK, 'log', '-1', '--oneline'], check=False)\n",
|
| 173 |
"print('cwd =', os.getcwd())"
|
| 174 |
]
|
| 175 |
},
|
| 176 |
-
{
|
| 177 |
-
"cell_type": "markdown",
|
| 178 |
-
"metadata": {},
|
| 179 |
-
"source": [
|
| 180 |
-
"## 5. Configure run (shard, paths, env vars)"
|
| 181 |
-
]
|
| 182 |
-
},
|
| 183 |
{
|
| 184 |
"cell_type": "code",
|
| 185 |
-
"metadata": {},
|
| 186 |
"execution_count": null,
|
|
|
|
| 187 |
"outputs": [],
|
| 188 |
"source": [
|
|
|
|
| 189 |
"import os\n",
|
| 190 |
-
"\n",
|
| 191 |
"os.environ['INCIDENT_COMMANDER_MOCK'] = 'true'\n",
|
| 192 |
"os.environ['IC_ACTOR_MODEL'] = ACTOR_PATH\n",
|
| 193 |
-
"os.environ['IC_CRITIC_PROVIDER'] = 'local'
|
| 194 |
"os.environ['IC_CRITIC_MODEL'] = CRITIC_PATH\n",
|
| 195 |
-
"os.environ['IC_TASK_MODE'] = 'all'
|
| 196 |
"os.environ['IC_TASK_SHARDS'] = '3'\n",
|
| 197 |
"os.environ['IC_TASK_SHARD'] = '1'\n",
|
| 198 |
-
"os.environ['IC_TOTAL_UPDATES'] = '60'
|
| 199 |
"os.environ['IC_ROLLOUTS'] = '3'\n",
|
| 200 |
"os.environ['IC_MAX_STEPS'] = '12'\n",
|
| 201 |
"os.environ['IC_CKPT_EVERY'] = '15'\n",
|
| 202 |
"os.environ['IC_RUN_NAME'] = 'kaggle2'\n",
|
| 203 |
-
"\n",
|
| 204 |
"print('actor :', os.environ['IC_ACTOR_MODEL'])\n",
|
| 205 |
"print('critic:', os.environ['IC_CRITIC_MODEL'])\n",
|
| 206 |
"print('shard :', os.environ['IC_TASK_SHARD'], '/', os.environ['IC_TASK_SHARDS'])"
|
| 207 |
]
|
| 208 |
},
|
| 209 |
-
{
|
| 210 |
-
"cell_type": "markdown",
|
| 211 |
-
"metadata": {},
|
| 212 |
-
"source": [
|
| 213 |
-
"## 6. Train"
|
| 214 |
-
]
|
| 215 |
-
},
|
| 216 |
{
|
| 217 |
"cell_type": "code",
|
| 218 |
-
"metadata": {},
|
| 219 |
"execution_count": null,
|
|
|
|
| 220 |
"outputs": [],
|
| 221 |
"source": [
|
| 222 |
-
"#
|
| 223 |
-
"# to stdout. Kaggle truncates very long outputs \u2014 adapter checkpoints are\n",
|
| 224 |
-
"# always written to /kaggle/working/incident-commander/colab/logs/ regardless.\n",
|
| 225 |
"import subprocess, sys\n",
|
| 226 |
-
"result = subprocess.run([sys.executable, 'scripts/run_training.py'],\n",
|
| 227 |
-
" check=False)\n",
|
| 228 |
"print('exit code:', result.returncode)"
|
| 229 |
]
|
| 230 |
},
|
| 231 |
-
{
|
| 232 |
-
"cell_type": "markdown",
|
| 233 |
-
"metadata": {},
|
| 234 |
-
"source": [
|
| 235 |
-
"## 7. Package outputs for download"
|
| 236 |
-
]
|
| 237 |
-
},
|
| 238 |
{
|
| 239 |
"cell_type": "code",
|
| 240 |
-
"metadata": {},
|
| 241 |
"execution_count": null,
|
|
|
|
| 242 |
"outputs": [],
|
| 243 |
"source": [
|
|
|
|
| 244 |
"import shutil, glob, pathlib\n",
|
| 245 |
-
"\n",
|
| 246 |
"LOGS = pathlib.Path('colab/logs')\n",
|
| 247 |
"finals = sorted(LOGS.glob('adapter_kaggle2_final'))\n",
|
| 248 |
"ckpts = sorted(LOGS.glob('adapter_kaggle2_u*'))\n",
|
| 249 |
-
"keep
|
| 250 |
-
"assert keep, 'No adapter directories found
|
| 251 |
"src = keep[-1]\n",
|
| 252 |
"print('packaging', src)\n",
|
| 253 |
-
"\n",
|
| 254 |
"dst = pathlib.Path('/kaggle/working/adapter_kaggle2.zip')\n",
|
| 255 |
"shutil.make_archive(str(dst.with_suffix('')), 'zip', root_dir=src)\n",
|
| 256 |
"print('zipped to', dst, 'size:', dst.stat().st_size, 'bytes')\n",
|
| 257 |
-
"\n",
|
| 258 |
-
"# Also copy the JSON training log for plotting on your laptop.\n",
|
| 259 |
"for j in glob.glob('colab/logs/training_kaggle2*.json'):\n",
|
| 260 |
" shutil.copy(j, '/kaggle/working/')\n",
|
| 261 |
"print('files in /kaggle/working/:')\n",
|
| 262 |
"for f in sorted(pathlib.Path('/kaggle/working/').iterdir()):\n",
|
| 263 |
-
" if f.name == 'hf-cache':
|
|
|
|
| 264 |
" print(' ', f.name, f.stat().st_size if f.is_file() else '<dir>')"
|
| 265 |
]
|
| 266 |
},
|
|
@@ -270,9 +212,8 @@
|
|
| 270 |
"source": [
|
| 271 |
"## Done\n",
|
| 272 |
"\n",
|
| 273 |
-
"Download `adapter_kaggle2.zip` from the **Output** tab on the\n",
|
| 274 |
-
"
|
| 275 |
-
"laptop run:\n",
|
| 276 |
"\n",
|
| 277 |
"```powershell\n",
|
| 278 |
"python scripts/merge_lora_adapters.py `\n",
|
|
@@ -280,8 +221,7 @@
|
|
| 280 |
" --output ./adapter_merged\n",
|
| 281 |
"```\n",
|
| 282 |
"\n",
|
| 283 |
-
"The merged adapter loads with the standard `peft` API on top of
|
| 284 |
-
"`microsoft/Phi-3.5-mini-instruct`.\n"
|
| 285 |
]
|
| 286 |
}
|
| 287 |
],
|
|
|
|
| 4 |
"cell_type": "markdown",
|
| 5 |
"metadata": {},
|
| 6 |
"source": [
|
| 7 |
+
"# IncidentCommander RL — Kaggle shard 2 / 3\n",
|
| 8 |
"\n",
|
| 9 |
+
"**Workload:** every 3rd task starting at index **1** (~127 of 381 scenarios).\n",
|
| 10 |
+
"Trains a LoRA on **Phi-3.5-mini-instruct** using a local **DeepSeek-R1-0528-Qwen3-8B** critic.\n",
|
|
|
|
|
|
|
| 11 |
"\n",
|
| 12 |
+
"## REQUIRED — attach these 2 Kaggle Models before running\n",
|
| 13 |
+
"Right sidebar → `+ Add Input` → `Models` tab:\n",
|
| 14 |
+
"1. `Microsoft / phi-3` → framework `PyTorch` → variation `phi-3.5-mini-instruct` → version `2`\n",
|
| 15 |
+
"2. `deepseek-ai / deepseek-r1-0528` → framework `Transformers` → variation `deepseek-r1-0528-qwen3-8b` → version `1`\n",
|
| 16 |
"\n",
|
| 17 |
+
"## Required notebook settings\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
"- Accelerator: `GPU T4 x2` or `GPU P100`\n",
|
| 19 |
+
"- Internet: `On`\n",
|
| 20 |
"- Persistence: `Files only`\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
"\n",
|
| 22 |
+
"**Output:** `/kaggle/working/adapter_kaggle2.zip` — download from the sidebar after the run finishes."
|
|
|
|
|
|
|
| 23 |
]
|
| 24 |
},
|
| 25 |
{
|
| 26 |
+
"cell_type": "code",
|
| 27 |
+
"execution_count": null,
|
| 28 |
"metadata": {},
|
| 29 |
+
"outputs": [],
|
| 30 |
"source": [
|
| 31 |
+
"# === 1. Install deps + unsloth (best-effort) ===\n",
|
| 32 |
+
"# Qwen3 (in DeepSeek-R1-0528) needs transformers >= 4.51. Unsloth speeds up\n",
|
| 33 |
+
"# the actor ~2x; if its install fails on this Kaggle image we fall back to\n",
|
| 34 |
+
"# pure HF transformers automatically (train_lib.py handles both paths).\n",
|
| 35 |
+
"import subprocess, sys\n",
|
| 36 |
+
"\n",
|
| 37 |
+
"def pip(*args):\n",
|
| 38 |
+
" return subprocess.run([sys.executable, '-m', 'pip', 'install', '-q', *args],\n",
|
| 39 |
+
" check=False).returncode\n",
|
| 40 |
+
"\n",
|
| 41 |
+
"rc = pip('-U', 'unsloth')\n",
|
| 42 |
+
"print('[install] unsloth rc =', rc, '(non-zero is fine, HF fallback works)')\n",
|
| 43 |
+
"\n",
|
| 44 |
+
"pip('-U',\n",
|
| 45 |
+
" 'transformers>=4.51,<4.55',\n",
|
| 46 |
+
" 'peft>=0.13,<0.16',\n",
|
| 47 |
+
" 'accelerate>=1.1,<1.5',\n",
|
| 48 |
+
" 'bitsandbytes>=0.45.5',\n",
|
| 49 |
+
" 'huggingface_hub>=0.25,<1.0',\n",
|
| 50 |
+
" 'pydantic>=2,<3',\n",
|
| 51 |
+
" 'datasets', 'sentencepiece', 'protobuf', 'safetensors')\n",
|
| 52 |
+
"print('[install] pinned stack done')"
|
| 53 |
]
|
| 54 |
},
|
| 55 |
{
|
| 56 |
"cell_type": "code",
|
|
|
|
| 57 |
"execution_count": null,
|
| 58 |
+
"metadata": {},
|
| 59 |
"outputs": [],
|
| 60 |
"source": [
|
| 61 |
+
"# === 2. GPU sanity ===\n",
|
| 62 |
"import subprocess\n",
|
| 63 |
"print('--- GPU ---')\n",
|
| 64 |
"subprocess.run(['nvidia-smi', '-L'], check=False)\n",
|
| 65 |
"import torch\n",
|
| 66 |
+
"print('CUDA OK?', torch.cuda.is_available(),\n",
|
| 67 |
+
" '| device:', torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'none')"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
]
|
| 69 |
},
|
| 70 |
{
|
| 71 |
"cell_type": "code",
|
|
|
|
| 72 |
"execution_count": null,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
"metadata": {},
|
|
|
|
| 74 |
"outputs": [],
|
| 75 |
"source": [
|
| 76 |
+
"# === 3. Verify attached Kaggle Models + suppress warning spam ===\n",
|
| 77 |
+
"import os, pathlib, shutil, warnings, logging\n",
|
| 78 |
"\n",
|
| 79 |
"ACTOR_PATH = '/kaggle/input/models/Microsoft/phi-3/pytorch/phi-3.5-mini-instruct/2'\n",
|
| 80 |
"CRITIC_PATH = '/kaggle/input/models/deepseek-ai/deepseek-r1-0528/transformers/deepseek-r1-0528-qwen3-8b/1'\n",
|
|
|
|
| 82 |
"def verify(path, label):\n",
|
| 83 |
" p = pathlib.Path(path)\n",
|
| 84 |
" if not p.exists():\n",
|
| 85 |
+
" raise SystemExit(f'{label} not found at {path}. Attach the matching Kaggle Model.')\n",
|
| 86 |
+
" if not (any(p.glob('*.safetensors')) or any(p.glob('*.bin'))):\n",
|
| 87 |
+
" raise SystemExit(f'{label} found at {path} but no weight files inside.')\n",
|
| 88 |
+
" print(f'{label}: OK -> {path}')\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
"\n",
|
| 90 |
"verify(ACTOR_PATH, 'actor (Phi-3.5-mini-instruct)')\n",
|
| 91 |
"verify(CRITIC_PATH, 'critic (DeepSeek-R1-0528-Qwen3-8B)')\n",
|
| 92 |
"\n",
|
|
|
|
|
|
|
| 93 |
"os.environ['HF_HOME'] = '/tmp/hf-cache'\n",
|
| 94 |
"os.environ['HUGGINGFACE_HUB_CACHE'] = '/tmp/hf-cache'\n",
|
| 95 |
"os.environ['TRANSFORMERS_CACHE'] = '/tmp/hf-cache'\n",
|
| 96 |
"pathlib.Path('/tmp/hf-cache').mkdir(parents=True, exist_ok=True)\n",
|
| 97 |
"\n",
|
| 98 |
+
"modules_dir = pathlib.Path('/tmp/hf-cache/modules')\n",
|
| 99 |
+
"if modules_dir.exists():\n",
|
| 100 |
+
" shutil.rmtree(modules_dir, ignore_errors=True)\n",
|
| 101 |
+
" print('cleared cached custom modeling code at', modules_dir)\n",
|
| 102 |
+
"\n",
|
| 103 |
"try:\n",
|
| 104 |
" from kaggle_secrets import UserSecretsClient\n",
|
| 105 |
" os.environ['HF_TOKEN'] = UserSecretsClient().get_secret('HF_TOKEN')\n",
|
| 106 |
" print('HF_TOKEN attached from Kaggle Secrets')\n",
|
| 107 |
"except Exception:\n",
|
| 108 |
+
" print('No HF_TOKEN -- training runs fully offline (that is fine).')\n",
|
| 109 |
"\n",
|
| 110 |
+
"for pat in ('.*Caching is incompatible with gradient checkpointing.*',\n",
|
| 111 |
+
" '.*None of the inputs have requires_grad=True.*',\n",
|
| 112 |
+
" '.*use_reentrant parameter should be passed explicitly.*',\n",
|
| 113 |
+
" \".*AccumulateGrad node's stream does not match.*\"):\n",
|
| 114 |
+
" warnings.filterwarnings('ignore', message=pat)\n",
|
| 115 |
+
"\n",
|
| 116 |
+
"class _PhiFilter(logging.Filter):\n",
|
| 117 |
+
" def filter(self, r):\n",
|
| 118 |
+
" return 'Caching is incompatible' not in r.getMessage()\n",
|
| 119 |
+
"for n in ('transformers', 'transformers.models.phi3.modeling_phi3',\n",
|
| 120 |
+
" 'torch.utils.checkpoint'):\n",
|
| 121 |
+
" logging.getLogger(n).addFilter(_PhiFilter())\n",
|
| 122 |
+
"print('warning filters installed')"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
]
|
| 124 |
},
|
| 125 |
{
|
| 126 |
"cell_type": "code",
|
|
|
|
| 127 |
"execution_count": null,
|
| 128 |
+
"metadata": {},
|
| 129 |
"outputs": [],
|
| 130 |
"source": [
|
| 131 |
+
"# === 4. Clone the repo (fresh every run, prints commit hash) ===\n",
|
| 132 |
"import os, subprocess, pathlib, shutil\n",
|
| 133 |
"WORK = '/kaggle/working/incident-commander'\n",
|
|
|
|
|
|
|
| 134 |
"os.chdir('/kaggle/working')\n",
|
| 135 |
+
"if pathlib.Path(WORK).exists():\n",
|
|
|
|
|
|
|
|
|
|
| 136 |
" shutil.rmtree(WORK, ignore_errors=True)\n",
|
| 137 |
"subprocess.run(['git', 'clone', '--depth', '1',\n",
|
| 138 |
+
" 'https://github.com/r1cksync/meta-rl-hack.git', WORK],\n",
|
| 139 |
+
" check=True)\n",
|
| 140 |
"os.chdir(WORK)\n",
|
|
|
|
| 141 |
"subprocess.run(['git', '-C', WORK, 'log', '-1', '--oneline'], check=False)\n",
|
| 142 |
"print('cwd =', os.getcwd())"
|
| 143 |
]
|
| 144 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
{
|
| 146 |
"cell_type": "code",
|
|
|
|
| 147 |
"execution_count": null,
|
| 148 |
+
"metadata": {},
|
| 149 |
"outputs": [],
|
| 150 |
"source": [
|
| 151 |
+
"# === 5. Configure run (shard 2 / 3) ===\n",
|
| 152 |
"import os\n",
|
|
|
|
| 153 |
"os.environ['INCIDENT_COMMANDER_MOCK'] = 'true'\n",
|
| 154 |
"os.environ['IC_ACTOR_MODEL'] = ACTOR_PATH\n",
|
| 155 |
+
"os.environ['IC_CRITIC_PROVIDER'] = 'local'\n",
|
| 156 |
"os.environ['IC_CRITIC_MODEL'] = CRITIC_PATH\n",
|
| 157 |
+
"os.environ['IC_TASK_MODE'] = 'all'\n",
|
| 158 |
"os.environ['IC_TASK_SHARDS'] = '3'\n",
|
| 159 |
"os.environ['IC_TASK_SHARD'] = '1'\n",
|
| 160 |
+
"os.environ['IC_TOTAL_UPDATES'] = '60'\n",
|
| 161 |
"os.environ['IC_ROLLOUTS'] = '3'\n",
|
| 162 |
"os.environ['IC_MAX_STEPS'] = '12'\n",
|
| 163 |
"os.environ['IC_CKPT_EVERY'] = '15'\n",
|
| 164 |
"os.environ['IC_RUN_NAME'] = 'kaggle2'\n",
|
|
|
|
| 165 |
"print('actor :', os.environ['IC_ACTOR_MODEL'])\n",
|
| 166 |
"print('critic:', os.environ['IC_CRITIC_MODEL'])\n",
|
| 167 |
"print('shard :', os.environ['IC_TASK_SHARD'], '/', os.environ['IC_TASK_SHARDS'])"
|
| 168 |
]
|
| 169 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
{
|
| 171 |
"cell_type": "code",
|
|
|
|
| 172 |
"execution_count": null,
|
| 173 |
+
"metadata": {},
|
| 174 |
"outputs": [],
|
| 175 |
"source": [
|
| 176 |
+
"# === 6. Train ===\n",
|
|
|
|
|
|
|
| 177 |
"import subprocess, sys\n",
|
| 178 |
+
"result = subprocess.run([sys.executable, 'scripts/run_training.py'], check=False)\n",
|
|
|
|
| 179 |
"print('exit code:', result.returncode)"
|
| 180 |
]
|
| 181 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 182 |
{
|
| 183 |
"cell_type": "code",
|
|
|
|
| 184 |
"execution_count": null,
|
| 185 |
+
"metadata": {},
|
| 186 |
"outputs": [],
|
| 187 |
"source": [
|
| 188 |
+
"# === 7. Package outputs for download ===\n",
|
| 189 |
"import shutil, glob, pathlib\n",
|
|
|
|
| 190 |
"LOGS = pathlib.Path('colab/logs')\n",
|
| 191 |
"finals = sorted(LOGS.glob('adapter_kaggle2_final'))\n",
|
| 192 |
"ckpts = sorted(LOGS.glob('adapter_kaggle2_u*'))\n",
|
| 193 |
+
"keep = (finals or ckpts)\n",
|
| 194 |
+
"assert keep, 'No adapter directories found -- check the training cell output.'\n",
|
| 195 |
"src = keep[-1]\n",
|
| 196 |
"print('packaging', src)\n",
|
|
|
|
| 197 |
"dst = pathlib.Path('/kaggle/working/adapter_kaggle2.zip')\n",
|
| 198 |
"shutil.make_archive(str(dst.with_suffix('')), 'zip', root_dir=src)\n",
|
| 199 |
"print('zipped to', dst, 'size:', dst.stat().st_size, 'bytes')\n",
|
|
|
|
|
|
|
| 200 |
"for j in glob.glob('colab/logs/training_kaggle2*.json'):\n",
|
| 201 |
" shutil.copy(j, '/kaggle/working/')\n",
|
| 202 |
"print('files in /kaggle/working/:')\n",
|
| 203 |
"for f in sorted(pathlib.Path('/kaggle/working/').iterdir()):\n",
|
| 204 |
+
" if f.name == 'hf-cache':\n",
|
| 205 |
+
" continue\n",
|
| 206 |
" print(' ', f.name, f.stat().st_size if f.is_file() else '<dir>')"
|
| 207 |
]
|
| 208 |
},
|
|
|
|
| 212 |
"source": [
|
| 213 |
"## Done\n",
|
| 214 |
"\n",
|
| 215 |
+
"Download `adapter_kaggle2.zip` from the **Output** tab on the right.\n",
|
| 216 |
+
"Run shard 2 and shard 3 in parallel browser tabs, then on your laptop:\n",
|
|
|
|
| 217 |
"\n",
|
| 218 |
"```powershell\n",
|
| 219 |
"python scripts/merge_lora_adapters.py `\n",
|
|
|
|
| 221 |
" --output ./adapter_merged\n",
|
| 222 |
"```\n",
|
| 223 |
"\n",
|
| 224 |
+
"The merged adapter loads with the standard `peft` API on top of `microsoft/Phi-3.5-mini-instruct`."
|
|
|
|
| 225 |
]
|
| 226 |
}
|
| 227 |
],
|
kaggle/kaggle_train_shard3.ipynb
CHANGED
|
@@ -4,95 +4,77 @@
|
|
| 4 |
"cell_type": "markdown",
|
| 5 |
"metadata": {},
|
| 6 |
"source": [
|
| 7 |
-
"# IncidentCommander RL
|
| 8 |
"\n",
|
| 9 |
-
"**Workload:** every 3rd task starting at index 2\n",
|
| 10 |
-
"
|
| 11 |
-
"**deepseek-ai/DeepSeek-R1-0528-Qwen3-8B** critic \u2014 both attached as Kaggle Models so they live in\n",
|
| 12 |
-
"the read-only `/kaggle/input/` mount and DO NOT eat the 20 GB working quota.\n",
|
| 13 |
"\n",
|
| 14 |
-
"
|
| 15 |
-
"`+ Add Input`
|
| 16 |
-
"1.
|
| 17 |
-
"2.
|
| 18 |
"\n",
|
| 19 |
-
"
|
| 20 |
-
"- `/kaggle/input/models/Microsoft/phi-3/pytorch/phi-3.5-mini-instruct/2`\n",
|
| 21 |
-
"- `/kaggle/input/models/deepseek-ai/deepseek-r1-0528/transformers/deepseek-r1-0528-qwen3-8b/1`\n",
|
| 22 |
-
"\n",
|
| 23 |
-
"**Required notebook settings** (right-hand sidebar):\n",
|
| 24 |
"- Accelerator: `GPU T4 x2` or `GPU P100`\n",
|
|
|
|
| 25 |
"- Persistence: `Files only`\n",
|
| 26 |
-
"- Internet: `On` (for `git clone` and optional HF Hub upload)\n",
|
| 27 |
-
"\n",
|
| 28 |
-
"**Optional** (only if you want intermediate checkpoint upload to your HF\n",
|
| 29 |
-
"repo): Add-ons \u2192 Secrets \u2192 add `HF_TOKEN` and toggle it on.\n",
|
| 30 |
"\n",
|
| 31 |
-
"**Output:** `/kaggle/working/adapter_kaggle3.zip`
|
| 32 |
-
"the sidebar after the run finishes. Combine all 3 with\n",
|
| 33 |
-
"`scripts/merge_lora_adapters.py` on your laptop.\n"
|
| 34 |
]
|
| 35 |
},
|
| 36 |
{
|
| 37 |
-
"cell_type": "
|
|
|
|
| 38 |
"metadata": {},
|
|
|
|
| 39 |
"source": [
|
| 40 |
-
"#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
]
|
| 42 |
},
|
| 43 |
{
|
| 44 |
"cell_type": "code",
|
| 45 |
-
"metadata": {},
|
| 46 |
"execution_count": null,
|
|
|
|
| 47 |
"outputs": [],
|
| 48 |
"source": [
|
|
|
|
| 49 |
"import subprocess\n",
|
| 50 |
"print('--- GPU ---')\n",
|
| 51 |
"subprocess.run(['nvidia-smi', '-L'], check=False)\n",
|
| 52 |
"import torch\n",
|
| 53 |
-
"print('CUDA OK?', torch.cuda.is_available(),
|
| 54 |
-
" torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'none')"
|
| 55 |
-
]
|
| 56 |
-
},
|
| 57 |
-
{
|
| 58 |
-
"cell_type": "markdown",
|
| 59 |
-
"metadata": {},
|
| 60 |
-
"source": [
|
| 61 |
-
"## 2. Install deps (Kaggle has torch/transformers preinstalled \u2014 we just pin compatible versions)"
|
| 62 |
]
|
| 63 |
},
|
| 64 |
{
|
| 65 |
"cell_type": "code",
|
| 66 |
-
"metadata": {},
|
| 67 |
"execution_count": null,
|
| 68 |
-
"outputs": [],
|
| 69 |
-
"source": [
|
| 70 |
-
"# Qwen3 architecture (used inside DeepSeek-R1-0528-Qwen3-8B) requires\n",
|
| 71 |
-
"# transformers >= 4.51. Bump the whole stack to a known-compatible set.\n",
|
| 72 |
-
"%pip install -q -U \\\n",
|
| 73 |
-
" \"transformers>=4.51,<4.55\" \\\n",
|
| 74 |
-
" \"peft>=0.13,<0.16\" \\\n",
|
| 75 |
-
" \"accelerate>=1.1,<1.5\" \\\n",
|
| 76 |
-
" \"bitsandbytes>=0.45.5\" \\\n",
|
| 77 |
-
" \"huggingface_hub>=0.25,<1.0\" \\\n",
|
| 78 |
-
" \"pydantic>=2,<3\" \\\n",
|
| 79 |
-
" \"datasets\" \"sentencepiece\" \"protobuf\" \"safetensors\""
|
| 80 |
-
]
|
| 81 |
-
},
|
| 82 |
-
{
|
| 83 |
-
"cell_type": "markdown",
|
| 84 |
-
"metadata": {},
|
| 85 |
-
"source": [
|
| 86 |
-
"## 3. Resolve attached Kaggle Models (read-only, no download)"
|
| 87 |
-
]
|
| 88 |
-
},
|
| 89 |
-
{
|
| 90 |
-
"cell_type": "code",
|
| 91 |
"metadata": {},
|
| 92 |
-
"execution_count": null,
|
| 93 |
"outputs": [],
|
| 94 |
"source": [
|
| 95 |
-
"
|
|
|
|
| 96 |
"\n",
|
| 97 |
"ACTOR_PATH = '/kaggle/input/models/Microsoft/phi-3/pytorch/phi-3.5-mini-instruct/2'\n",
|
| 98 |
"CRITIC_PATH = '/kaggle/input/models/deepseek-ai/deepseek-r1-0528/transformers/deepseek-r1-0528-qwen3-8b/1'\n",
|
|
@@ -100,167 +82,127 @@
|
|
| 100 |
"def verify(path, label):\n",
|
| 101 |
" p = pathlib.Path(path)\n",
|
| 102 |
" if not p.exists():\n",
|
| 103 |
-
" raise SystemExit(\n",
|
| 104 |
-
"
|
| 105 |
-
"
|
| 106 |
-
"
|
| 107 |
-
" has_weights = any(p.glob('*.safetensors')) or any(p.glob('*.bin'))\n",
|
| 108 |
-
" if not has_weights:\n",
|
| 109 |
-
" raise SystemExit(f'{label} found at {path} but no *.safetensors / *.bin inside.')\n",
|
| 110 |
-
" print(f'{label}: OK \u2192 {path}')\n",
|
| 111 |
"\n",
|
| 112 |
"verify(ACTOR_PATH, 'actor (Phi-3.5-mini-instruct)')\n",
|
| 113 |
"verify(CRITIC_PATH, 'critic (DeepSeek-R1-0528-Qwen3-8B)')\n",
|
| 114 |
"\n",
|
| 115 |
-
"# Push HF Hub cache out of /kaggle/working so an accidental snapshot_download\n",
|
| 116 |
-
"# (e.g. by a tokenizer) writes to /tmp instead of eating the 20 GB quota.\n",
|
| 117 |
"os.environ['HF_HOME'] = '/tmp/hf-cache'\n",
|
| 118 |
"os.environ['HUGGINGFACE_HUB_CACHE'] = '/tmp/hf-cache'\n",
|
| 119 |
"os.environ['TRANSFORMERS_CACHE'] = '/tmp/hf-cache'\n",
|
| 120 |
"pathlib.Path('/tmp/hf-cache').mkdir(parents=True, exist_ok=True)\n",
|
| 121 |
"\n",
|
| 122 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
"try:\n",
|
| 124 |
" from kaggle_secrets import UserSecretsClient\n",
|
| 125 |
" os.environ['HF_TOKEN'] = UserSecretsClient().get_secret('HF_TOKEN')\n",
|
| 126 |
" print('HF_TOKEN attached from Kaggle Secrets')\n",
|
| 127 |
"except Exception:\n",
|
| 128 |
-
" print('No HF_TOKEN
|
| 129 |
"\n",
|
| 130 |
-
"
|
| 131 |
-
"
|
| 132 |
-
"
|
| 133 |
-
"
|
| 134 |
-
"
|
| 135 |
-
"
|
| 136 |
-
"
|
| 137 |
-
"
|
| 138 |
-
"
|
| 139 |
-
"
|
| 140 |
-
"
|
| 141 |
-
"
|
| 142 |
-
"
|
| 143 |
-
]
|
| 144 |
-
},
|
| 145 |
-
{
|
| 146 |
-
"cell_type": "markdown",
|
| 147 |
-
"metadata": {},
|
| 148 |
-
"source": [
|
| 149 |
-
"## 4. Clone the repo (public GitHub) \u2014 always pull latest"
|
| 150 |
]
|
| 151 |
},
|
| 152 |
{
|
| 153 |
"cell_type": "code",
|
| 154 |
-
"metadata": {},
|
| 155 |
"execution_count": null,
|
|
|
|
| 156 |
"outputs": [],
|
| 157 |
"source": [
|
|
|
|
| 158 |
"import os, subprocess, pathlib, shutil\n",
|
| 159 |
"WORK = '/kaggle/working/incident-commander'\n",
|
| 160 |
-
"# IMPORTANT: chdir OUT of WORK before deleting it, otherwise git clone fails\n",
|
| 161 |
-
"# with \"Unable to read current working directory\" on a re-run.\n",
|
| 162 |
"os.chdir('/kaggle/working')\n",
|
| 163 |
-
"
|
| 164 |
-
"if p.exists():\n",
|
| 165 |
-
" # Wipe any stale clone from a previous session/run so we always get the\n",
|
| 166 |
-
" # newest scripts/run_training.py + colab/train_lib.py from main.\n",
|
| 167 |
" shutil.rmtree(WORK, ignore_errors=True)\n",
|
| 168 |
"subprocess.run(['git', 'clone', '--depth', '1',\n",
|
| 169 |
-
" 'https://github.com/r1cksync/meta-rl-hack.git', WORK],
|
|
|
|
| 170 |
"os.chdir(WORK)\n",
|
| 171 |
-
"# Show the commit we are running so it is obvious in the logs.\n",
|
| 172 |
"subprocess.run(['git', '-C', WORK, 'log', '-1', '--oneline'], check=False)\n",
|
| 173 |
"print('cwd =', os.getcwd())"
|
| 174 |
]
|
| 175 |
},
|
| 176 |
-
{
|
| 177 |
-
"cell_type": "markdown",
|
| 178 |
-
"metadata": {},
|
| 179 |
-
"source": [
|
| 180 |
-
"## 5. Configure run (shard, paths, env vars)"
|
| 181 |
-
]
|
| 182 |
-
},
|
| 183 |
{
|
| 184 |
"cell_type": "code",
|
| 185 |
-
"metadata": {},
|
| 186 |
"execution_count": null,
|
|
|
|
| 187 |
"outputs": [],
|
| 188 |
"source": [
|
|
|
|
| 189 |
"import os\n",
|
| 190 |
-
"\n",
|
| 191 |
"os.environ['INCIDENT_COMMANDER_MOCK'] = 'true'\n",
|
| 192 |
"os.environ['IC_ACTOR_MODEL'] = ACTOR_PATH\n",
|
| 193 |
-
"os.environ['IC_CRITIC_PROVIDER'] = 'local'
|
| 194 |
"os.environ['IC_CRITIC_MODEL'] = CRITIC_PATH\n",
|
| 195 |
-
"os.environ['IC_TASK_MODE'] = 'all'
|
| 196 |
"os.environ['IC_TASK_SHARDS'] = '3'\n",
|
| 197 |
"os.environ['IC_TASK_SHARD'] = '2'\n",
|
| 198 |
-
"os.environ['IC_TOTAL_UPDATES'] = '60'
|
| 199 |
"os.environ['IC_ROLLOUTS'] = '3'\n",
|
| 200 |
"os.environ['IC_MAX_STEPS'] = '12'\n",
|
| 201 |
"os.environ['IC_CKPT_EVERY'] = '15'\n",
|
| 202 |
"os.environ['IC_RUN_NAME'] = 'kaggle3'\n",
|
| 203 |
-
"\n",
|
| 204 |
"print('actor :', os.environ['IC_ACTOR_MODEL'])\n",
|
| 205 |
"print('critic:', os.environ['IC_CRITIC_MODEL'])\n",
|
| 206 |
"print('shard :', os.environ['IC_TASK_SHARD'], '/', os.environ['IC_TASK_SHARDS'])"
|
| 207 |
]
|
| 208 |
},
|
| 209 |
-
{
|
| 210 |
-
"cell_type": "markdown",
|
| 211 |
-
"metadata": {},
|
| 212 |
-
"source": [
|
| 213 |
-
"## 6. Train"
|
| 214 |
-
]
|
| 215 |
-
},
|
| 216 |
{
|
| 217 |
"cell_type": "code",
|
| 218 |
-
"metadata": {},
|
| 219 |
"execution_count": null,
|
|
|
|
| 220 |
"outputs": [],
|
| 221 |
"source": [
|
| 222 |
-
"#
|
| 223 |
-
"# to stdout. Kaggle truncates very long outputs \u2014 adapter checkpoints are\n",
|
| 224 |
-
"# always written to /kaggle/working/incident-commander/colab/logs/ regardless.\n",
|
| 225 |
"import subprocess, sys\n",
|
| 226 |
-
"result = subprocess.run([sys.executable, 'scripts/run_training.py'],\n",
|
| 227 |
-
" check=False)\n",
|
| 228 |
"print('exit code:', result.returncode)"
|
| 229 |
]
|
| 230 |
},
|
| 231 |
-
{
|
| 232 |
-
"cell_type": "markdown",
|
| 233 |
-
"metadata": {},
|
| 234 |
-
"source": [
|
| 235 |
-
"## 7. Package outputs for download"
|
| 236 |
-
]
|
| 237 |
-
},
|
| 238 |
{
|
| 239 |
"cell_type": "code",
|
| 240 |
-
"metadata": {},
|
| 241 |
"execution_count": null,
|
|
|
|
| 242 |
"outputs": [],
|
| 243 |
"source": [
|
|
|
|
| 244 |
"import shutil, glob, pathlib\n",
|
| 245 |
-
"\n",
|
| 246 |
"LOGS = pathlib.Path('colab/logs')\n",
|
| 247 |
"finals = sorted(LOGS.glob('adapter_kaggle3_final'))\n",
|
| 248 |
"ckpts = sorted(LOGS.glob('adapter_kaggle3_u*'))\n",
|
| 249 |
-
"keep
|
| 250 |
-
"assert keep, 'No adapter directories found
|
| 251 |
"src = keep[-1]\n",
|
| 252 |
"print('packaging', src)\n",
|
| 253 |
-
"\n",
|
| 254 |
"dst = pathlib.Path('/kaggle/working/adapter_kaggle3.zip')\n",
|
| 255 |
"shutil.make_archive(str(dst.with_suffix('')), 'zip', root_dir=src)\n",
|
| 256 |
"print('zipped to', dst, 'size:', dst.stat().st_size, 'bytes')\n",
|
| 257 |
-
"\n",
|
| 258 |
-
"# Also copy the JSON training log for plotting on your laptop.\n",
|
| 259 |
"for j in glob.glob('colab/logs/training_kaggle3*.json'):\n",
|
| 260 |
" shutil.copy(j, '/kaggle/working/')\n",
|
| 261 |
"print('files in /kaggle/working/:')\n",
|
| 262 |
"for f in sorted(pathlib.Path('/kaggle/working/').iterdir()):\n",
|
| 263 |
-
" if f.name == 'hf-cache':
|
|
|
|
| 264 |
" print(' ', f.name, f.stat().st_size if f.is_file() else '<dir>')"
|
| 265 |
]
|
| 266 |
},
|
|
@@ -270,9 +212,8 @@
|
|
| 270 |
"source": [
|
| 271 |
"## Done\n",
|
| 272 |
"\n",
|
| 273 |
-
"Download `adapter_kaggle3.zip` from the **Output** tab on the\n",
|
| 274 |
-
"
|
| 275 |
-
"laptop run:\n",
|
| 276 |
"\n",
|
| 277 |
"```powershell\n",
|
| 278 |
"python scripts/merge_lora_adapters.py `\n",
|
|
@@ -280,8 +221,7 @@
|
|
| 280 |
" --output ./adapter_merged\n",
|
| 281 |
"```\n",
|
| 282 |
"\n",
|
| 283 |
-
"The merged adapter loads with the standard `peft` API on top of
|
| 284 |
-
"`microsoft/Phi-3.5-mini-instruct`.\n"
|
| 285 |
]
|
| 286 |
}
|
| 287 |
],
|
|
|
|
| 4 |
"cell_type": "markdown",
|
| 5 |
"metadata": {},
|
| 6 |
"source": [
|
| 7 |
+
"# IncidentCommander RL — Kaggle shard 3 / 3\n",
|
| 8 |
"\n",
|
| 9 |
+
"**Workload:** every 3rd task starting at index **2** (~127 of 381 scenarios).\n",
|
| 10 |
+
"Trains a LoRA on **Phi-3.5-mini-instruct** using a local **DeepSeek-R1-0528-Qwen3-8B** critic.\n",
|
|
|
|
|
|
|
| 11 |
"\n",
|
| 12 |
+
"## REQUIRED — attach these 2 Kaggle Models before running\n",
|
| 13 |
+
"Right sidebar → `+ Add Input` → `Models` tab:\n",
|
| 14 |
+
"1. `Microsoft / phi-3` → framework `PyTorch` → variation `phi-3.5-mini-instruct` → version `2`\n",
|
| 15 |
+
"2. `deepseek-ai / deepseek-r1-0528` → framework `Transformers` → variation `deepseek-r1-0528-qwen3-8b` → version `1`\n",
|
| 16 |
"\n",
|
| 17 |
+
"## Required notebook settings\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
"- Accelerator: `GPU T4 x2` or `GPU P100`\n",
|
| 19 |
+
"- Internet: `On`\n",
|
| 20 |
"- Persistence: `Files only`\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
"\n",
|
| 22 |
+
"**Output:** `/kaggle/working/adapter_kaggle3.zip` — download from the sidebar after the run finishes."
|
|
|
|
|
|
|
| 23 |
]
|
| 24 |
},
|
| 25 |
{
|
| 26 |
+
"cell_type": "code",
|
| 27 |
+
"execution_count": null,
|
| 28 |
"metadata": {},
|
| 29 |
+
"outputs": [],
|
| 30 |
"source": [
|
| 31 |
+
"# === 1. Install deps + unsloth (best-effort) ===\n",
|
| 32 |
+
"# Qwen3 (in DeepSeek-R1-0528) needs transformers >= 4.51. Unsloth speeds up\n",
|
| 33 |
+
"# the actor ~2x; if its install fails on this Kaggle image we fall back to\n",
|
| 34 |
+
"# pure HF transformers automatically (train_lib.py handles both paths).\n",
|
| 35 |
+
"import subprocess, sys\n",
|
| 36 |
+
"\n",
|
| 37 |
+
"def pip(*args):\n",
|
| 38 |
+
" return subprocess.run([sys.executable, '-m', 'pip', 'install', '-q', *args],\n",
|
| 39 |
+
" check=False).returncode\n",
|
| 40 |
+
"\n",
|
| 41 |
+
"rc = pip('-U', 'unsloth')\n",
|
| 42 |
+
"print('[install] unsloth rc =', rc, '(non-zero is fine, HF fallback works)')\n",
|
| 43 |
+
"\n",
|
| 44 |
+
"pip('-U',\n",
|
| 45 |
+
" 'transformers>=4.51,<4.55',\n",
|
| 46 |
+
" 'peft>=0.13,<0.16',\n",
|
| 47 |
+
" 'accelerate>=1.1,<1.5',\n",
|
| 48 |
+
" 'bitsandbytes>=0.45.5',\n",
|
| 49 |
+
" 'huggingface_hub>=0.25,<1.0',\n",
|
| 50 |
+
" 'pydantic>=2,<3',\n",
|
| 51 |
+
" 'datasets', 'sentencepiece', 'protobuf', 'safetensors')\n",
|
| 52 |
+
"print('[install] pinned stack done')"
|
| 53 |
]
|
| 54 |
},
|
| 55 |
{
|
| 56 |
"cell_type": "code",
|
|
|
|
| 57 |
"execution_count": null,
|
| 58 |
+
"metadata": {},
|
| 59 |
"outputs": [],
|
| 60 |
"source": [
|
| 61 |
+
"# === 2. GPU sanity ===\n",
|
| 62 |
"import subprocess\n",
|
| 63 |
"print('--- GPU ---')\n",
|
| 64 |
"subprocess.run(['nvidia-smi', '-L'], check=False)\n",
|
| 65 |
"import torch\n",
|
| 66 |
+
"print('CUDA OK?', torch.cuda.is_available(),\n",
|
| 67 |
+
" '| device:', torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'none')"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
]
|
| 69 |
},
|
| 70 |
{
|
| 71 |
"cell_type": "code",
|
|
|
|
| 72 |
"execution_count": null,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
"metadata": {},
|
|
|
|
| 74 |
"outputs": [],
|
| 75 |
"source": [
|
| 76 |
+
"# === 3. Verify attached Kaggle Models + suppress warning spam ===\n",
|
| 77 |
+
"import os, pathlib, shutil, warnings, logging\n",
|
| 78 |
"\n",
|
| 79 |
"ACTOR_PATH = '/kaggle/input/models/Microsoft/phi-3/pytorch/phi-3.5-mini-instruct/2'\n",
|
| 80 |
"CRITIC_PATH = '/kaggle/input/models/deepseek-ai/deepseek-r1-0528/transformers/deepseek-r1-0528-qwen3-8b/1'\n",
|
|
|
|
| 82 |
"def verify(path, label):\n",
|
| 83 |
" p = pathlib.Path(path)\n",
|
| 84 |
" if not p.exists():\n",
|
| 85 |
+
" raise SystemExit(f'{label} not found at {path}. Attach the matching Kaggle Model.')\n",
|
| 86 |
+
" if not (any(p.glob('*.safetensors')) or any(p.glob('*.bin'))):\n",
|
| 87 |
+
" raise SystemExit(f'{label} found at {path} but no weight files inside.')\n",
|
| 88 |
+
" print(f'{label}: OK -> {path}')\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
"\n",
|
| 90 |
"verify(ACTOR_PATH, 'actor (Phi-3.5-mini-instruct)')\n",
|
| 91 |
"verify(CRITIC_PATH, 'critic (DeepSeek-R1-0528-Qwen3-8B)')\n",
|
| 92 |
"\n",
|
|
|
|
|
|
|
| 93 |
"os.environ['HF_HOME'] = '/tmp/hf-cache'\n",
|
| 94 |
"os.environ['HUGGINGFACE_HUB_CACHE'] = '/tmp/hf-cache'\n",
|
| 95 |
"os.environ['TRANSFORMERS_CACHE'] = '/tmp/hf-cache'\n",
|
| 96 |
"pathlib.Path('/tmp/hf-cache').mkdir(parents=True, exist_ok=True)\n",
|
| 97 |
"\n",
|
| 98 |
+
"modules_dir = pathlib.Path('/tmp/hf-cache/modules')\n",
|
| 99 |
+
"if modules_dir.exists():\n",
|
| 100 |
+
" shutil.rmtree(modules_dir, ignore_errors=True)\n",
|
| 101 |
+
" print('cleared cached custom modeling code at', modules_dir)\n",
|
| 102 |
+
"\n",
|
| 103 |
"try:\n",
|
| 104 |
" from kaggle_secrets import UserSecretsClient\n",
|
| 105 |
" os.environ['HF_TOKEN'] = UserSecretsClient().get_secret('HF_TOKEN')\n",
|
| 106 |
" print('HF_TOKEN attached from Kaggle Secrets')\n",
|
| 107 |
"except Exception:\n",
|
| 108 |
+
" print('No HF_TOKEN -- training runs fully offline (that is fine).')\n",
|
| 109 |
"\n",
|
| 110 |
+
"for pat in ('.*Caching is incompatible with gradient checkpointing.*',\n",
|
| 111 |
+
" '.*None of the inputs have requires_grad=True.*',\n",
|
| 112 |
+
" '.*use_reentrant parameter should be passed explicitly.*',\n",
|
| 113 |
+
" \".*AccumulateGrad node's stream does not match.*\"):\n",
|
| 114 |
+
" warnings.filterwarnings('ignore', message=pat)\n",
|
| 115 |
+
"\n",
|
| 116 |
+
"class _PhiFilter(logging.Filter):\n",
|
| 117 |
+
" def filter(self, r):\n",
|
| 118 |
+
" return 'Caching is incompatible' not in r.getMessage()\n",
|
| 119 |
+
"for n in ('transformers', 'transformers.models.phi3.modeling_phi3',\n",
|
| 120 |
+
" 'torch.utils.checkpoint'):\n",
|
| 121 |
+
" logging.getLogger(n).addFilter(_PhiFilter())\n",
|
| 122 |
+
"print('warning filters installed')"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
]
|
| 124 |
},
|
| 125 |
{
|
| 126 |
"cell_type": "code",
|
|
|
|
| 127 |
"execution_count": null,
|
| 128 |
+
"metadata": {},
|
| 129 |
"outputs": [],
|
| 130 |
"source": [
|
| 131 |
+
"# === 4. Clone the repo (fresh every run, prints commit hash) ===\n",
|
| 132 |
"import os, subprocess, pathlib, shutil\n",
|
| 133 |
"WORK = '/kaggle/working/incident-commander'\n",
|
|
|
|
|
|
|
| 134 |
"os.chdir('/kaggle/working')\n",
|
| 135 |
+
"if pathlib.Path(WORK).exists():\n",
|
|
|
|
|
|
|
|
|
|
| 136 |
" shutil.rmtree(WORK, ignore_errors=True)\n",
|
| 137 |
"subprocess.run(['git', 'clone', '--depth', '1',\n",
|
| 138 |
+
" 'https://github.com/r1cksync/meta-rl-hack.git', WORK],\n",
|
| 139 |
+
" check=True)\n",
|
| 140 |
"os.chdir(WORK)\n",
|
|
|
|
| 141 |
"subprocess.run(['git', '-C', WORK, 'log', '-1', '--oneline'], check=False)\n",
|
| 142 |
"print('cwd =', os.getcwd())"
|
| 143 |
]
|
| 144 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
{
|
| 146 |
"cell_type": "code",
|
|
|
|
| 147 |
"execution_count": null,
|
| 148 |
+
"metadata": {},
|
| 149 |
"outputs": [],
|
| 150 |
"source": [
|
| 151 |
+
"# === 5. Configure run (shard 3 / 3) ===\n",
|
| 152 |
"import os\n",
|
|
|
|
| 153 |
"os.environ['INCIDENT_COMMANDER_MOCK'] = 'true'\n",
|
| 154 |
"os.environ['IC_ACTOR_MODEL'] = ACTOR_PATH\n",
|
| 155 |
+
"os.environ['IC_CRITIC_PROVIDER'] = 'local'\n",
|
| 156 |
"os.environ['IC_CRITIC_MODEL'] = CRITIC_PATH\n",
|
| 157 |
+
"os.environ['IC_TASK_MODE'] = 'all'\n",
|
| 158 |
"os.environ['IC_TASK_SHARDS'] = '3'\n",
|
| 159 |
"os.environ['IC_TASK_SHARD'] = '2'\n",
|
| 160 |
+
"os.environ['IC_TOTAL_UPDATES'] = '60'\n",
|
| 161 |
"os.environ['IC_ROLLOUTS'] = '3'\n",
|
| 162 |
"os.environ['IC_MAX_STEPS'] = '12'\n",
|
| 163 |
"os.environ['IC_CKPT_EVERY'] = '15'\n",
|
| 164 |
"os.environ['IC_RUN_NAME'] = 'kaggle3'\n",
|
|
|
|
| 165 |
"print('actor :', os.environ['IC_ACTOR_MODEL'])\n",
|
| 166 |
"print('critic:', os.environ['IC_CRITIC_MODEL'])\n",
|
| 167 |
"print('shard :', os.environ['IC_TASK_SHARD'], '/', os.environ['IC_TASK_SHARDS'])"
|
| 168 |
]
|
| 169 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
{
|
| 171 |
"cell_type": "code",
|
|
|
|
| 172 |
"execution_count": null,
|
| 173 |
+
"metadata": {},
|
| 174 |
"outputs": [],
|
| 175 |
"source": [
|
| 176 |
+
"# === 6. Train ===\n",
|
|
|
|
|
|
|
| 177 |
"import subprocess, sys\n",
|
| 178 |
+
"result = subprocess.run([sys.executable, 'scripts/run_training.py'], check=False)\n",
|
|
|
|
| 179 |
"print('exit code:', result.returncode)"
|
| 180 |
]
|
| 181 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 182 |
{
|
| 183 |
"cell_type": "code",
|
|
|
|
| 184 |
"execution_count": null,
|
| 185 |
+
"metadata": {},
|
| 186 |
"outputs": [],
|
| 187 |
"source": [
|
| 188 |
+
"# === 7. Package outputs for download ===\n",
|
| 189 |
"import shutil, glob, pathlib\n",
|
|
|
|
| 190 |
"LOGS = pathlib.Path('colab/logs')\n",
|
| 191 |
"finals = sorted(LOGS.glob('adapter_kaggle3_final'))\n",
|
| 192 |
"ckpts = sorted(LOGS.glob('adapter_kaggle3_u*'))\n",
|
| 193 |
+
"keep = (finals or ckpts)\n",
|
| 194 |
+
"assert keep, 'No adapter directories found -- check the training cell output.'\n",
|
| 195 |
"src = keep[-1]\n",
|
| 196 |
"print('packaging', src)\n",
|
|
|
|
| 197 |
"dst = pathlib.Path('/kaggle/working/adapter_kaggle3.zip')\n",
|
| 198 |
"shutil.make_archive(str(dst.with_suffix('')), 'zip', root_dir=src)\n",
|
| 199 |
"print('zipped to', dst, 'size:', dst.stat().st_size, 'bytes')\n",
|
|
|
|
|
|
|
| 200 |
"for j in glob.glob('colab/logs/training_kaggle3*.json'):\n",
|
| 201 |
" shutil.copy(j, '/kaggle/working/')\n",
|
| 202 |
"print('files in /kaggle/working/:')\n",
|
| 203 |
"for f in sorted(pathlib.Path('/kaggle/working/').iterdir()):\n",
|
| 204 |
+
" if f.name == 'hf-cache':\n",
|
| 205 |
+
" continue\n",
|
| 206 |
" print(' ', f.name, f.stat().st_size if f.is_file() else '<dir>')"
|
| 207 |
]
|
| 208 |
},
|
|
|
|
| 212 |
"source": [
|
| 213 |
"## Done\n",
|
| 214 |
"\n",
|
| 215 |
+
"Download `adapter_kaggle3.zip` from the **Output** tab on the right.\n",
|
| 216 |
+
"Run shard 2 and shard 3 in parallel browser tabs, then on your laptop:\n",
|
|
|
|
| 217 |
"\n",
|
| 218 |
"```powershell\n",
|
| 219 |
"python scripts/merge_lora_adapters.py `\n",
|
|
|
|
| 221 |
" --output ./adapter_merged\n",
|
| 222 |
"```\n",
|
| 223 |
"\n",
|
| 224 |
+
"The merged adapter loads with the standard `peft` API on top of `microsoft/Phi-3.5-mini-instruct`."
|
|
|
|
| 225 |
]
|
| 226 |
}
|
| 227 |
],
|