@tuned-tensor/local 0.2.8 → 0.3.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/CHANGELOG.md +67 -0
- package/README.md +84 -204
- package/dist/artifacts.d.ts +3 -4
- package/dist/artifacts.js +55 -33
- package/dist/artifacts.js.map +1 -1
- package/dist/compare.d.ts +1 -8
- package/dist/compare.js +1 -23
- package/dist/compare.js.map +1 -1
- package/dist/contracts.d.ts +59 -366
- package/dist/contracts.js +73 -224
- package/dist/contracts.js.map +1 -1
- package/dist/dataset.d.ts +2 -4
- package/dist/dataset.js +31 -125
- package/dist/dataset.js.map +1 -1
- package/dist/doctor.d.ts +2 -3
- package/dist/doctor.js +23 -161
- package/dist/doctor.js.map +1 -1
- package/dist/evaluation.d.ts +11 -71
- package/dist/evaluation.js +212 -572
- package/dist/evaluation.js.map +1 -1
- package/dist/huggingface-cache.d.ts +8 -7
- package/dist/huggingface-cache.js +16 -8
- package/dist/huggingface-cache.js.map +1 -1
- package/dist/index.d.ts +0 -10
- package/dist/index.js +205 -628
- package/dist/index.js.map +1 -1
- package/dist/local-project.d.ts +1 -11
- package/dist/local-project.js +33 -61
- package/dist/local-project.js.map +1 -1
- package/dist/model-registry.d.ts +3 -16
- package/dist/model-registry.js +76 -292
- package/dist/model-registry.js.map +1 -1
- package/dist/model-server.d.ts +1 -2
- package/dist/model-server.js +9 -18
- package/dist/model-server.js.map +1 -1
- package/dist/orchestrator.d.ts +11 -25
- package/dist/orchestrator.js +246 -566
- package/dist/orchestrator.js.map +1 -1
- package/dist/prefetch.d.ts +1 -5
- package/dist/prefetch.js +14 -19
- package/dist/prefetch.js.map +1 -1
- package/dist/process-runner.d.ts +10 -29
- package/dist/process-runner.js +63 -169
- package/dist/process-runner.js.map +1 -1
- package/dist/process-training.d.ts +0 -1
- package/dist/process-training.js +10 -87
- package/dist/process-training.js.map +1 -1
- package/dist/store.d.ts +1 -3
- package/dist/store.js +92 -290
- package/dist/store.js.map +1 -1
- package/docs/architecture.md +87 -152
- package/docs/spark.md +66 -97
- package/examples/dry-runner.json +14 -0
- package/examples/local-runner.json +8 -6
- package/examples/smoke-spec.json +41 -0
- package/package.json +6 -6
- package/training/local-runner/pyproject.toml +0 -5
- package/training/local-runner/src/evaluate.py +89 -234
- package/training/local-runner/src/model_contract.py +47 -0
- package/training/local-runner/src/prefetch.py +18 -4
- package/training/local-runner/src/serve.py +54 -115
- package/training/local-runner/src/sft_data.py +97 -0
- package/training/local-runner/src/train.py +146 -346
- package/training/local-runner/uv.lock +0 -1197
- package/dist/labeling-sanitize.d.ts +0 -31
- package/dist/labeling-sanitize.js +0 -158
- package/dist/labeling-sanitize.js.map +0 -1
- package/dist/labeling.d.ts +0 -155
- package/dist/labeling.js +0 -496
- package/dist/labeling.js.map +0 -1
- package/dist/openrouter.d.ts +0 -29
- package/dist/openrouter.js +0 -66
- package/dist/openrouter.js.map +0 -1
- package/dist/server.d.ts +0 -9
- package/dist/server.js +0 -211
- package/dist/server.js.map +0 -1
- package/docs/local-workflow-remediation-2026-07-13.md +0 -130
- package/docs/local-workflow-ux-review-2026-07-13.md +0 -458
- package/examples/dpo-preferences.jsonl +0 -2
- package/examples/dpo-run-request.json +0 -34
- package/examples/smoke-run-request.json +0 -34
- package/training/local-runner/src/train_dpo.py +0 -286
package/docs/architecture.md
CHANGED
|
@@ -1,154 +1,89 @@
|
|
|
1
1
|
# Architecture
|
|
2
2
|
|
|
3
|
-
TT Local is
|
|
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
|
-
custom workflow can load any artifact format as long as it writes compatible
|
|
91
|
-
evaluation results.
|
|
92
|
-
|
|
93
|
-
`paths.modelCache` is a single cache contract: it is passed as Hugging Face
|
|
94
|
-
`HF_HOME`, and Hub snapshots live beneath `<modelCache>/hub`. The environment
|
|
95
|
-
is finalized before importing Hugging Face or Transformers in every bundled
|
|
96
|
-
Python process. Prefetch records the resolved snapshot revision, file count,
|
|
97
|
-
and byte count; `models verify-base` performs a local-only structural check of
|
|
98
|
-
the cached config, tokenizer, weights, and indexed shards.
|
|
99
|
-
|
|
100
|
-
An explicitly configured `paths.baseModel` is a complete Hugging Face snapshot
|
|
101
|
-
directory, never a generic weights file or archive. Its file contents are
|
|
102
|
-
fingerprinted for stage identity. Remote runs should set an immutable
|
|
103
|
-
`base_model_revision`; baseline caching is bypassed when the model or a remote
|
|
104
|
-
input lacks stable content identity.
|
|
105
|
-
|
|
106
|
-
## Local State Layout
|
|
107
|
-
|
|
108
|
-
The local store is intentionally transparent and easy to back up:
|
|
109
|
-
|
|
110
|
-
- `metadata.sqlite`
|
|
111
|
-
- `specs/<spec-id>/spec.json`
|
|
112
|
-
- `runs/<run-id>/request.json`
|
|
113
|
-
- `runs/<run-id>/state.json`
|
|
114
|
-
- `runs/<run-id>/progress.jsonl`
|
|
115
|
-
- `runs/<run-id>/run-report.json`
|
|
116
|
-
- `models/<model-id>/model.json`
|
|
117
|
-
|
|
118
|
-
Each successful real training stage also writes `artifact-manifest.json` with
|
|
119
|
-
the model contract and SHA-256/size entries for immutable files. Dry runs do
|
|
120
|
-
not create model records. `tt-local models verify` accepts a model ID, exact
|
|
121
|
-
artifact path, or its manifest path and re-hashes the model before it is served
|
|
122
|
-
or handed off.
|
|
123
|
-
|
|
124
|
-
The default Transformers/PEFT contract requires exact adapter weights plus a
|
|
125
|
-
non-empty `adapter_config.json`; a full-model contract requires recognized
|
|
126
|
-
Transformers model weights. Command backends may publish another layout only
|
|
127
|
-
with an explicit framework/format contract, and such artifacts are not
|
|
128
|
-
implicitly servable.
|
|
129
|
-
|
|
130
|
-
SQLite is the primary metadata index for CLI and dashboard listings. The
|
|
131
|
-
per-object JSON files remain the recoverable source for artifacts and
|
|
132
|
-
human-readable inspection. `tt-local store rebuild-index` can reconstruct the
|
|
133
|
-
SQLite index from the canonical per-object files.
|
|
134
|
-
|
|
135
|
-
## Dashboard API
|
|
136
|
-
|
|
137
|
-
The local server is a lightweight Node HTTP server backed by the local state
|
|
138
|
-
store. Current endpoints include:
|
|
139
|
-
|
|
140
|
-
- `GET /api/health`
|
|
141
|
-
- `GET /api/runs`, `GET /api/runs/:id`, `GET /api/runs/:id/events`
|
|
142
|
-
- `GET /api/runs/:id/events/stream`
|
|
143
|
-
- `GET /api/runs/:id/report`
|
|
144
|
-
- `POST /api/runs`
|
|
145
|
-
- `POST /api/runs/:id/cancel`
|
|
146
|
-
- `GET /api/models`, `GET /api/models/:id`
|
|
147
|
-
- `GET /api/specs`, `GET /api/specs/:id`
|
|
148
|
-
|
|
149
|
-
## Failure Handling
|
|
150
|
-
|
|
151
|
-
The orchestrator should fail fast when prerequisites are missing. Common checks
|
|
152
|
-
include uv availability, Python dependency resolution, GPU visibility, model
|
|
153
|
-
cache permissions, artifact directory writability, and dataset size limits for
|
|
154
|
-
the selected model.
|
|
3
|
+
TT Local is a focused, single-host fine-tuning tool. Its supported product
|
|
4
|
+
boundary is text SFT of `Qwen/Qwen3.5-2B` into a LoRA adapter on CUDA.
|
|
5
|
+
|
|
6
|
+
## Workflow
|
|
7
|
+
|
|
8
|
+
1. Parse a strict behavior spec or request.
|
|
9
|
+
2. Compile or validate chat JSONL and select distinct training/evaluation rows.
|
|
10
|
+
3. Evaluate the base model with the bundled Transformers runner.
|
|
11
|
+
4. Train a PEFT adapter with the bundled, locked `uv` project.
|
|
12
|
+
5. Verify and register the adapter before downstream evaluation.
|
|
13
|
+
6. Evaluate the adapter on the same held-out rows.
|
|
14
|
+
7. Write a base-versus-tuned report.
|
|
15
|
+
|
|
16
|
+
The orchestrator retains explicit stages and fingerprints internally so an
|
|
17
|
+
interrupted run can safely resume. These mechanics are reliability
|
|
18
|
+
implementation details, not a public plugin framework.
|
|
19
|
+
|
|
20
|
+
## Boundaries
|
|
21
|
+
|
|
22
|
+
The first version intentionally excludes:
|
|
23
|
+
|
|
24
|
+
- arbitrary training or evaluation commands;
|
|
25
|
+
- DPO, continued pretraining, and multimodal training;
|
|
26
|
+
- cloud labeling or LLM-as-judge calls;
|
|
27
|
+
- classic tabular model studies;
|
|
28
|
+
- a local web dashboard;
|
|
29
|
+
- unverified model-family claims.
|
|
30
|
+
|
|
31
|
+
The next model or method should arrive with its own locked dependencies,
|
|
32
|
+
resource defaults, data contract, and real CUDA acceptance test.
|
|
33
|
+
|
|
34
|
+
## Python boundary
|
|
35
|
+
|
|
36
|
+
Node owns input validation, state, process lifecycle, manifests, and reports.
|
|
37
|
+
The bundled Python project owns four small operations:
|
|
38
|
+
|
|
39
|
+
- `prefetch.py`: download and verify the pinned Hugging Face snapshot;
|
|
40
|
+
- `evaluate.py`: generate predictions without receiving reference answers;
|
|
41
|
+
- `train.py`: perform CUDA-only Qwen LoRA SFT;
|
|
42
|
+
- `serve.py`: load the base model and verified adapter for inference.
|
|
43
|
+
|
|
44
|
+
Training uses assistant-only loss. Prompt tokens have label `-100`, and
|
|
45
|
+
truncation removes older prompt tokens before it removes any answer token.
|
|
46
|
+
Tokenizer chat-template failures are fatal because a fallback would silently
|
|
47
|
+
change the trained or served prompt format.
|
|
48
|
+
|
|
49
|
+
## Evaluation
|
|
50
|
+
|
|
51
|
+
Baseline and candidate evaluation use the same input IDs, generation settings,
|
|
52
|
+
and deterministic scoring:
|
|
53
|
+
|
|
54
|
+
- baseline: recorded base-model snapshot;
|
|
55
|
+
- candidate: that base snapshot plus the run's verified PEFT adapter;
|
|
56
|
+
- scoring: normalized exact match or selected JSON fields.
|
|
57
|
+
|
|
58
|
+
The Python evaluator receives only opaque IDs and prompts. Node joins its
|
|
59
|
+
predictions to trusted references before scoring. This avoids accidental label
|
|
60
|
+
leakage across the process boundary.
|
|
61
|
+
|
|
62
|
+
## Storage and integrity
|
|
63
|
+
|
|
64
|
+
Canonical JSON and JSONL files are the state store; there is no database or
|
|
65
|
+
mirrored index. Writes are atomic and listings scan the small local metadata
|
|
66
|
+
tree deterministically.
|
|
67
|
+
|
|
68
|
+
Each real adapter has an atomic `artifact-manifest.json` with the expected PEFT
|
|
69
|
+
files, byte sizes, and SHA-256 hashes. A model is registered immediately after
|
|
70
|
+
training and manifest verification, so a later evaluation failure does not
|
|
71
|
+
hide a valid artifact. Serving verifies the manifest again.
|
|
72
|
+
|
|
73
|
+
## Configuration
|
|
74
|
+
|
|
75
|
+
The runner config controls only:
|
|
76
|
+
|
|
77
|
+
- state, artifact, and Hugging Face cache paths;
|
|
78
|
+
- CUDA or CPU inference for evaluation and serving;
|
|
79
|
+
- deterministic generation and scoring limits.
|
|
80
|
+
|
|
81
|
+
The training project, Python entrypoints, working directory, and child
|
|
82
|
+
environment are internal and fixed. Every stage uses the locked `uv` project
|
|
83
|
+
included in the npm package. The mutable virtual environment lives in the
|
|
84
|
+
user cache, keyed by the project and lockfile content, so a read-only global
|
|
85
|
+
npm install remains runnable.
|
|
86
|
+
|
|
87
|
+
Schemas are strict. Misspelled or obsolete fields fail validation instead of
|
|
88
|
+
silently reverting to defaults. Training itself is CUDA-only and fails fast
|
|
89
|
+
when PyTorch cannot see the GPU.
|
package/docs/spark.md
CHANGED
|
@@ -1,134 +1,103 @@
|
|
|
1
|
-
#
|
|
1
|
+
# DGX Spark
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
able to see the GPU.
|
|
3
|
+
DGX Spark is the reference host for TT Local's first supported path:
|
|
4
|
+
`Qwen/Qwen3.5-2B` text SFT with a LoRA adapter.
|
|
6
5
|
|
|
7
|
-
##
|
|
6
|
+
## Check the host
|
|
8
7
|
|
|
9
|
-
Run
|
|
8
|
+
Run on the Spark:
|
|
10
9
|
|
|
11
10
|
```bash
|
|
12
11
|
nvidia-smi
|
|
12
|
+
node --version
|
|
13
13
|
uv --version
|
|
14
|
-
uv run python --version
|
|
15
14
|
```
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
TT Local requires Node 22+, `uv`, working CUDA PyTorch, and enough free space
|
|
17
|
+
for the Hugging Face cache plus run artifacts.
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Open a new shell or source the installer-updated profile before rerunning
|
|
24
|
-
`uv --version`.
|
|
25
|
-
|
|
26
|
-
Then run the project doctor command:
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
npm run build
|
|
30
|
-
tt-local doctor --config examples/local-runner.json
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Dry Run
|
|
34
|
-
|
|
35
|
-
The example config uses `dryRun: true`, so it validates orchestration, dataset
|
|
36
|
-
compilation, artifact writing, and report generation without launching training:
|
|
19
|
+
## Create a project
|
|
37
20
|
|
|
38
21
|
```bash
|
|
39
|
-
|
|
22
|
+
mkdir -p ~/tuned-tensor-runs/support-adapter
|
|
23
|
+
cd ~/tuned-tensor-runs/support-adapter
|
|
24
|
+
tt-local init --name "Support Adapter" --model Qwen/Qwen3.5-2B --profile spark
|
|
40
25
|
```
|
|
41
26
|
|
|
42
|
-
|
|
27
|
+
Edit both generated examples in `tunedtensor.json`. For a meaningful run,
|
|
28
|
+
replace them with a larger, representative dataset and a separate validation
|
|
29
|
+
split.
|
|
43
30
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
That project is bundled in the npm package, so users do not need a local source
|
|
47
|
-
checkout. Leave `training.script` unset: the runner chooses the bundled script
|
|
48
|
-
from the run request's `training_method`.
|
|
49
|
-
|
|
50
|
-
- `training_method: "sft"` runs `training/local-runner/src/train.py`.
|
|
51
|
-
- `training_method: "dpo"` runs `training/local-runner/src/train_dpo.py`.
|
|
52
|
-
|
|
53
|
-
Set `training.script` only when you want to override that selection with a
|
|
54
|
-
specific custom uv script.
|
|
31
|
+
The generated `local-runner.json` uses CUDA and project-local artifacts. A
|
|
32
|
+
durable Spark configuration can set:
|
|
55
33
|
|
|
56
34
|
```json
|
|
57
35
|
{
|
|
58
|
-
"artifactRoot": "/home/eve/
|
|
59
|
-
"
|
|
60
|
-
"training": {
|
|
61
|
-
"backend": "uv",
|
|
62
|
-
"project": "training/local-runner"
|
|
63
|
-
},
|
|
36
|
+
"artifactRoot": "/home/eve/tuned-tensor-runs/artifacts",
|
|
37
|
+
"storeRoot": "/home/eve/tuned-tensor-runs/store",
|
|
64
38
|
"paths": {
|
|
65
39
|
"modelCache": "/home/eve/.cache/huggingface"
|
|
40
|
+
},
|
|
41
|
+
"evaluation": {
|
|
42
|
+
"inference": {
|
|
43
|
+
"device": "cuda"
|
|
44
|
+
},
|
|
45
|
+
"scoring": {
|
|
46
|
+
"mode": "exact_match"
|
|
47
|
+
},
|
|
48
|
+
"timeoutMs": 1800000
|
|
66
49
|
}
|
|
67
50
|
}
|
|
68
51
|
```
|
|
69
52
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- `SM_CHANNEL_TRAINING` to the local training JSONL directory;
|
|
73
|
-
- `TT_HYPERPARAMETERS_PATH` to the generated hyperparameter JSON file;
|
|
74
|
-
- `SM_OUTPUT_DIR` to the local training output directory;
|
|
75
|
-
- `SM_MODEL_DIR` to the local model output directory;
|
|
76
|
-
- `SM_CHANNEL_BASE_MODEL` when a local base-model artifact path is configured;
|
|
77
|
-
- `HF_HOME` when `paths.modelCache` is configured.
|
|
78
|
-
|
|
79
|
-
Real runs also use the Transformers/PEFT evaluator by default. Baseline
|
|
80
|
-
evaluation loads the original Hugging Face model, and candidate evaluation loads
|
|
81
|
-
that same base model plus the fine-tuned artifact from the run directory. Set
|
|
82
|
-
`paths.modelCache` to a persistent Spark-local cache so training and evaluation
|
|
83
|
-
reuse downloads.
|
|
53
|
+
Every Python stage uses the locked runtime included in the npm package; a
|
|
54
|
+
source checkout and a custom runner path are neither required nor supported.
|
|
84
55
|
|
|
85
|
-
|
|
86
|
-
creating `tunedtensor.json` and the runner config:
|
|
56
|
+
## Preflight and run
|
|
87
57
|
|
|
88
58
|
```bash
|
|
89
|
-
tt-local
|
|
59
|
+
tt-local doctor tunedtensor.json
|
|
60
|
+
tt-local validate tunedtensor.json
|
|
61
|
+
tt-local models prefetch tunedtensor.json
|
|
62
|
+
tt-local models verify-base tunedtensor.json
|
|
63
|
+
tt-local run tunedtensor.json
|
|
90
64
|
```
|
|
91
65
|
|
|
92
|
-
|
|
93
|
-
Transformers
|
|
66
|
+
`doctor` resolves the same bundled project and paths the run will use, imports
|
|
67
|
+
Torch/Transformers/PEFT, requires visible CUDA, checks writable storage, and
|
|
68
|
+
rejects unchanged placeholders. `validate` reads and normalizes the actual
|
|
69
|
+
dataset before any run state or artifact directory is claimed.
|
|
94
70
|
|
|
95
|
-
|
|
96
|
-
entrypoints instead:
|
|
71
|
+
The runner provides these paths to Python:
|
|
97
72
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
"evaluation": {
|
|
107
|
-
"inference": {
|
|
108
|
-
"provider": "batch_command",
|
|
109
|
-
"command": ["python", "nanogpt/evaluate.py"]
|
|
110
|
-
},
|
|
111
|
-
"scoring": {
|
|
112
|
-
"mode": "exact_match"
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
```
|
|
73
|
+
- `SM_CHANNEL_TRAINING`: prepared chat JSONL directory;
|
|
74
|
+
- `TT_HYPERPARAMETERS_PATH`: generated SFT/LoRA parameters;
|
|
75
|
+
- `SM_OUTPUT_DIR`: logs and metrics;
|
|
76
|
+
- `SM_MODEL_DIR`: adapter output;
|
|
77
|
+
- `SM_CHANNEL_BASE_MODEL`: optional verified local model snapshot;
|
|
78
|
+
- `HF_HOME`: configured persistent model cache.
|
|
79
|
+
|
|
80
|
+
## Verify and serve
|
|
117
81
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
82
|
+
```bash
|
|
83
|
+
tt-local runs report <run-id>
|
|
84
|
+
tt-local models verify local-<run-id>
|
|
85
|
+
tt-local serve local-<run-id> --spec tunedtensor.json --port 8000
|
|
86
|
+
```
|
|
121
87
|
|
|
122
|
-
|
|
123
|
-
through uv:
|
|
88
|
+
In another shell:
|
|
124
89
|
|
|
125
90
|
```bash
|
|
126
|
-
|
|
127
|
-
|
|
91
|
+
curl http://127.0.0.1:8000/health
|
|
92
|
+
curl http://127.0.0.1:8000/v1/models
|
|
93
|
+
curl http://127.0.0.1:8000/v1/chat/completions \
|
|
94
|
+
-H 'Content-Type: application/json' \
|
|
95
|
+
-d '{"messages":[{"role":"user","content":"Classify: I loved it."}]}'
|
|
128
96
|
```
|
|
129
97
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
`
|
|
134
|
-
|
|
98
|
+
If a run fails, start with `tt-local runs events <run-id>` and
|
|
99
|
+
`tt-local runs get <run-id>`. The run record reports its `artifact_dir`; the
|
|
100
|
+
main subprocess logs there are `training/training.log`,
|
|
101
|
+
`baseline-eval.json.inference.log`, and `candidate-eval.json.inference.log`.
|
|
102
|
+
The adapter is registered as soon as its manifest verifies, even if candidate
|
|
103
|
+
evaluation fails afterward.
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"artifactRoot": ".tt-local/artifacts",
|
|
3
3
|
"storeRoot": ".tt-local/store",
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
"backend": "uv",
|
|
7
|
-
"project": "training/local-runner"
|
|
4
|
+
"paths": {
|
|
5
|
+
"modelCache": "~/.cache/huggingface"
|
|
8
6
|
},
|
|
9
7
|
"evaluation": {
|
|
10
8
|
"inference": {
|
|
11
|
-
"
|
|
9
|
+
"device": "cuda",
|
|
10
|
+
"maxNewTokens": 32,
|
|
11
|
+
"temperature": 0,
|
|
12
|
+
"topP": 1
|
|
12
13
|
},
|
|
13
14
|
"scoring": {
|
|
14
15
|
"mode": "exact_match"
|
|
15
16
|
},
|
|
16
|
-
"maxExamples": 2
|
|
17
|
+
"maxExamples": 2,
|
|
18
|
+
"timeoutMs": 1800000
|
|
17
19
|
}
|
|
18
20
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "22222222-2222-4222-8222-222222222222",
|
|
3
|
+
"name": "Local Smoke Assistant",
|
|
4
|
+
"description": "Tiny local runner smoke test.",
|
|
5
|
+
"system_prompt": "Return exactly one sentiment label.",
|
|
6
|
+
"guidelines": [
|
|
7
|
+
"Reply with positive or negative."
|
|
8
|
+
],
|
|
9
|
+
"constraints": [
|
|
10
|
+
"Do not include extra commentary."
|
|
11
|
+
],
|
|
12
|
+
"base_model": "Qwen/Qwen3.5-2B",
|
|
13
|
+
"examples": [
|
|
14
|
+
{
|
|
15
|
+
"input": "Classify sentiment: I love this product.",
|
|
16
|
+
"output": "positive"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"input": "Classify sentiment: This was disappointing.",
|
|
20
|
+
"output": "negative"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"input": "Classify sentiment: The update works perfectly.",
|
|
24
|
+
"output": "positive"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"input": "Classify sentiment: Support never replied.",
|
|
28
|
+
"output": "negative"
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"hyperparameters": {
|
|
32
|
+
"n_epochs": 1,
|
|
33
|
+
"learning_rate": 0.0002,
|
|
34
|
+
"batch_size": 1,
|
|
35
|
+
"gradient_accumulation_steps": 1,
|
|
36
|
+
"lora_rank": 4,
|
|
37
|
+
"lora_alpha": 8,
|
|
38
|
+
"max_seq_length": 256,
|
|
39
|
+
"max_eval_examples": 2
|
|
40
|
+
}
|
|
41
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tuned-tensor/local",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Local CUDA LoRA fine-tuning with held-out base-versus-tuned evaluation.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"private": false,
|
|
7
7
|
"repository": {
|
|
@@ -28,22 +28,22 @@
|
|
|
28
28
|
"LICENSE"
|
|
29
29
|
],
|
|
30
30
|
"scripts": {
|
|
31
|
-
"
|
|
31
|
+
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
32
|
+
"build": "npm run clean && tsc -p tsconfig.json",
|
|
32
33
|
"prepack": "npm run build",
|
|
33
34
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
34
|
-
"test": "node --import tsx --test \"test/**/*.test.ts\""
|
|
35
|
+
"test": "node --import tsx --test \"test/**/*.test.ts\"",
|
|
36
|
+
"test:python": "python3 -m unittest discover -s training/local-runner/tests -p 'test_*.py'"
|
|
35
37
|
},
|
|
36
38
|
"engines": {
|
|
37
39
|
"node": ">=22"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
|
-
"@types/better-sqlite3": "^7.6.13",
|
|
41
42
|
"@types/node": "^25.0.0",
|
|
42
43
|
"tsx": "^4.22.4",
|
|
43
44
|
"typescript": "^6.0.0"
|
|
44
45
|
},
|
|
45
46
|
"dependencies": {
|
|
46
|
-
"better-sqlite3": "^12.11.1",
|
|
47
47
|
"zod": "^4.4.3"
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -4,16 +4,11 @@ version = "0.1.0"
|
|
|
4
4
|
requires-python = ">=3.11"
|
|
5
5
|
dependencies = [
|
|
6
6
|
"accelerate>=1.0.0",
|
|
7
|
-
"datasets>=4.0.0",
|
|
8
7
|
"huggingface-hub>=0.36.0",
|
|
9
8
|
"peft>=0.13.0",
|
|
10
|
-
"pillow>=10.0.0",
|
|
11
|
-
"qwen-vl-utils>=0.0.14",
|
|
12
9
|
"safetensors>=0.4.5",
|
|
13
10
|
"torch>=2.11.0",
|
|
14
|
-
"torchvision>=0.24.0",
|
|
15
11
|
"transformers>=4.57.0",
|
|
16
|
-
"trl>=1.7.0",
|
|
17
12
|
]
|
|
18
13
|
|
|
19
14
|
[tool.uv.sources]
|