@tuned-tensor/cli 0.13.0-beta.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -9
- package/dist/{chunk-2VJ3VVZF.js → chunk-YJYCGSHJ.js} +537 -536
- package/dist/chunk-YJYCGSHJ.js.map +1 -0
- package/dist/index.js +53 -401
- package/dist/index.js.map +1 -1
- package/dist/local-runtime.js +39 -10
- package/dist/local-runtime.js.map +1 -1
- package/docs/local-runtime/architecture.md +6 -5
- package/docs/local-runtime/spark.md +23 -17
- package/package.json +1 -1
- package/training/local-runner/src/evaluate.py +4 -1
- package/training/local-runner/src/model_contract.py +5 -3
- package/training/local-runner/src/serve.py +1 -1
- package/dist/chunk-2VJ3VVZF.js.map +0 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# DGX Spark
|
|
2
2
|
|
|
3
3
|
> [!IMPORTANT]
|
|
4
|
-
> `tt-local` is deprecated. Install `@tuned-tensor/cli`
|
|
5
|
-
> Existing projects still work.
|
|
4
|
+
> The standalone `tt-local` binary is deprecated. Install `@tuned-tensor/cli`
|
|
5
|
+
> and use `tt`. Existing projects still work; `tt local …` remains a hidden alias.
|
|
6
6
|
|
|
7
|
-
DGX Spark is the reference host for local text SFT with LoRA adapters. TT
|
|
8
|
-
certifies `Qwen/Qwen3.5-2B
|
|
7
|
+
DGX Spark is the reference host for local text SFT with LoRA adapters. TT
|
|
8
|
+
certifies `Qwen/Qwen3.5-2B` at snapshot
|
|
9
|
+
`15852e8c16360a2fea060d615a32b45270f8a8fc`, the larger
|
|
9
10
|
`nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16` checkpoint, and
|
|
10
11
|
`meta-models/Muse-Glimmer-30B`.
|
|
11
12
|
|
|
@@ -27,7 +28,7 @@ for the Hugging Face cache plus run artifacts.
|
|
|
27
28
|
```bash
|
|
28
29
|
mkdir -p ~/tuned-tensor-runs/support-adapter
|
|
29
30
|
cd ~/tuned-tensor-runs/support-adapter
|
|
30
|
-
tt
|
|
31
|
+
tt init --name "Support Adapter" --model Qwen/Qwen3.5-2B --profile spark
|
|
31
32
|
```
|
|
32
33
|
|
|
33
34
|
For a Nemotron execution worker:
|
|
@@ -35,7 +36,7 @@ For a Nemotron execution worker:
|
|
|
35
36
|
```bash
|
|
36
37
|
mkdir -p ~/tuned-tensor-runs/nemotron-worker
|
|
37
38
|
cd ~/tuned-tensor-runs/nemotron-worker
|
|
38
|
-
tt
|
|
39
|
+
tt init \
|
|
39
40
|
--name "Nemotron Worker" \
|
|
40
41
|
--model nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16 \
|
|
41
42
|
--profile spark
|
|
@@ -52,7 +53,7 @@ For a Muse Glimmer execution worker:
|
|
|
52
53
|
```bash
|
|
53
54
|
mkdir -p ~/tuned-tensor-runs/muse-glimmer-worker
|
|
54
55
|
cd ~/tuned-tensor-runs/muse-glimmer-worker
|
|
55
|
-
tt
|
|
56
|
+
tt init \
|
|
56
57
|
--name "Muse Glimmer Worker" \
|
|
57
58
|
--model meta-models/Muse-Glimmer-30B \
|
|
58
59
|
--profile spark
|
|
@@ -97,11 +98,11 @@ source checkout and a custom runner path are neither required nor supported.
|
|
|
97
98
|
## Preflight and run
|
|
98
99
|
|
|
99
100
|
```bash
|
|
100
|
-
tt
|
|
101
|
-
tt
|
|
102
|
-
tt
|
|
103
|
-
tt
|
|
104
|
-
tt
|
|
101
|
+
tt doctor tunedtensor.json
|
|
102
|
+
tt validate tunedtensor.json
|
|
103
|
+
tt models prefetch tunedtensor.json
|
|
104
|
+
tt models verify-base tunedtensor.json
|
|
105
|
+
tt run tunedtensor.json
|
|
105
106
|
```
|
|
106
107
|
|
|
107
108
|
`doctor` resolves the same bundled project and paths the run will use, imports
|
|
@@ -121,14 +122,19 @@ The runner provides these paths to Python:
|
|
|
121
122
|
## Verify and serve
|
|
122
123
|
|
|
123
124
|
```bash
|
|
124
|
-
tt
|
|
125
|
-
tt
|
|
126
|
-
tt
|
|
125
|
+
tt runs report <run-id>
|
|
126
|
+
tt models verify local-<run-id>
|
|
127
|
+
tt serve local-<run-id> --spec tunedtensor.json --port 8000
|
|
127
128
|
```
|
|
128
129
|
|
|
130
|
+
`tt serve active` fails unless an adapter is activated. Activation requires a
|
|
131
|
+
`generalRegression` suite in `local-runner.json`. Serve a specific adapter
|
|
132
|
+
with `tt serve local-<run-id>` until then.
|
|
133
|
+
|
|
129
134
|
In another shell:
|
|
130
135
|
|
|
131
136
|
```bash
|
|
137
|
+
curl http://127.0.0.1:8000/
|
|
132
138
|
curl http://127.0.0.1:8000/health
|
|
133
139
|
curl http://127.0.0.1:8000/v1/models
|
|
134
140
|
curl http://127.0.0.1:8000/v1/chat/completions \
|
|
@@ -136,8 +142,8 @@ curl http://127.0.0.1:8000/v1/chat/completions \
|
|
|
136
142
|
-d '{"messages":[{"role":"user","content":"Classify: I loved it."}]}'
|
|
137
143
|
```
|
|
138
144
|
|
|
139
|
-
If a run fails, start with `tt
|
|
140
|
-
`tt
|
|
145
|
+
If a run fails, start with `tt runs events <run-id>` and
|
|
146
|
+
`tt runs get <run-id>`. The run record reports its `artifact_dir`; the
|
|
141
147
|
main subprocess logs there are `training/training.log`,
|
|
142
148
|
`baseline-eval.json.inference.log`, and `candidate-eval.json.inference.log`.
|
|
143
149
|
The adapter is registered as soon as its manifest verifies, even if candidate
|
package/package.json
CHANGED
|
@@ -93,7 +93,10 @@ def _extract_adapter_archive(path: Path, destination: Path) -> None:
|
|
|
93
93
|
raise ValueError(f"Unsafe archive member: {member.name}") from exc
|
|
94
94
|
if member.issym() or member.islnk() or member.isdev():
|
|
95
95
|
raise ValueError(f"Unsafe archive member type: {member.name}")
|
|
96
|
-
|
|
96
|
+
try:
|
|
97
|
+
archive.extractall(destination, filter="data")
|
|
98
|
+
except TypeError:
|
|
99
|
+
archive.extractall(destination)
|
|
97
100
|
|
|
98
101
|
|
|
99
102
|
def resolve_adapter_path(value: str | None, tmp: Path) -> str | None:
|
|
@@ -6,6 +6,8 @@ from typing import Any
|
|
|
6
6
|
CERTIFIED_BASE_MODEL = "Qwen/Qwen3.5-2B"
|
|
7
7
|
NEMOTRON_BASE_MODEL = "nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16"
|
|
8
8
|
MUSE_GLIMMER_BASE_MODEL = "meta-models/Muse-Glimmer-30B"
|
|
9
|
+
# Immutable Hugging Face revision reviewed for Qwen 3.5 2B local fine-tuning.
|
|
10
|
+
QWEN_BASE_MODEL_REVISION = "15852e8c16360a2fea060d615a32b45270f8a8fc"
|
|
9
11
|
# Immutable Hugging Face revision reviewed for Nemotron local fine-tuning.
|
|
10
12
|
# Node validates local snapshots against this revision and its certified file
|
|
11
13
|
# digests before invoking Python.
|
|
@@ -133,11 +135,11 @@ def assert_certified_base_model(model_id: str, label: str = "base model") -> Non
|
|
|
133
135
|
def assert_certified_base_model_revision(base_model: str, revision: str | None, label: str = "base model revision") -> None:
|
|
134
136
|
"""Require the certified immutable revision for pinned training models.
|
|
135
137
|
|
|
136
|
-
Qwen
|
|
137
|
-
|
|
138
|
-
verified by the Node runtime.
|
|
138
|
+
Qwen, Nemotron, and Muse Glimmer loads are bound here; local snapshot
|
|
139
|
+
contents are additionally verified by the Node runtime.
|
|
139
140
|
"""
|
|
140
141
|
expected = {
|
|
142
|
+
CERTIFIED_BASE_MODEL: QWEN_BASE_MODEL_REVISION,
|
|
141
143
|
NEMOTRON_BASE_MODEL: NEMOTRON_BASE_MODEL_REVISION,
|
|
142
144
|
MUSE_GLIMMER_BASE_MODEL: MUSE_GLIMMER_BASE_MODEL_REVISION,
|
|
143
145
|
}.get(base_model)
|
|
@@ -191,7 +191,7 @@ class Handler(BaseHTTPRequestHandler):
|
|
|
191
191
|
if not self.authorized():
|
|
192
192
|
self.send_json(401, {"error": {"message": "Unauthorized"}})
|
|
193
193
|
return
|
|
194
|
-
if self.path
|
|
194
|
+
if self.path in {"/", "/health"}:
|
|
195
195
|
self.send_json(200, {"status": "ok", "model": MODEL_NAME, "device": DEVICE})
|
|
196
196
|
return
|
|
197
197
|
if self.path == "/v1/models":
|