Spaces:
Running
Running
Remove colab_launcher.ipynb (HF security scanner flag, cloudflared tunnel no longer needed since we moved to HF Spaces)
Browse files- training/colab_launcher.ipynb +0 -152
training/colab_launcher.ipynb
DELETED
|
@@ -1,152 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"cells": [
|
| 3 |
-
{
|
| 4 |
-
"cell_type": "markdown",
|
| 5 |
-
"id": "intro",
|
| 6 |
-
"metadata": {},
|
| 7 |
-
"source": [
|
| 8 |
-
"# Colab → VSCode bridge\n",
|
| 9 |
-
"\n",
|
| 10 |
-
"Run this notebook **on Colab** (T4 GPU runtime). It clones the stocker repo,\n",
|
| 11 |
-
"installs deps, then starts a Jupyter server tunneled via cloudflared.\n",
|
| 12 |
-
"\n",
|
| 13 |
-
"Then on your **local machine**, open VSCode → Command Palette →\n",
|
| 14 |
-
"*Jupyter: Specify Jupyter Server for Connections* → paste the URL printed\n",
|
| 15 |
-
"by the last cell. Open `training/train_grpo.ipynb` locally; pick the remote\n",
|
| 16 |
-
"kernel; cells now execute on Colab's GPU while you edit in VSCode.\n",
|
| 17 |
-
"\n",
|
| 18 |
-
"Caveat: the kernel runs on Colab, so file paths must match what the kernel\n",
|
| 19 |
-
"sees. The launcher `cd`s into `/content/stocker` and adds it to `sys.path`\n",
|
| 20 |
-
"before starting the server, so `import app...` works out of the box.\n",
|
| 21 |
-
"Files you save inside the notebook write to Colab's filesystem — push them\n",
|
| 22 |
-
"back via `git push` from a Colab cell, or mount Drive (cell 0)."
|
| 23 |
-
]
|
| 24 |
-
},
|
| 25 |
-
{
|
| 26 |
-
"cell_type": "code",
|
| 27 |
-
"execution_count": null,
|
| 28 |
-
"id": "drive",
|
| 29 |
-
"metadata": {},
|
| 30 |
-
"outputs": [],
|
| 31 |
-
"source": [
|
| 32 |
-
"# OPTIONAL — mount Drive so artifacts under training/runs/ persist across sessions.\n",
|
| 33 |
-
"# Skip if you'll just download artifacts at the end of the run.\n",
|
| 34 |
-
"# from google.colab import drive\n",
|
| 35 |
-
"# drive.mount('/content/drive')\n",
|
| 36 |
-
"pass"
|
| 37 |
-
]
|
| 38 |
-
},
|
| 39 |
-
{
|
| 40 |
-
"cell_type": "code",
|
| 41 |
-
"execution_count": null,
|
| 42 |
-
"id": "clone",
|
| 43 |
-
"metadata": {},
|
| 44 |
-
"outputs": [],
|
| 45 |
-
"source": [
|
| 46 |
-
"import os\n",
|
| 47 |
-
"REPO_URL = 'https://github.com/CRIMSONHydra/stocker.git' # <-- edit me\n",
|
| 48 |
-
"WORKDIR = '/content/stocker'\n",
|
| 49 |
-
"if not os.path.isdir(WORKDIR):\n",
|
| 50 |
-
" assert '<your-username>' not in REPO_URL, 'Edit REPO_URL first.'\n",
|
| 51 |
-
" !git clone {REPO_URL} {WORKDIR}\n",
|
| 52 |
-
"%cd {WORKDIR}\n",
|
| 53 |
-
"!git pull --rebase 2>/dev/null || true"
|
| 54 |
-
]
|
| 55 |
-
},
|
| 56 |
-
{
|
| 57 |
-
"cell_type": "code",
|
| 58 |
-
"execution_count": null,
|
| 59 |
-
"id": "deps",
|
| 60 |
-
"metadata": {},
|
| 61 |
-
"outputs": [],
|
| 62 |
-
"source": [
|
| 63 |
-
"# Same dep set as train_grpo.ipynb's install cell.\n",
|
| 64 |
-
"!pip install -q -U 'transformers>=4.55' 'trl>=0.11' 'peft>=0.13' 'accelerate>=1.0' 'bitsandbytes>=0.43' 'datasets>=3.0'\n",
|
| 65 |
-
"!pip install -q --upgrade-strategy=only-if-needed yfinance mplfinance pyarrow 'pydantic>=2' pydantic-settings 'openai>=1' tensorboard 'huggingface_hub>=1.10' jupyter-server"
|
| 66 |
-
]
|
| 67 |
-
},
|
| 68 |
-
{
|
| 69 |
-
"cell_type": "code",
|
| 70 |
-
"execution_count": null,
|
| 71 |
-
"id": "cloudflared",
|
| 72 |
-
"metadata": {},
|
| 73 |
-
"outputs": [],
|
| 74 |
-
"source": [
|
| 75 |
-
"# Install cloudflared (free trycloudflare.com tunnel, no signup).\n",
|
| 76 |
-
"!wget -q -O /usr/local/bin/cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64\n",
|
| 77 |
-
"!chmod +x /usr/local/bin/cloudflared\n",
|
| 78 |
-
"!cloudflared --version"
|
| 79 |
-
]
|
| 80 |
-
},
|
| 81 |
-
{
|
| 82 |
-
"cell_type": "code",
|
| 83 |
-
"execution_count": null,
|
| 84 |
-
"id": "build-data",
|
| 85 |
-
"metadata": {},
|
| 86 |
-
"outputs": [],
|
| 87 |
-
"source": [
|
| 88 |
-
"# Pre-build the bundled dataset on Colab so VSCode-driven cells can\n",
|
| 89 |
-
"# `from app.data import loader` immediately. Idempotent.\n",
|
| 90 |
-
"!python scripts/build_dataset.py\n",
|
| 91 |
-
"!python scripts/validate_tasks.py"
|
| 92 |
-
]
|
| 93 |
-
},
|
| 94 |
-
{
|
| 95 |
-
"cell_type": "code",
|
| 96 |
-
"execution_count": null,
|
| 97 |
-
"id": "launch",
|
| 98 |
-
"metadata": {},
|
| 99 |
-
"outputs": [],
|
| 100 |
-
"source": "import os, re, secrets, signal, socket, subprocess, sys, time, pathlib\n\nTOKEN = secrets.token_urlsafe(24)\nPORT = 9988\nLOG_J = pathlib.Path('/content/jupyter.log')\nLOG_C = pathlib.Path('/content/cloudflared.log')\nWORKDIR = '/content/stocker'\n\n# We track the PIDs of OUR own children so re-running this cell can clean up\n# without `pkill -f jupyter-server` (which would also kill Colab's backend\n# and disconnect the runtime!).\nPID_DIR = pathlib.Path('/tmp/stocker_launcher_pids'); PID_DIR.mkdir(exist_ok=True)\n\ndef _kill_prev(name: str) -> None:\n pf = PID_DIR / f'{name}.pid'\n if not pf.exists():\n return\n try:\n pid = int(pf.read_text().strip())\n os.kill(pid, signal.SIGKILL)\n except (ProcessLookupError, ValueError):\n pass\n pf.unlink(missing_ok=True)\n\n_kill_prev('jupyter'); _kill_prev('cloudflared')\nLOG_J.write_text(''); LOG_C.write_text('')\n\ndef _port_free(p: int) -> bool:\n with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:\n return s.connect_ex(('127.0.0.1', p)) != 0\n\nif not _port_free(PORT):\n raise RuntimeError(\n f'Port {PORT} still in use. Re-run after a moment, or restart the '\n f'runtime (Runtime > Restart session) and re-run all cells.'\n )\n\n# --- jupyter-server -------------------------------------------------------\nos.environ['PYTHONPATH'] = WORKDIR\nj = subprocess.Popen(\n [\n sys.executable, '-m', 'jupyter', 'server',\n f'--ServerApp.token={TOKEN}',\n '--ServerApp.password=',\n f'--ServerApp.port={PORT}',\n '--ServerApp.ip=127.0.0.1',\n '--ServerApp.allow_origin=*',\n '--ServerApp.disable_check_xsrf=True',\n '--ServerApp.allow_remote_access=True',\n '--no-browser',\n f'--ServerApp.root_dir={WORKDIR}',\n ],\n stdout=open(LOG_J, 'w'),\n stderr=subprocess.STDOUT,\n cwd=WORKDIR,\n)\n(PID_DIR / 'jupyter.pid').write_text(str(j.pid))\ntime.sleep(3)\nif j.poll() is not None:\n raise RuntimeError(f'jupyter-server died:\\n{LOG_J.read_text()[-2000:]}')\nprint(f'jupyter-server up on 127.0.0.1:{PORT} (pid={j.pid})')\n\n# --- cloudflared (with --logfile, NOT shell redirection) ------------------\nc = subprocess.Popen(\n ['cloudflared', 'tunnel',\n '--url', f'http://127.0.0.1:{PORT}',\n '--no-autoupdate',\n '--loglevel', 'info',\n '--logfile', str(LOG_C)],\n stdout=subprocess.DEVNULL,\n stderr=subprocess.DEVNULL,\n)\n(PID_DIR / 'cloudflared.pid').write_text(str(c.pid))\n\nprint('cloudflared starting (typical: 5-30s) ', end='', flush=True)\nurl, deadline = None, time.time() + 120\nURL_RE = re.compile(r'https://[a-z0-9-]+\\.trycloudflare\\.com')\nwhile time.time() < deadline:\n if c.poll() is not None:\n print(f'\\ncloudflared exited unexpectedly:\\n{LOG_C.read_text()[-2000:]}', file=sys.stderr)\n break\n txt = LOG_C.read_text() if LOG_C.exists() else ''\n m = URL_RE.search(txt)\n if m:\n url = m.group(0)\n break\n print('.', end='', flush=True)\n time.sleep(2)\nprint()\n\nif not url:\n raise RuntimeError(\n 'cloudflared did not produce a URL within 120s.\\n'\n '----- last 2KB of cloudflared log -----\\n'\n + LOG_C.read_text()[-2000:]\n + '\\n----- last 1KB of jupyter log -----\\n'\n + LOG_J.read_text()[-1000:]\n )\n\nFULL = f'{url}/?token={TOKEN}'\nprint('=' * 70)\nprint('Paste this into VSCode -> Jupyter: Specify Jupyter Server for Connections')\nprint()\nprint(' ', FULL)\nprint()\nprint('Smoke-test from anywhere:')\nprint(f' curl -s \"{FULL}/api/status\" | head -c 200')\nprint('=' * 70)\nprint('\\nKeep this Colab tab open — the tunnel dies when the runtime disconnects.')"
|
| 101 |
-
},
|
| 102 |
-
{
|
| 103 |
-
"cell_type": "markdown",
|
| 104 |
-
"id": "vscode-steps",
|
| 105 |
-
"metadata": {},
|
| 106 |
-
"source": [
|
| 107 |
-
"## Connect from VSCode\n",
|
| 108 |
-
"\n",
|
| 109 |
-
"1. **Install the Jupyter extension** in VSCode (Microsoft, ID `ms-toolsai.jupyter`) if you don't have it.\n",
|
| 110 |
-
"2. Open `training/train_grpo.ipynb` locally.\n",
|
| 111 |
-
"3. Command Palette → **`Jupyter: Specify Jupyter Server for Connections`** → *Existing* → paste the URL printed above.\n",
|
| 112 |
-
"4. In the kernel picker (top-right of the notebook), pick the remote runtime — VSCode shows it as `Python 3 (ipykernel)` under the trycloudflare host.\n",
|
| 113 |
-
"5. Run cells. Imports like `from app.council.llm import TransformersLLMClient` resolve because the kernel cwd is `/content/stocker`.\n",
|
| 114 |
-
"\n",
|
| 115 |
-
"## Heartbeat\n",
|
| 116 |
-
"\n",
|
| 117 |
-
"If you idle, Colab eventually evicts the runtime and the URL stops working.\n",
|
| 118 |
-
"Re-run the **`launch`** cell to get a new URL and re-specify the server in\n",
|
| 119 |
-
"VSCode. Long training runs should run inside a `nohup`-style guard or use\n",
|
| 120 |
-
"Colab Pro for the 24-hour runtime.\n",
|
| 121 |
-
"\n",
|
| 122 |
-
"## Pulling artifacts back\n",
|
| 123 |
-
"\n",
|
| 124 |
-
"Trained LoRAs and plots land in `/content/stocker/training/runs/<id>/`. To\n",
|
| 125 |
-
"get them onto your laptop:\n",
|
| 126 |
-
"\n",
|
| 127 |
-
"```python\n",
|
| 128 |
-
"# in a Colab cell, after training\n",
|
| 129 |
-
"from google.colab import files\n",
|
| 130 |
-
"import shutil, glob\n",
|
| 131 |
-
"run = sorted(glob.glob('/content/stocker/training/runs/grpo_*'))[-1]\n",
|
| 132 |
-
"shutil.make_archive('/content/run', 'zip', run)\n",
|
| 133 |
-
"files.download('/content/run.zip')\n",
|
| 134 |
-
"```\n",
|
| 135 |
-
"\n",
|
| 136 |
-
"Or `git add` + `git push` from a Colab cell to your fork."
|
| 137 |
-
]
|
| 138 |
-
}
|
| 139 |
-
],
|
| 140 |
-
"metadata": {
|
| 141 |
-
"kernelspec": {
|
| 142 |
-
"display_name": "Python 3",
|
| 143 |
-
"language": "python",
|
| 144 |
-
"name": "python3"
|
| 145 |
-
},
|
| 146 |
-
"language_info": {
|
| 147 |
-
"name": "python"
|
| 148 |
-
}
|
| 149 |
-
},
|
| 150 |
-
"nbformat": 4,
|
| 151 |
-
"nbformat_minor": 5
|
| 152 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|