gamedevelop commited on
Commit
de3f1ec
·
verified ·
1 Parent(s): bc4120c

Create chatcode/build_notebook.py

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