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.
Files changed (69) hide show
  1. anthracite-1.0.0/LICENSE +15 -0
  2. anthracite-1.0.0/MANIFEST.in +3 -0
  3. anthracite-1.0.0/PKG-INFO +500 -0
  4. anthracite-1.0.0/README.md +457 -0
  5. anthracite-1.0.0/anthracite/__init__.py +222 -0
  6. anthracite-1.0.0/anthracite/architectures/__init__.py +9 -0
  7. anthracite-1.0.0/anthracite/architectures/anthracite1_embedding.py +231 -0
  8. anthracite-1.0.0/anthracite/architectures/anthracite1_text.py +309 -0
  9. anthracite-1.0.0/anthracite/cli.py +161 -0
  10. anthracite-1.0.0/anthracite/core/__init__.py +4 -0
  11. anthracite-1.0.0/anthracite/core/config.py +209 -0
  12. anthracite-1.0.0/anthracite/core/exceptions.py +62 -0
  13. anthracite-1.0.0/anthracite/core/finetuner.py +292 -0
  14. anthracite-1.0.0/anthracite/core/registry.py +98 -0
  15. anthracite-1.0.0/anthracite/core/trainer.py +487 -0
  16. anthracite-1.0.0/anthracite/datasets/__init__.py +9 -0
  17. anthracite-1.0.0/anthracite/datasets/hf.py +58 -0
  18. anthracite-1.0.0/anthracite/datasets/loader.py +139 -0
  19. anthracite-1.0.0/anthracite/datasets/local.py +235 -0
  20. anthracite-1.0.0/anthracite/datasets/pairs.py +125 -0
  21. anthracite-1.0.0/anthracite/datasets/text.py +142 -0
  22. anthracite-1.0.0/anthracite/devices/__init__.py +3 -0
  23. anthracite-1.0.0/anthracite/devices/auto.py +147 -0
  24. anthracite-1.0.0/anthracite/devices/cpu.py +54 -0
  25. anthracite-1.0.0/anthracite/devices/cuda.py +69 -0
  26. anthracite-1.0.0/anthracite/devices/tpu.py +68 -0
  27. anthracite-1.0.0/anthracite/inference/__init__.py +13 -0
  28. anthracite-1.0.0/anthracite/inference/embedding.py +90 -0
  29. anthracite-1.0.0/anthracite/inference/loader.py +86 -0
  30. anthracite-1.0.0/anthracite/inference/text.py +64 -0
  31. anthracite-1.0.0/anthracite/interface/__init__.py +3 -0
  32. anthracite-1.0.0/anthracite/interface/generator.py +215 -0
  33. anthracite-1.0.0/anthracite/io/__init__.py +4 -0
  34. anthracite-1.0.0/anthracite/io/config.py +65 -0
  35. anthracite-1.0.0/anthracite/io/metadata.py +157 -0
  36. anthracite-1.0.0/anthracite/io/safetensors.py +147 -0
  37. anthracite-1.0.0/anthracite/tokenizer/__init__.py +5 -0
  38. anthracite-1.0.0/anthracite/tokenizer/builder.py +218 -0
  39. anthracite-1.0.0/anthracite/tokenizer/tokenizer.py +230 -0
  40. anthracite-1.0.0/anthracite/tokenizer/vocabulary.py +91 -0
  41. anthracite-1.0.0/anthracite/training/__init__.py +18 -0
  42. anthracite-1.0.0/anthracite/training/checkpoint.py +145 -0
  43. anthracite-1.0.0/anthracite/training/loop.py +227 -0
  44. anthracite-1.0.0/anthracite/training/memory.py +165 -0
  45. anthracite-1.0.0/anthracite/training/optimizer.py +38 -0
  46. anthracite-1.0.0/anthracite/training/precision.py +94 -0
  47. anthracite-1.0.0/anthracite/training/scheduler.py +64 -0
  48. anthracite-1.0.0/anthracite/utils/logging.py +105 -0
  49. anthracite-1.0.0/anthracite/utils/parameters.py +187 -0
  50. anthracite-1.0.0/anthracite/utils/progress.py +66 -0
  51. anthracite-1.0.0/anthracite/utils/seed.py +76 -0
  52. anthracite-1.0.0/anthracite.egg-info/PKG-INFO +500 -0
  53. anthracite-1.0.0/anthracite.egg-info/SOURCES.txt +67 -0
  54. anthracite-1.0.0/anthracite.egg-info/dependency_links.txt +1 -0
  55. anthracite-1.0.0/anthracite.egg-info/entry_points.txt +2 -0
  56. anthracite-1.0.0/anthracite.egg-info/requires.txt +27 -0
  57. anthracite-1.0.0/anthracite.egg-info/top_level.txt +1 -0
  58. anthracite-1.0.0/examples/01_train_text.py +17 -0
  59. anthracite-1.0.0/examples/02_finetune.py +11 -0
  60. anthracite-1.0.0/examples/03_generate.py +8 -0
  61. anthracite-1.0.0/examples/04_embedding_model.py +17 -0
  62. anthracite-1.0.0/examples/05_contrastive_finetune.py +20 -0
  63. anthracite-1.0.0/examples/06_embed_and_search.py +18 -0
  64. anthracite-1.0.0/examples/07_interface.py +5 -0
  65. anthracite-1.0.0/examples/08_huggingface_dataset.py +12 -0
  66. anthracite-1.0.0/examples/09_resume_training.py +11 -0
  67. anthracite-1.0.0/pyproject.toml +52 -0
  68. anthracite-1.0.0/setup.cfg +4 -0
  69. anthracite-1.0.0/tests/test_smoke.py +170 -0
@@ -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,3 @@
1
+ include README.md
2
+ include LICENSE
3
+ recursive-include examples *.py *.jsonl *.txt
@@ -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