neurarch 0.0.0-stage → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,96 @@
1
+ Sustainable Use License
2
+
3
+ Version 1.0
4
+
5
+ ## Acceptance
6
+
7
+ By using the software, you agree to all of the terms and conditions below.
8
+
9
+ ## Copyright License
10
+
11
+ The licensor grants you a non-exclusive, royalty-free, worldwide,
12
+ non-sublicensable, non-transferable license to use, copy, distribute, make
13
+ available, and prepare derivative works of the software, in each case subject
14
+ to the limitations below.
15
+
16
+ ## Limitations
17
+
18
+ You may use or modify the software only for your own internal business purposes
19
+ or for non-commercial or personal use. You may distribute the software or
20
+ provide it to others only if you do so free of charge for non-commercial
21
+ purposes. You may not alter, remove, or obscure any licensing, copyright, or
22
+ other notices of the licensor in the software. Any use of the licensor's
23
+ trademarks is subject to applicable law.
24
+
25
+ ## Patents
26
+
27
+ The licensor grants you a license, under any patent claims the licensor can
28
+ license, or becomes able to license, to make, have made, use, sell, offer for
29
+ sale, import and have imported the software, in each case subject to the
30
+ limitations and conditions in this license. This license does not cover any
31
+ patent claims that you cause to be infringed by modifications or additions to
32
+ the software. If you or your company make any written claim that the software
33
+ infringes or contributes to infringement of any patent, your patent license for
34
+ the software granted under these terms ends immediately. If your company makes
35
+ such a claim, your patent license ends immediately for work on behalf of your
36
+ company.
37
+
38
+ ## Notices
39
+
40
+ You must ensure that anyone who gets a copy of any part of the software from you
41
+ also gets a copy of these terms.
42
+
43
+ If you modify the software, you must include in any modified copies of the
44
+ software prominent notices stating that you have modified the software.
45
+
46
+ ## No Other Rights
47
+
48
+ These terms do not imply any licenses other than those expressly granted in
49
+ these terms.
50
+
51
+ ## Termination
52
+
53
+ If you use the software in violation of these terms, such use is not licensed,
54
+ and your licenses will automatically terminate. If the licensor provides you
55
+ with a notice of your violation, and you cease all violation of this license no
56
+ later than 30 days after you receive that notice, your licenses will be
57
+ reinstated retroactively. However, if you violate these terms after such
58
+ reinstatement, any additional violation of these terms will cause your licenses
59
+ to terminate automatically and permanently.
60
+
61
+ ## No Liability
62
+
63
+ As far as the law allows, the software comes as is, without any warranty or
64
+ condition, and the licensor will not be liable to you for any damages arising
65
+ out of these terms or the use or nature of the software, under any kind of
66
+ legal claim.
67
+
68
+ ## Definitions
69
+
70
+ The "licensor" is the entity offering these terms.
71
+
72
+ The "software" is the software the licensor makes available under these terms,
73
+ including any portion of it.
74
+
75
+ "You" refers to the individual or entity agreeing to these terms.
76
+
77
+ "Your company" is any legal entity, sole proprietorship, or other kind of
78
+ organization that you work for, plus all organizations that have control over,
79
+ are under the control of, or are under common control with that organization.
80
+ "Control" means ownership of substantially all the assets of an entity, or the
81
+ power to direct its management and policies by vote, contract, or otherwise.
82
+ Control can be direct or indirect.
83
+
84
+ "Your licenses" are all the licenses granted to you for the software under these
85
+ terms.
86
+
87
+ "Use" means anything you do with the software requiring one of your licenses.
88
+
89
+ "Trademark" means trademarks, service marks, and similar rights.
90
+
91
+ ---
92
+
93
+ Copyright (c) 2026 neurarch-ai
94
+
95
+ This license is adapted from the Sustainable Use License, which is published by
96
+ n8n GmbH under CC BY-SA 4.0 and is intended to be reused.
package/README.md CHANGED
@@ -1,3 +1,261 @@
1
- # Temporary Holding Version
1
+ # neurarch
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ What a GPU training job needs before it takes a reservation: the peak memory at
4
+ its batch, the smallest card that holds it, and what one run costs, read from a
5
+ Hugging Face `config.json` (or a traced graph). No account, no download, no GPU.
6
+
7
+ ```
8
+ npx neurarch rightsize jobs.csv # each past job's request next to what it needed
9
+ npx neurarch Qwen/Qwen3-8B --batch 8 # the training peak for one model
10
+ npx neurarch oom error.txt --model Qwen/Qwen3-8B --batch 8 # why it ran out of memory, and the least invasive fix
11
+ npx neurarch Qwen/Qwen3-8B --inference --batch 4 --seq-len 4096 --gen 512 # weights + KV cache for a generation job
12
+ ```
13
+
14
+ The memory number is calibrated against measured runs, and every run is public
15
+ next to `accelerate estimate-memory`: <https://neurarch.com/memory-calibration.html>.
16
+
17
+ It also reads any Hugging Face model as an architecture:
18
+
19
+ ```
20
+ npx neurarch microsoft/Phi-3-mini-4k-instruct
21
+ ```
22
+
23
+ ```
24
+ microsoft/Phi-3-mini-4k-instruct phi3 · text-generation
25
+
26
+ published (safetensors.total) 3.82B 3,821,079,552
27
+ derived (config.json alone) 3.82B 3,821,111,616
28
+ difference +0.00% within 2%: the reconstruction matches the checkpoint
29
+
30
+ layers (198, showing 12; --layers for all)
31
+ 1 Input Input 1 × 4096
32
+ 2 Embedding Embedding 1 × 4096 × 3072
33
+ ...
34
+
35
+ checks clean
36
+ ```
37
+
38
+ ## The number this exists to print
39
+
40
+ The second one. `derived` is computed from `config.json` alone: the layer graph
41
+ is reconstructed from the config, shapes are propagated through it, and the
42
+ parameters are counted. `published` is `safetensors.total` from the Hub API,
43
+ the scalars actually stored in the weight files.
44
+
45
+ They come from different places, so the gap between them is the only honest
46
+ statement about whether the reconstruction is worth anything. Everything else
47
+ the tool prints, the layer table and the checks, is downstream of that.
48
+
49
+ The tolerance is 2%, chosen before the numbers were looked at because it is
50
+ smaller than one layer in every model in the reference set. Agreement across
51
+ the published set lives at <https://neurarch.com/m/>.
52
+
53
+ ## What one training run would cost
54
+
55
+ ```
56
+ npx neurarch bert-base-uncased --data 3M --gpu h100-80gb
57
+ ```
58
+
59
+ ```
60
+ one training run over 3,000,000 samples
61
+ quoted $31 on H100 (80GB), 8.0 h
62
+ fits T4 A100_40 H100_80 (training peak ~4.2 GB at batch 32, 512 tokens, 1.15x headroom)
63
+ tokens 512 assumed (default 2048, or the context if shorter); --seq-len to change
64
+ attention SDPA, scores not stored; eager would add 8.4 GB
65
+ derived, not measured: nothing here was trained
66
+ ```
67
+
68
+ `--data` is the size of YOUR training set (`3M`, `500k`, `2B`). It is required
69
+ for a price, and that is deliberate: with no workload the estimate defaults to
70
+ 50,000 rows, which is nobody's training set and would make the largest number
71
+ on the screen the one nobody stated. Same model, same card, three sizes:
72
+
73
+ | `--data` | quoted | wall clock |
74
+ |---|---|---|
75
+ | 50k | $0.59 | 0.1 h |
76
+ | 3M | $31 | 8.0 h |
77
+ | 40M | $418 | 4.4 days |
78
+
79
+ `--gpu` is one of `t4-16gb`, `l4-24gb`, `a10g-24gb`, `l40s-48gb`, `a100-40gb`,
80
+ `a100-80gb`, `h100-80gb`; a prefix works when it is unambiguous (`t4`, `h100`),
81
+ and `a100` is refused with both options rather than resolved by array order.
82
+
83
+ `--batch 8` sizes the training peak at that batch (default 32). `--attention` is
84
+ `sdpa` (the default, and Hugging Face's own), `flash` or `eager`. Only eager
85
+ keeps the attention score matrices for backward, so only eager adds them to the
86
+ peak; under the other two the line says how many GB eager would add. On a token
87
+ model at 2048 tokens that term is most of the activation memory, so it is worth
88
+ setting when your training script sets `attn_implementation="eager"`. The
89
+ same option is the `attention` field on `POST /api/v1/plan` and the `attention`
90
+ column of `rightsize`, so all three size one model the same way.
91
+
92
+ `--seq-len 8192` sizes a text model at that many tokens per sample. The default
93
+ is 2048, or the model's context when that is shorter (BERT: 512). It is not
94
+ `max_position_embeddings`: that is the longest input the model accepts, and
95
+ Qwen3-0.6B declares 40,960, which put a ~191 GB peak at batch 8 on a model
96
+ people fine-tune on one card. At 2048 tokens the same line reads ~21 GB. The
97
+ default is the one `rightsize` uses for a blank `seq_len` and the `seq_len`
98
+ field on `POST /api/v1/plan` (which the MCP `plan` tool calls), and the line
99
+ always says the length it used. `--batch`, `--seq-len` or `--attention` without
100
+ `--data` print the training peak with no price.
101
+
102
+ `--inference` sizes a generation job instead: weights at `--precision` (bf16 by
103
+ default; fp16, fp32, int8, int4) plus the KV cache at the last generated token,
104
+ `--seq-len` prompt tokens plus `--gen` generated ones (default 256) at `--batch`
105
+ (default 1), with the same 1.15x headroom. The KV cache is the same per-token
106
+ formula the change record's serving line uses. It has no activation term, and it
107
+ prints what that leaves out (the prefill working set and prompt logits, the CUDA
108
+ context and any framework reserve). `npx neurarch oom --inference` compares an
109
+ error against this peak instead of the training one.
110
+
111
+ A repo with no safetensors index (InternLM-7B, xlnet-large-cased) has no
112
+ published count, so the plain read refuses it. With any sizing flag it is still
113
+ sized from `config.json`, under a line saying there was nothing to compare.
114
+
115
+ Everything in that block is arithmetic over the reconstructed graph at list GPU
116
+ prices. Nothing was trained and nothing was measured, which is why the verb is
117
+ "quoted": what it is good for is deciding whether to start the run, not
118
+ predicting what comes out of it.
119
+
120
+ ## Which modules a LoRA can sit on
121
+
122
+ ```
123
+ npx neurarch Qwen/Qwen3-0.6B --lora-targets
124
+ ```
125
+
126
+ ```
127
+ LoRA targets base 596.0M params, 196 linear modules
128
+ attention r=8 +2.3M (0.38%) r=16 +4.6M (0.77%) over 112 modules
129
+ target_modules=["q_proj","k_proj","v_proj","o_proj"]
130
+ all-linear r=8 +5.0M (0.85%) r=16 +10.1M (1.69%) over 196 modules
131
+ target_modules=["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj","down_proj"]
132
+ by role q_proj 28 · k_proj 28 · v_proj 28 · o_proj 28 · gate 28 · up 28 · down 28
133
+ ```
134
+
135
+ Every Linear in the reconstructed graph, with attention opened into its q, k,
136
+ v and o projections (GQA's narrower k and v included) and SwiGLU into gate, up
137
+ and down. A rank-r adapter adds r x (in + out) per module; the output head is
138
+ left out of all-linear, as PEFT does. `--json --lora-targets` returns the
139
+ per-module list. It says what each preset costs, not which one trains better.
140
+
141
+ ## Requested vs needed, over your past jobs
142
+
143
+ ```
144
+ npx neurarch rightsize jobs.csv --out report.md
145
+ ```
146
+
147
+ ```
148
+ 6 jobs, 174 GPU-hours, $507.85 spent; a right-sized request would have saved $404.64 (80% of spend), claiming nothing on 1 row marked under or unknown.
149
+ ```
150
+
151
+ For each job in the CSV: what it requested (card x count), what it needed
152
+ (the training peak the plan predicts at that batch), the smallest card that
153
+ holds it, a verdict, and the dollars a right-sized request would have saved
154
+ over the hours the reservation was held.
155
+
156
+ | verdict | means |
157
+ |---|---|
158
+ | `right-sized` | the request is the smallest capacity that holds the peak with 1.15x headroom, or one size up |
159
+ | `over` | a smaller card or fewer cards would have held it; the saving is priced on the cheapest one that does |
160
+ | `under` | the predicted peak does not fit what was requested: the job OOMed or relied on something the graph does not declare. No saving claimed |
161
+ | `unknown` | no graph (bad id, unreadable config, a card name it cannot resolve); the row says why. No saving claimed |
162
+
163
+ The CSV has a header row; column order is free. A sample is in
164
+ [`examples/jobs.sample.csv`](examples/jobs.sample.csv):
165
+
166
+ ```csv
167
+ job_id,model,gpu,batch,hours,seq_len,lora_rank
168
+ ft-qwen-small,Qwen/Qwen3-0.6B,8xH100,8,6,2048,
169
+ lora-qwen-8b,Qwen/Qwen3-8B,A100-80,4,12,2048,16
170
+ bert-classifier,bert-base-uncased,A100-80,32,3,512,
171
+ tinyllama-lora,TinyLlama/TinyLlama-1.1B-Chat-v1.0,H100,8,5,2048,8
172
+ phi3-sft,microsoft/Phi-3-mini-4k-instruct,A100-40,8,10,4096,
173
+ gpt2-pretrain,openai-community/gpt2,4xA100-80,16,24,1024,
174
+ ```
175
+
176
+ | column | required | |
177
+ |---|---|---|
178
+ | `job_id` | yes | any label |
179
+ | `model` | yes | a Hugging Face id, or a path to a `.neurarch.json` graph written by `neurarch-trace` |
180
+ | `gpu` | yes | `T4`, `L4`, `A10G`, `A100-40`, `A100-80`, `L40S`, `H100`, `H200`, or a count like `8xH100`. A bare `A100` is refused: the two differ by 2x in memory |
181
+ | `gpus` | no | card count, instead of `8xH100` |
182
+ | `hours` | yes | wall hours the job held the reservation |
183
+ | `batch` | no | per-device batch, default 32 |
184
+ | `seq_len` | no | sequence length for token models; default 2048, or the model's context if shorter |
185
+ | `lora_rank` | no | size the base frozen in bf16 (2 bytes per parameter) and only adapters (on every Linear but the head) as trainable |
186
+ | `attention` | no | `sdpa` (default), `flash` or `eager`. Only eager keeps the attention score matrices for backward |
187
+
188
+ `--prices prices.json` overrides the default list prices per GPU-hour
189
+ (`{"H100": 2.49, "A100-80": 1.79}`); cards it does not name keep theirs, and the
190
+ report says which were overridden. `--json` returns every row with the plan's
191
+ own `peakGb`, `smallestFitGpu`, `maxBatch` and `twoCardSplit`, plus `upperNeedGb` and
192
+ `fit`: a row whose capacity holds the estimate but not the conservative peak (the
193
+ estimate x 1.43, at or above the measured peak on 95% of held-out runs) is
194
+ `borderline`, says "measure once", and claims as not needed only what the
195
+ conservative peak would free.
196
+
197
+ **Three answers per card.** The training block prints each card green (the
198
+ conservative peak with 1.15x headroom fits), yellow `borderline` (the estimate
199
+ fits, the conservative peak does not: measure one step first) or red (the estimate
200
+ alone is past the card), then the upper bound, the largest batch it fits, and how
201
+ many copies of it fit each card and the smallest MIG slice on A100 / H100 (memory
202
+ only: compute and bandwidth are not considered). `--json` carries the same as
203
+ `cost.peakGbUpper`, `cost.upperBound`, `cost.gpuVerdict`, `cost.maxBatchSafe` and
204
+ `cost.shareable`; `cost.gpuFits` is unchanged.
205
+
206
+ **The memory model.** The peak is `buildPlan`'s training peak under AdamW with
207
+ bf16 autocast: weights, gradients and optimizer state plus activations (every
208
+ layer's output, the intermediates inside each layer, recurrent gate states, the
209
+ largest tensor's backward copy and, under eager attention, stored scores),
210
+ fitted on 178 measured runs. Held out one architecture at a time, the median
211
+ error is 7% on runs of 1 GB or more and it flagged 113 of the 131 times a run
212
+ did not fit a card; on 25 runs at the edge of a 24 GB card measured after the
213
+ fit, the median miss is 14%. Inference jobs and other optimizers will differ. A multi-card job
214
+ is sized as one model sharded across its cards (FSDP / ZeRO-3): the peak at the
215
+ global batch against the summed capacity. Default prices are Modal's on-demand
216
+ list prices, the same table the Neurarch app prices training with.
217
+
218
+ **What it does not know**: data loader memory, custom kernels beyond the
219
+ attention column, activation checkpointing (a checkpointed job needs less),
220
+ multi-node communication buffers, and throughput: the saving assumes the same
221
+ wall hours, so a request cut from 8 cards to 1 is capacity reserved and not
222
+ needed, not a promise the same job finishes as fast. The report prints all of
223
+ this next to the numbers.
224
+
225
+ ## What it refuses to do
226
+
227
+ - **No safetensors index on the Hub** → it prints nothing and says so. A
228
+ derived count with nothing to check it against looks authoritative and means
229
+ nothing.
230
+ - **A quantized checkpoint** → the counts are reported and explicitly marked
231
+ not comparable. Packed storage counts stored elements under a packing scheme,
232
+ not logical parameters, so the delta measures the packing, not us.
233
+ - **A multi-tower config** (CLIP, LLaVA) → same, with the sub-models named. The
234
+ checkpoint carries every tower; the graph carries what the reader
235
+ reconstructs, so a gap is a statement about what we read.
236
+ - **Weight sharing** (`num_hidden_groups`) → the graph counts blocks in the
237
+ forward pass, so a structural count is necessarily larger than the file.
238
+
239
+ ## Usage
240
+
241
+ ```
242
+ npx neurarch <model-id> # bert-base-uncased, Qwen/Qwen3-8B, ...
243
+ npx neurarch <model-id> --layers # every layer, not the first 12
244
+ npx neurarch <model-id> --json # machine-readable
245
+ npx neurarch rightsize jobs.csv # requested vs needed GPU over past jobs
246
+ ```
247
+
248
+ Exit code is `1` when the model cannot be read or a check blocks, `0`
249
+ otherwise, so it composes in a script.
250
+
251
+ Set `HF_TOKEN` to read a gated repo. The token is sent only to
252
+ `huggingface.co`. Nothing is uploaded anywhere and nothing is stored.
253
+
254
+ ## Related
255
+
256
+ - <https://neurarch.com/compare> — the same comparison for two models, in a
257
+ browser, no account
258
+ - `POST https://www.neurarch.com/api/v1/check` — run the checks on a graph of
259
+ your own
260
+ - [`neurarch-lint`](https://www.npmjs.com/package/neurarch-lint) — the same
261
+ checks against PyTorch source