File size: 10,094 Bytes
de3f1ec 048e554 de3f1ec | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | """Create a portable Colab walkthrough using the standard notebook JSON format."""
import ast
from contextlib import redirect_stdout
import io
import json
from pathlib import Path
def build():
cells = []
def markdown(text):
cells.append({"cell_type": "markdown", "id": f"cell-{len(cells):02}", "metadata": {}, "source": text})
def code(text):
cells.append({"cell_type": "code", "id": f"cell-{len(cells):02}", "metadata": {},
"source": text, "execution_count": None, "outputs": []})
markdown("""# PocketVision: cloud training for chat, code and writing
## Goal
Run a small QLoRA smoke experiment on a **Colab cloud GPU**, then inspect a candidate before scaling up.
The PC only displays this notebook. No trained 4B weights are included.
**Validation status:** the saved outputs show a local dry run only. Cloud installation, source authentication,
GPU memory, training, and model quality remain untested. Free Colab GPU availability is not guaranteed.
Choose a free runtime yourself; this notebook does not purchase compute or alter subscriptions.
English Wikipedia restricts AI-generated article prose. Use the reference-article task for other contexts,
and the outline/source-review task for Wikipedia preparation.
[Current guideline](https://en.wikipedia.org/wiki/Wikipedia:Writing_articles_with_large_language_models).
""")
markdown("""## Setup
1. Upload this notebook to Colab and select a GPU runtime.
2. Set `DRY_RUN = False` below. Set `RUN_TRAINING = True` only when ready to use the allocated GPU.
3. Store an existing Hugging Face **read token** in Colab Secrets as `HF_TOKEN` and grant this notebook access.
The source repository is private. Do not paste a token into a code cell or chat.
4. The Drive step asks you to mount Google Drive. This grants notebook code access to the mounted files;
only the named PocketVision folder is used here for checkpoints.
""")
code('''from pathlib import Path
import json
import os
import subprocess
import sys
DRY_RUN = True
RUN_TRAINING = False
SOURCE_REPO = "gamedevelop/pocketvision-chat-code"
SOURCE_REVISION = None # None resolves and records one immutable commit before downloading.
PILOT_ROWS = 200 # Dependency/memory smoke test. Use 20000 only after reviewing the smoke run.
HOLDOUT_PER_SOURCE = 2
MAX_STEPS = 25
RUN_NAME = "writing-smoke-01" # Change for a fresh run; existing output is never overwritten.
RESUME_CHECKPOINT = None # Or an existing checkpoint-N directory from the same run.
cloud_python = Path("/content/pocketvision-venv/bin/python")
source_dir = None
run_dir = None
print("Dry-run validation only; no cloud operations." if DRY_RUN else "Cloud setup enabled; training still needs RUN_TRAINING=True.")
''')
markdown("""### 1. Install an isolated cloud environment
Installation uses a separate environment, preserving the notebook kernel's packages.
The next check requires a CUDA GPU before any model weights are loaded.
""")
code('''if not DRY_RUN:
subprocess.run([sys.executable, "-m", "venv", str(cloud_python.parent.parent)], check=True)
subprocess.run([str(cloud_python), "-m", "pip", "install", "torch==2.9.1",
"--index-url", "https://download.pytorch.org/whl/cu128"], check=True)
subprocess.run([sys.executable, "-m", "pip", "install", "huggingface-hub==0.36.2"], check=True)
subprocess.run([str(cloud_python), "-c",
"import torch; assert torch.cuda.is_available(), 'Select a Colab GPU runtime'; print(torch.cuda.get_device_name(0))"], check=True)
else:
print("Skipped: dependency installation and GPU allocation checks.")
''')
markdown("""### 2. Download only the versioned source
The commit is resolved once and logged; pretrained weights and source ZIPs are excluded.
The model and datasets have their own pinned revisions in the configuration.
""")
code('''if not DRY_RUN:
from google.colab import userdata
from huggingface_hub import HfApi, snapshot_download
os.environ["HF_TOKEN"] = userdata.get("HF_TOKEN")
revision = HfApi().model_info(SOURCE_REPO, revision=SOURCE_REVISION or "main").sha
source_dir = Path(snapshot_download(SOURCE_REPO, revision=revision, allow_patterns=[
"app.py", "chat.py", "LICENSE*", "chatcode/*.py", "chatcode/*.json", "chatcode/*.txt", "chatcode/*.md"]))
assert (source_dir / "chatcode/articles.py").is_file(), "This source commit predates article support."
subprocess.run([str(cloud_python), "-m", "pip", "install", "-r",
str(source_dir / "chatcode/requirements-cloud.txt")], check=True)
subprocess.run([str(cloud_python), "-m", "pip", "check"], check=True)
print("Source commit:", revision)
else:
print("Skipped: private Hub download and authentication. No token requested.")
''')
markdown("""### 3. Use persistent storage
Colab's runtime disk is temporary. Drive contains the data manifest, optimizer checkpoints and candidate.
Only this new run folder is created; no existing files are deleted.
""")
code('''if not DRY_RUN:
from google.colab import drive
drive.mount("/content/drive")
checkpoint_root = Path("/content/drive/MyDrive/PocketVision-writing")
run_dir = checkpoint_root / RUN_NAME
if run_dir.exists() and any(run_dir.iterdir()) and not RESUME_CHECKPOINT:
raise FileExistsError("Choose a fresh RUN_NAME or explicitly resume an existing checkpoint.")
run_dir.mkdir(parents=True, exist_ok=True)
(run_dir / "run-info.json").write_text(json.dumps({"source_repo": SOURCE_REPO,
"source_revision": revision, "pilot_rows": PILOT_ROWS, "max_steps": MAX_STEPS}, indent=2))
print("Persistent run directory:", run_dir)
else:
print("Skipped: Drive authorization and persistent cloud writes.")
''')
markdown("""## Steps
### 4. Prepare data and run the capped experiment
This cell streams selected chat, coding, rewriting and summarization data, adds the small authored behavior
packets, and runs 25 optimizer steps. It may consume significant GPU time even on a small sample.
The full 20,000-example experiment is a separate decision after measuring steps/second and memory.
""")
code('''if not DRY_RUN and RUN_TRAINING:
data_dir = run_dir / "data"
if not (data_dir / "manifest.json").is_file():
subprocess.run([str(cloud_python), "-m", "chatcode.data", "--output", str(data_dir),
"--train", str(PILOT_ROWS), "--holdout-per-source", str(HOLDOUT_PER_SOURCE)], cwd=source_dir, check=True)
command = [str(cloud_python), "-m", "chatcode.train", "--data", str(data_dir),
"--output", str(run_dir / "training"), "--max-steps", str(MAX_STEPS)]
if RESUME_CHECKPOINT:
command.extend(["--resume-from-checkpoint", str(RESUME_CHECKPOINT)])
subprocess.run(command, cwd=source_dir, check=True)
else:
print("Skipped: dataset preparation and weight training. No model weights downloaded.")
''')
markdown("""## Checks
### 5. Compare base and candidate
The automated article check measures JSON/citation-ID validity on four held-out fictional cases.
It does **not** measure factual accuracy, source reliability, or Wikipedia suitability. Inspect all saved
outputs, and separately test chat and code regressions. Do not execute generated programs outside a sandbox.
""")
code('''if not DRY_RUN and RUN_TRAINING:
candidate_dir = run_dir / "training/adapter"
subprocess.run([str(cloud_python), "-m", "chatcode.evaluate_articles", "--adapter", str(candidate_dir),
"--output", str(run_dir / "article-evaluation.json")], cwd=source_dir, check=True)
print("Candidate and evaluation saved under:", run_dir)
else:
print("Skipped: model evaluation. No accuracy or quality result is claimed.")
''')
markdown("""## Next Steps
Review the cloud smoke run before raising `PILOT_ROWS`, holdout sizes or run duration. Training data changes
require a new run directory; do not resume a checkpoint against different data.
The source recipe alone does not improve weights. Compare factual support and neutrality with the base,
and check programming and conversation regressions before publishing a candidate.
No upload or Wikipedia publication is performed by this notebook. A later Hub upload needs a separate
write-scoped credential and a reviewed candidate. Do not share notebook outputs containing credentials.
""")
notebook = {"nbformat": 4, "nbformat_minor": 5,
"metadata": {"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"},
"language_info": {"name": "python", "version": "3.12"},
"pocketvision_validation": "local_dry_run_only_no_cloud_execution"}, "cells": cells}
return notebook
def validate_and_dry_run(notebook):
"""Structural and Python syntax checks when nbformat is unavailable locally."""
assert notebook["nbformat"] == 4 and notebook["nbformat_minor"] == 5
namespace, ids, count = {}, set(), 0
for cell in notebook["cells"]:
assert cell["id"] not in ids and isinstance(cell["metadata"], dict) and isinstance(cell["source"], str)
ids.add(cell["id"])
assert cell["cell_type"] in {"markdown", "code"}
if cell["cell_type"] == "code":
compiled = compile(ast.parse(cell["source"]), "<notebook-cell>", "exec")
output = io.StringIO()
with redirect_stdout(output):
exec(compiled, namespace)
count += 1
cell["execution_count"] = count
cell["outputs"] = [{"output_type": "stream", "name": "stdout", "text": output.getvalue()}]
assert namespace["DRY_RUN"] is True and namespace["RUN_TRAINING"] is False
return notebook
if __name__ == "__main__":
path = Path(__file__).with_name("cloud_training.ipynb")
path.write_text(json.dumps(validate_and_dry_run(build()), ensure_ascii=False, indent=2), encoding="utf-8")
print(f"Wrote {path}; all cells executed only in dry-run mode. GPU execution remains unverified.")
|