anthracite 1.0.0__tar.gz
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.
- anthracite-1.0.0/LICENSE +15 -0
- anthracite-1.0.0/MANIFEST.in +3 -0
- anthracite-1.0.0/PKG-INFO +500 -0
- anthracite-1.0.0/README.md +457 -0
- anthracite-1.0.0/anthracite/__init__.py +222 -0
- anthracite-1.0.0/anthracite/architectures/__init__.py +9 -0
- anthracite-1.0.0/anthracite/architectures/anthracite1_embedding.py +231 -0
- anthracite-1.0.0/anthracite/architectures/anthracite1_text.py +309 -0
- anthracite-1.0.0/anthracite/cli.py +161 -0
- anthracite-1.0.0/anthracite/core/__init__.py +4 -0
- anthracite-1.0.0/anthracite/core/config.py +209 -0
- anthracite-1.0.0/anthracite/core/exceptions.py +62 -0
- anthracite-1.0.0/anthracite/core/finetuner.py +292 -0
- anthracite-1.0.0/anthracite/core/registry.py +98 -0
- anthracite-1.0.0/anthracite/core/trainer.py +487 -0
- anthracite-1.0.0/anthracite/datasets/__init__.py +9 -0
- anthracite-1.0.0/anthracite/datasets/hf.py +58 -0
- anthracite-1.0.0/anthracite/datasets/loader.py +139 -0
- anthracite-1.0.0/anthracite/datasets/local.py +235 -0
- anthracite-1.0.0/anthracite/datasets/pairs.py +125 -0
- anthracite-1.0.0/anthracite/datasets/text.py +142 -0
- anthracite-1.0.0/anthracite/devices/__init__.py +3 -0
- anthracite-1.0.0/anthracite/devices/auto.py +147 -0
- anthracite-1.0.0/anthracite/devices/cpu.py +54 -0
- anthracite-1.0.0/anthracite/devices/cuda.py +69 -0
- anthracite-1.0.0/anthracite/devices/tpu.py +68 -0
- anthracite-1.0.0/anthracite/inference/__init__.py +13 -0
- anthracite-1.0.0/anthracite/inference/embedding.py +90 -0
- anthracite-1.0.0/anthracite/inference/loader.py +86 -0
- anthracite-1.0.0/anthracite/inference/text.py +64 -0
- anthracite-1.0.0/anthracite/interface/__init__.py +3 -0
- anthracite-1.0.0/anthracite/interface/generator.py +215 -0
- anthracite-1.0.0/anthracite/io/__init__.py +4 -0
- anthracite-1.0.0/anthracite/io/config.py +65 -0
- anthracite-1.0.0/anthracite/io/metadata.py +157 -0
- anthracite-1.0.0/anthracite/io/safetensors.py +147 -0
- anthracite-1.0.0/anthracite/tokenizer/__init__.py +5 -0
- anthracite-1.0.0/anthracite/tokenizer/builder.py +218 -0
- anthracite-1.0.0/anthracite/tokenizer/tokenizer.py +230 -0
- anthracite-1.0.0/anthracite/tokenizer/vocabulary.py +91 -0
- anthracite-1.0.0/anthracite/training/__init__.py +18 -0
- anthracite-1.0.0/anthracite/training/checkpoint.py +145 -0
- anthracite-1.0.0/anthracite/training/loop.py +227 -0
- anthracite-1.0.0/anthracite/training/memory.py +165 -0
- anthracite-1.0.0/anthracite/training/optimizer.py +38 -0
- anthracite-1.0.0/anthracite/training/precision.py +94 -0
- anthracite-1.0.0/anthracite/training/scheduler.py +64 -0
- anthracite-1.0.0/anthracite/utils/logging.py +105 -0
- anthracite-1.0.0/anthracite/utils/parameters.py +187 -0
- anthracite-1.0.0/anthracite/utils/progress.py +66 -0
- anthracite-1.0.0/anthracite/utils/seed.py +76 -0
- anthracite-1.0.0/anthracite.egg-info/PKG-INFO +500 -0
- anthracite-1.0.0/anthracite.egg-info/SOURCES.txt +67 -0
- anthracite-1.0.0/anthracite.egg-info/dependency_links.txt +1 -0
- anthracite-1.0.0/anthracite.egg-info/entry_points.txt +2 -0
- anthracite-1.0.0/anthracite.egg-info/requires.txt +27 -0
- anthracite-1.0.0/anthracite.egg-info/top_level.txt +1 -0
- anthracite-1.0.0/examples/01_train_text.py +17 -0
- anthracite-1.0.0/examples/02_finetune.py +11 -0
- anthracite-1.0.0/examples/03_generate.py +8 -0
- anthracite-1.0.0/examples/04_embedding_model.py +17 -0
- anthracite-1.0.0/examples/05_contrastive_finetune.py +20 -0
- anthracite-1.0.0/examples/06_embed_and_search.py +18 -0
- anthracite-1.0.0/examples/07_interface.py +5 -0
- anthracite-1.0.0/examples/08_huggingface_dataset.py +12 -0
- anthracite-1.0.0/examples/09_resume_training.py +11 -0
- anthracite-1.0.0/pyproject.toml +52 -0
- anthracite-1.0.0/setup.cfg +4 -0
- anthracite-1.0.0/tests/test_smoke.py +170 -0
anthracite-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Apache License 2.0
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nebulix Labs
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: anthracite
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Universal AI training & fine-tuning framework with its own Anthracite-1 architecture (text generation + embeddings)
|
|
5
|
+
Author: Nebulix Labs
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/nebulix-labs/anthracite
|
|
8
|
+
Project-URL: Issues, https://github.com/nebulix-labs/anthracite/issues
|
|
9
|
+
Keywords: machine-learning,training,fine-tuning,transformer,embeddings,llm,rag
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: torch>=2.1
|
|
22
|
+
Requires-Dist: numpy>=1.24
|
|
23
|
+
Requires-Dist: safetensors>=0.4
|
|
24
|
+
Requires-Dist: tokenizers>=0.15
|
|
25
|
+
Requires-Dist: tqdm>=4.65
|
|
26
|
+
Provides-Extra: hf
|
|
27
|
+
Requires-Dist: datasets>=2.14; extra == "hf"
|
|
28
|
+
Requires-Dist: huggingface_hub>=0.20; extra == "hf"
|
|
29
|
+
Provides-Extra: ui
|
|
30
|
+
Requires-Dist: gradio>=4.0; extra == "ui"
|
|
31
|
+
Provides-Extra: tpu
|
|
32
|
+
Requires-Dist: torch_xla>=2.1; extra == "tpu"
|
|
33
|
+
Provides-Extra: cuda
|
|
34
|
+
Requires-Dist: torch>=2.1; extra == "cuda"
|
|
35
|
+
Provides-Extra: all
|
|
36
|
+
Requires-Dist: datasets>=2.14; extra == "all"
|
|
37
|
+
Requires-Dist: huggingface_hub>=0.20; extra == "all"
|
|
38
|
+
Requires-Dist: gradio>=4.0; extra == "all"
|
|
39
|
+
Provides-Extra: dev
|
|
40
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
41
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
# Anthracite
|
|
45
|
+
|
|
46
|
+
**Universal AI training & fine-tuning framework** — one function call from a raw dataset to a packaged, ready-to-use model.
|
|
47
|
+
|
|
48
|
+
Anthracite is not a wrapper around anyone else's trainer. It ships its own configuration system, tokenizer builder, model architecture (**Anthracite-1**), training engine, memory manager, checkpoint system, packaging layer and inference loader.
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from anthracite import train
|
|
52
|
+
|
|
53
|
+
train(
|
|
54
|
+
model_name="Nutral-GPT-20M",
|
|
55
|
+
model_type="text_gen",
|
|
56
|
+
dataset="my_dataset.jsonl",
|
|
57
|
+
tokens=100_000_000,
|
|
58
|
+
params=20_000_000,
|
|
59
|
+
context_length=512,
|
|
60
|
+
device="auto",
|
|
61
|
+
batch_size="auto",
|
|
62
|
+
precision="auto",
|
|
63
|
+
)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
That single call loads and validates the dataset, trains a tokenizer, solves the architecture dimensions for your parameter budget, picks a device and precision, plans a safe batch size, trains with gradient accumulation and OOM recovery, checkpoints along the way, and writes a complete SafeTensors model package.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Install
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pip install anthracite
|
|
74
|
+
|
|
75
|
+
# optional extras
|
|
76
|
+
pip install anthracite[hf] # Hugging Face datasets + hub
|
|
77
|
+
pip install anthracite[ui] # gradio interfaces
|
|
78
|
+
pip install anthracite[tpu] # torch_xla
|
|
79
|
+
pip install anthracite[all]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
From source:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install -e .
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Python 3.10+.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Public API
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from anthracite import train, finetune, load_model, generate, create_interface
|
|
96
|
+
from anthracite import embed, similarity, search # embedding models
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
| function | purpose |
|
|
100
|
+
|---|---|
|
|
101
|
+
| `train(...)` | train a new model from scratch |
|
|
102
|
+
| `finetune(...)` | continue training an existing model |
|
|
103
|
+
| `load_model(...)` | load config + architecture + weights + tokenizer |
|
|
104
|
+
| `generate(...)` | text generation (`text_gen` models) |
|
|
105
|
+
| `embed(...)` / `similarity(...)` / `search(...)` | vectors, cosine scores, ranking (`embedding` models) |
|
|
106
|
+
| `create_interface(...)` | launch a UI built from the model's own config |
|
|
107
|
+
|
|
108
|
+
There is a CLI too:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
anthracite train --model-name MyModel --dataset ./data/train.jsonl --tokens 50M --params 10M
|
|
112
|
+
anthracite finetune --model ./models/MyModel --dataset ./data/instructions.jsonl --tokens 5M
|
|
113
|
+
anthracite generate --model ./models/MyModel --prompt "Hello"
|
|
114
|
+
anthracite embed --model ./models/MyEmbedder --text "hello" --text "hi there" --compare
|
|
115
|
+
anthracite interface --model ./models/MyModel
|
|
116
|
+
anthracite info
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Model types
|
|
122
|
+
|
|
123
|
+
| type | status | pipeline |
|
|
124
|
+
|---|---|---|
|
|
125
|
+
| `text_gen` | available | Anthracite-1 causal transformer (next-token prediction) |
|
|
126
|
+
| `embedding` | available | Anthracite-1 bidirectional encoder (MLM pretraining + contrastive fine-tuning) |
|
|
127
|
+
| `img_gen`, `vision`, `multimodal`, `audio`, `classification` | planned | register in `anthracite/core/registry.py` |
|
|
128
|
+
|
|
129
|
+
The two pipelines are genuinely separate. `text_gen` uses causal attention and a
|
|
130
|
+
next-token loss; `embedding` uses bidirectional attention, pooled vectors, and
|
|
131
|
+
either a masked-language-model or an InfoNCE contrastive loss. Neither
|
|
132
|
+
objective is applied to the other architecture.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Anthracite-1
|
|
137
|
+
|
|
138
|
+
**Text** (`architectures/anthracite1_text.py`)
|
|
139
|
+
|
|
140
|
+
* byte-level BPE token embeddings, tied to the output projection
|
|
141
|
+
* rotary positional representation (no learned position table)
|
|
142
|
+
* pre-norm residual blocks with RMSNorm
|
|
143
|
+
* grouped-query causal attention (smaller KV cache)
|
|
144
|
+
* SwiGLU feed-forward, 8/3 expansion rounded to a multiple of 64
|
|
145
|
+
* depth-scaled initialisation on residual output projections
|
|
146
|
+
|
|
147
|
+
**Embedding** (`architectures/anthracite1_embedding.py`)
|
|
148
|
+
|
|
149
|
+
* the same Anthracite-1 blocks, but attention is bidirectional
|
|
150
|
+
* masked mean / CLS / max pooling into a fixed-size vector, L2-normalised
|
|
151
|
+
* optional projection head (`embedding_dim=...`) when you want a smaller vector
|
|
152
|
+
* `mlm` objective for pretraining from raw text (80/10/10 masking)
|
|
153
|
+
* `contrastive` objective: symmetric InfoNCE with in-batch negatives and
|
|
154
|
+
optional hard negatives, temperature from `temperature=...`
|
|
155
|
+
|
|
156
|
+
You don't choose the architecture — it is fixed at `anthracite-1`. You choose the *size*:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
params="20M" # or params=40_000_000
|
|
160
|
+
context_length=512
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Anthracite searches width/depth combinations and picks the one whose analytic
|
|
164
|
+
parameter count lands closest to your request. Both the estimate and the exact
|
|
165
|
+
count end up in `metadata.json`.
|
|
166
|
+
|
|
167
|
+
Advanced users can override the solver:
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
train(..., d_model=512, n_layers=8, n_heads=8)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Datasets
|
|
176
|
+
|
|
177
|
+
Detected automatically:
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
dataset="HuggingFaceH4/ultrachat_200k" # Hugging Face id
|
|
181
|
+
dataset="./data/train.json" # JSON array
|
|
182
|
+
dataset="./data/train.jsonl" # JSONL
|
|
183
|
+
dataset="./data/corpus.txt" # plain text
|
|
184
|
+
dataset="./data/data.csv" # CSV / TSV
|
|
185
|
+
dataset="./dataset/" # directory (recursive)
|
|
186
|
+
dataset=my_hf_dataset # Hugging Face Dataset object
|
|
187
|
+
dataset=["some text", "more text"] # list of strings
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Records are unwrapped intelligently: `text` / `content` / `body` columns,
|
|
191
|
+
`instruction`+`input`+`output`, `prompt`+`completion`, and chat formats
|
|
192
|
+
(`messages`, `conversations`) all work without configuration.
|
|
193
|
+
|
|
194
|
+
For contrastive embedding training, records need two text columns. Anthracite
|
|
195
|
+
auto-detects the usual names:
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{"anchor": "how do i reset my password", "positive": "password reset instructions"}
|
|
199
|
+
{"query": "...", "positive": "...", "negative": "..."}
|
|
200
|
+
{"question": "...", "answer": "..."}
|
|
201
|
+
{"sentence1": "...", "sentence2": "..."}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
If a dataset has no pair columns, an `embedding` run falls back to MLM
|
|
205
|
+
pretraining. Force either one with `objective="mlm"` / `objective="contrastive"`.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Embedding models (the two-stage recipe)
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
from anthracite import train, finetune, embed, similarity, search
|
|
213
|
+
|
|
214
|
+
# stage 1 – pretrain the encoder on raw text (masked language modelling)
|
|
215
|
+
train(
|
|
216
|
+
model_name="MyEmbedder",
|
|
217
|
+
model_type="embedding",
|
|
218
|
+
dataset="./data/corpus.jsonl",
|
|
219
|
+
tokens=50_000_000,
|
|
220
|
+
params="30M",
|
|
221
|
+
context_length=256,
|
|
222
|
+
objective="mlm", # or leave it on "auto"
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
# stage 2 – turn it into a retrieval model on (anchor, positive) pairs
|
|
226
|
+
finetune(
|
|
227
|
+
model="./models/MyEmbedder",
|
|
228
|
+
dataset="./data/pairs.jsonl",
|
|
229
|
+
tokens=10_000_000,
|
|
230
|
+
objective="contrastive", # auto-detected from the pair columns
|
|
231
|
+
batch_size=32, # bigger batches = more in-batch negatives
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
# use it
|
|
235
|
+
model = "./models/MyEmbedder-Finetuned"
|
|
236
|
+
print(similarity(model, "how do i reset my password", "password reset instructions"))
|
|
237
|
+
print(search(model, "refund policy", documents, top_k=3))
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Useful knobs: `embedding_dim` (projection size; `0` keeps `d_model`),
|
|
241
|
+
`pooling` (`mean` / `cls` / `max`), `temperature` (InfoNCE, default `0.05`),
|
|
242
|
+
`mlm_probability` (default `0.15`) and `max_sequence_length` (truncation for
|
|
243
|
+
pair training).
|
|
244
|
+
|
|
245
|
+
`embed()` always returns L2-normalised vectors, so a dot product *is* the
|
|
246
|
+
cosine similarity.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Token budget
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
tokens=500_000_000
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
The corpus is tokenized until the budget is reached; training never exceeds it.
|
|
257
|
+
Progress shows `Tokens: 125M / 500M`, and the run records:
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
{ "requested_tokens": 500000000, "processed_tokens": 498734592 }
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Contrastive pairs are billed as the tokens of every encoded view
|
|
264
|
+
(anchor + positive, plus the negative when present), so the same `tokens=` knob
|
|
265
|
+
means the same thing in both pipelines.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Devices
|
|
270
|
+
|
|
271
|
+
```python
|
|
272
|
+
device="auto" # cuda → tpu → cpu
|
|
273
|
+
device="cpu"
|
|
274
|
+
device="cuda"
|
|
275
|
+
device="cuda:1"
|
|
276
|
+
device="tpu"
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
`auto` is the default. An explicit choice is always respected — and if it is
|
|
280
|
+
impossible you get a clear error rather than a silent fallback:
|
|
281
|
+
|
|
282
|
+
```text
|
|
283
|
+
AnthraciteError:
|
|
284
|
+
TPU was requested but no supported TPU runtime was detected.
|
|
285
|
+
→ Install torch_xla (pip install anthracite[tpu]) or use device='auto'.
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
The TPU backend lives in `devices/tpu.py` and is completely independent of the
|
|
289
|
+
CPU and CUDA paths.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Batch size, OOM protection and precision
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
batch_size="auto" # or batch_size=8 — OOM protection stays on either way
|
|
297
|
+
precision="auto" # or "fp32" / "fp16" / "bf16"
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
```text
|
|
301
|
+
Requested batch size: auto
|
|
302
|
+
|
|
303
|
+
Detected VRAM: 15.2 GB (14.8 GB free)
|
|
304
|
+
|
|
305
|
+
Selected:
|
|
306
|
+
micro_batch_size = 4
|
|
307
|
+
gradient_accumulation = 8
|
|
308
|
+
effective_batch_size = 32
|
|
309
|
+
precision = BF16
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
On an out-of-memory error Anthracite halves the micro batch, doubles gradient
|
|
313
|
+
accumulation (so the effective batch is unchanged), rebuilds the loader and
|
|
314
|
+
continues — repeatedly, down to a micro batch of 1, and only then raises
|
|
315
|
+
`InsufficientMemoryError`. Unsupported precisions fall back gracefully with a
|
|
316
|
+
warning.
|
|
317
|
+
|
|
318
|
+
Before the first step it prints a pre-flight check:
|
|
319
|
+
|
|
320
|
+
```text
|
|
321
|
+
Configuration validated.
|
|
322
|
+
Estimated memory: 3.7 GB
|
|
323
|
+
Available memory: 7.8 GB
|
|
324
|
+
Configuration: SAFE
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Tokenizer
|
|
330
|
+
|
|
331
|
+
Every model gets its own tokenizer — you never have to supply one.
|
|
332
|
+
|
|
333
|
+
```python
|
|
334
|
+
vocab_size=32768 # default
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Byte-level BPE with `<BOS>`, `<EOS>`, `<PAD>`, `<UNK>` at fixed ids. Training
|
|
338
|
+
uses the Rust `tokenizers` library when it is installed and a self-contained
|
|
339
|
+
pure-Python BPE trainer otherwise; both write the same `tokenizer.json`.
|
|
340
|
+
|
|
341
|
+
```python
|
|
342
|
+
from anthracite import AnthraciteTokenizer
|
|
343
|
+
|
|
344
|
+
tok = AnthraciteTokenizer.train(["some corpus"], vocab_size=4096)
|
|
345
|
+
tok.save("./my-tokenizer")
|
|
346
|
+
tok = AnthraciteTokenizer.load("./my-tokenizer")
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## Output layout
|
|
352
|
+
|
|
353
|
+
```text
|
|
354
|
+
Nutral-GPT-20M/
|
|
355
|
+
├── model.safetensors
|
|
356
|
+
├── config.json
|
|
357
|
+
├── tokenizer.json
|
|
358
|
+
├── tokenizer_config.json
|
|
359
|
+
├── special_tokens_map.json
|
|
360
|
+
├── training_config.json
|
|
361
|
+
├── training_state.json
|
|
362
|
+
├── metrics.json
|
|
363
|
+
├── metadata.json
|
|
364
|
+
├── README.md ← generated model card
|
|
365
|
+
├── final/ ← inference-only copy (no optimizer state)
|
|
366
|
+
└── checkpoints/
|
|
367
|
+
├── checkpoint-10000/
|
|
368
|
+
├── checkpoint-20000/
|
|
369
|
+
└── checkpoint-final/
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
`metadata.json`:
|
|
373
|
+
|
|
374
|
+
```json
|
|
375
|
+
{
|
|
376
|
+
"name": "Nutral-GPT-20M",
|
|
377
|
+
"architecture": "anthracite-1",
|
|
378
|
+
"model_type": "text_gen",
|
|
379
|
+
"parameters": 20123456,
|
|
380
|
+
"context_length": 512,
|
|
381
|
+
"vocab_size": 32768,
|
|
382
|
+
"tokens_trained": 100000000,
|
|
383
|
+
"device": "cuda",
|
|
384
|
+
"precision": "bf16",
|
|
385
|
+
"dataset": "local_dataset",
|
|
386
|
+
"framework": "Anthracite",
|
|
387
|
+
"anthracite_version": "1.0.0"
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## Checkpoints & resume
|
|
394
|
+
|
|
395
|
+
```python
|
|
396
|
+
train(..., checkpoint_interval=5000, keep_last_checkpoints=3)
|
|
397
|
+
|
|
398
|
+
train(..., resume=True) # newest checkpoint
|
|
399
|
+
train(..., resume="./models/M/checkpoints/checkpoint-10000")
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Checkpoints carry optimizer state, scheduler state, step, token count, RNG
|
|
403
|
+
state and the full configuration. The final model directory deliberately
|
|
404
|
+
excludes optimizer state.
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## Fine-tuning
|
|
409
|
+
|
|
410
|
+
```python
|
|
411
|
+
from anthracite import finetune
|
|
412
|
+
|
|
413
|
+
finetune(
|
|
414
|
+
model="./models/Nutral-GPT-20M", # local dir, checkpoint dir, or HF repo id
|
|
415
|
+
dataset="./data/instructions.jsonl",
|
|
416
|
+
tokens=20_000_000,
|
|
417
|
+
device="auto",
|
|
418
|
+
)
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
The base architecture is preserved and read from the model's own `config.json`;
|
|
422
|
+
the base tokenizer is reused and checked for compatibility (a mismatch raises
|
|
423
|
+
`TokenizerError` rather than silently corrupting the embeddings). The base model
|
|
424
|
+
is never overwritten — output goes to `Nutral-GPT-20M-Finetuned` unless you pass
|
|
425
|
+
`output_dir`.
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## Generation
|
|
430
|
+
|
|
431
|
+
```python
|
|
432
|
+
from anthracite import generate, embed, similarity, search
|
|
433
|
+
|
|
434
|
+
text = generate(model="./models/Nutral-GPT-20M", prompt="Hello, my name is", max_tokens=100)
|
|
435
|
+
|
|
436
|
+
vectors = embed("./models/MyEmbedder", ["first sentence", "second sentence"]) # (2, dim)
|
|
437
|
+
score = similarity("./models/MyEmbedder", "how do i reset my password",
|
|
438
|
+
"password reset instructions")
|
|
439
|
+
hits = search("./models/MyEmbedder", "refund policy", documents, top_k=3)
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
Interfaces are generated from the model config:
|
|
443
|
+
|
|
444
|
+
```python
|
|
445
|
+
from anthracite import create_interface
|
|
446
|
+
|
|
447
|
+
create_interface(model="./models/Nutral-GPT-20M")
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
The text UI exposes prompt, temperature, top-p and max tokens. The embedding UI
|
|
451
|
+
gives a similarity tab and a search tab (query + documents + top-k).
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## Reproducibility
|
|
456
|
+
|
|
457
|
+
```python
|
|
458
|
+
train(..., seed=42, deterministic=True)
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
Seeds Python, NumPy, PyTorch and CUDA; the seed is stored in the metadata and
|
|
462
|
+
the RNG state travels with every checkpoint.
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
## Errors
|
|
467
|
+
|
|
468
|
+
All errors derive from `AnthraciteError` and carry an actionable hint:
|
|
469
|
+
|
|
470
|
+
`DatasetNotFoundError`, `UnsupportedDatasetError`, `UnsupportedModelTypeError`,
|
|
471
|
+
`TokenizerError`, `ArchitectureError`, `DeviceError`, `TPUNotAvailableError`,
|
|
472
|
+
`InsufficientMemoryError`, `InvalidConfigurationError`, `CheckpointError`,
|
|
473
|
+
`GenerationError`.
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## Project layout
|
|
478
|
+
|
|
479
|
+
```text
|
|
480
|
+
anthracite/
|
|
481
|
+
├── __init__.py public API
|
|
482
|
+
├── cli.py
|
|
483
|
+
├── core/ trainer, finetuner, config, registry, exceptions
|
|
484
|
+
├── architectures/ anthracite1_text.py, anthracite1_embedding.py
|
|
485
|
+
├── tokenizer/ builder.py, tokenizer.py, vocabulary.py
|
|
486
|
+
├── datasets/ loader.py, hf.py, local.py, text.py, pairs.py
|
|
487
|
+
├── training/ loop.py, optimizer.py, scheduler.py, precision.py, memory.py, checkpoint.py
|
|
488
|
+
├── devices/ cpu.py, cuda.py, tpu.py, auto.py
|
|
489
|
+
├── io/ safetensors.py, config.py, metadata.py
|
|
490
|
+
├── inference/ loader.py, text.py, embedding.py
|
|
491
|
+
├── interface/ generator.py
|
|
492
|
+
└── utils/ logging.py, seed.py, parameters.py, progress.py
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
Adding a new model type means one `registry.register(...)` call plus an
|
|
496
|
+
architecture module — the API, checkpointing, IO and CLI need no changes.
|
|
497
|
+
|
|
498
|
+
## License
|
|
499
|
+
|
|
500
|
+
Apache-2.0
|