canifinetune 0.1.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 (43) hide show
  1. canifinetune-0.1.0/.gitignore +62 -0
  2. canifinetune-0.1.0/LICENSE +21 -0
  3. canifinetune-0.1.0/PKG-INFO +251 -0
  4. canifinetune-0.1.0/README.md +201 -0
  5. canifinetune-0.1.0/examples/README.md +16 -0
  6. canifinetune-0.1.0/examples/qwen_1_5b_qlora_4080/README.md +56 -0
  7. canifinetune-0.1.0/examples/tiny_gpt2_lora_smoke/README.md +56 -0
  8. canifinetune-0.1.0/pyproject.toml +127 -0
  9. canifinetune-0.1.0/src/canifinetune/__init__.py +6 -0
  10. canifinetune-0.1.0/src/canifinetune/bench/__init__.py +5 -0
  11. canifinetune-0.1.0/src/canifinetune/bench/memory_trace.py +69 -0
  12. canifinetune-0.1.0/src/canifinetune/bench/oom.py +34 -0
  13. canifinetune-0.1.0/src/canifinetune/bench/runner.py +450 -0
  14. canifinetune-0.1.0/src/canifinetune/bench/synthetic_data.py +75 -0
  15. canifinetune-0.1.0/src/canifinetune/cli.py +512 -0
  16. canifinetune-0.1.0/src/canifinetune/doctor.py +165 -0
  17. canifinetune-0.1.0/src/canifinetune/estimator/__init__.py +29 -0
  18. canifinetune-0.1.0/src/canifinetune/estimator/calibration.py +191 -0
  19. canifinetune-0.1.0/src/canifinetune/estimator/formulas.py +315 -0
  20. canifinetune-0.1.0/src/canifinetune/estimator/memory.py +250 -0
  21. canifinetune-0.1.0/src/canifinetune/estimator/model_metadata.py +342 -0
  22. canifinetune-0.1.0/src/canifinetune/estimator/recommender.py +228 -0
  23. canifinetune-0.1.0/src/canifinetune/recipes/__init__.py +5 -0
  24. canifinetune-0.1.0/src/canifinetune/recipes/generator.py +147 -0
  25. canifinetune-0.1.0/src/canifinetune/recipes/templates/README.md.j2 +56 -0
  26. canifinetune-0.1.0/src/canifinetune/recipes/templates/config.yaml.j2 +38 -0
  27. canifinetune-0.1.0/src/canifinetune/recipes/templates/dataset_format.md.j2 +35 -0
  28. canifinetune-0.1.0/src/canifinetune/recipes/templates/eval_smoke.py.j2 +56 -0
  29. canifinetune-0.1.0/src/canifinetune/recipes/templates/expected_vram.md.j2 +51 -0
  30. canifinetune-0.1.0/src/canifinetune/recipes/templates/requirements.txt.j2 +11 -0
  31. canifinetune-0.1.0/src/canifinetune/recipes/templates/run.sh.j2 +9 -0
  32. canifinetune-0.1.0/src/canifinetune/recipes/templates/sample_dataset.jsonl.j2 +8 -0
  33. canifinetune-0.1.0/src/canifinetune/recipes/templates/train.py.j2 +300 -0
  34. canifinetune-0.1.0/src/canifinetune/recipes/templates/troubleshooting.md.j2 +69 -0
  35. canifinetune-0.1.0/src/canifinetune/reports/__init__.py +11 -0
  36. canifinetune-0.1.0/src/canifinetune/reports/html.py +97 -0
  37. canifinetune-0.1.0/src/canifinetune/reports/markdown.py +167 -0
  38. canifinetune-0.1.0/src/canifinetune/utils/__init__.py +1 -0
  39. canifinetune-0.1.0/src/canifinetune/utils/gpu.py +145 -0
  40. canifinetune-0.1.0/src/canifinetune/utils/hf.py +60 -0
  41. canifinetune-0.1.0/src/canifinetune/utils/logging.py +48 -0
  42. canifinetune-0.1.0/src/canifinetune/utils/subprocess.py +30 -0
  43. canifinetune-0.1.0/src/canifinetune/utils/units.py +96 -0
@@ -0,0 +1,62 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ .eggs/
11
+ *.egg
12
+
13
+ # Virtual envs
14
+ .venv/
15
+ venv/
16
+ env/
17
+ .python-version-local
18
+
19
+ # Tooling
20
+ .ruff_cache/
21
+ .mypy_cache/
22
+ .pytest_cache/
23
+ .coverage
24
+ htmlcov/
25
+ .tox/
26
+ .nox/
27
+
28
+ # IDE
29
+ .vscode/
30
+ .idea/
31
+ *.swp
32
+ *~
33
+
34
+ # OS
35
+ .DS_Store
36
+ Thumbs.db
37
+ desktop.ini
38
+
39
+ # Project local artifacts (small results are tracked under benchmarks/results)
40
+ .cache/
41
+ hf_cache/
42
+ runs/
43
+ output*/
44
+ checkpoints/
45
+ adapters/
46
+ *.log
47
+
48
+ # Models we never want to commit
49
+ *.bin
50
+ *.safetensors
51
+ *.gguf
52
+ *.pt
53
+ *.pth
54
+ *.onnx
55
+
56
+ # Large datasets
57
+ *.parquet
58
+ *.arrow
59
+
60
+ # OneDrive cruft
61
+ *.tmp
62
+ *.lock
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Daoyuan Li
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,251 @@
1
+ Metadata-Version: 2.4
2
+ Name: canifinetune
3
+ Version: 0.1.0
4
+ Summary: Estimate, benchmark, and generate fine-tuning recipes for LLMs on consumer GPUs.
5
+ Project-URL: Homepage, https://github.com/DaoyuanLi2816/can-i-finetune-this
6
+ Project-URL: Issues, https://github.com/DaoyuanLi2816/can-i-finetune-this/issues
7
+ Project-URL: Repository, https://github.com/DaoyuanLi2816/can-i-finetune-this
8
+ Author-email: Daoyuan Li <lidaoyuan2816@gmail.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: fine-tuning,gpu,huggingface,llm,lora,memory,peft,qlora,transformers
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: huggingface-hub>=0.25
24
+ Requires-Dist: jinja2>=3.1
25
+ Requires-Dist: platformdirs>=4.2
26
+ Requires-Dist: pydantic>=2.6
27
+ Requires-Dist: pyyaml>=6.0
28
+ Requires-Dist: rich>=13.7
29
+ Requires-Dist: typer>=0.12
30
+ Provides-Extra: dev
31
+ Requires-Dist: mypy>=1.10; extra == 'dev'
32
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
33
+ Requires-Dist: pytest>=8.0; extra == 'dev'
34
+ Requires-Dist: ruff>=0.5; extra == 'dev'
35
+ Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
36
+ Provides-Extra: report
37
+ Requires-Dist: pandas>=2.2; extra == 'report'
38
+ Requires-Dist: tabulate>=0.9; extra == 'report'
39
+ Provides-Extra: train
40
+ Requires-Dist: accelerate>=0.33; extra == 'train'
41
+ Requires-Dist: bitsandbytes>=0.43; (platform_system != 'Darwin') and extra == 'train'
42
+ Requires-Dist: datasets>=2.20; extra == 'train'
43
+ Requires-Dist: peft>=0.12; extra == 'train'
44
+ Requires-Dist: protobuf>=4.25; extra == 'train'
45
+ Requires-Dist: sentencepiece>=0.2; extra == 'train'
46
+ Requires-Dist: torch>=2.3; extra == 'train'
47
+ Requires-Dist: transformers>=4.43; extra == 'train'
48
+ Requires-Dist: trl>=0.9; extra == 'train'
49
+ Description-Content-Type: text/markdown
50
+
51
+ # can-i-finetune-this
52
+
53
+ [![CI](https://github.com/DaoyuanLi2816/can-i-finetune-this/actions/workflows/ci.yml/badge.svg)](https://github.com/DaoyuanLi2816/can-i-finetune-this/actions/workflows/ci.yml)
54
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org)
55
+ [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
56
+
57
+ **Estimate, benchmark, and generate fine-tuning recipes for LLMs on consumer GPUs.**
58
+
59
+ ![can-i-finetune-this architecture](docs/architecture.png)
60
+
61
+ You have one consumer-grade NVIDIA GPU. You want to fine-tune an open-weight LLM
62
+ with LoRA or QLoRA, but you do not want to download 14 GB of weights just to
63
+ discover that your 12 GB / 16 GB / 24 GB card OOMs on step 1.
64
+
65
+ `canifinetune` answers, before you spend the disk and the time:
66
+
67
+ 1. Can I fine-tune this model?
68
+ 2. About how much VRAM will it use?
69
+ 3. What batch size / sequence length / LoRA rank / quantization should I use?
70
+ 4. If I can't, how should I downsize?
71
+ 5. Is there local benchmark evidence for that answer?
72
+ 6. Can I get a ready-to-run Hugging Face + PEFT + TRL training script for that config?
73
+
74
+ It is a single Python package with a CLI:
75
+
76
+ ```bash
77
+ canifinetune doctor
78
+ canifinetune estimate --model Qwen/Qwen2.5-1.5B-Instruct --method qlora --gpu-vram-gb 16 --seq-len 2048 --micro-batch-size 1 --lora-rank 16
79
+ canifinetune recommend --model Qwen/Qwen2.5-1.5B-Instruct --gpu-vram-gb 16
80
+ canifinetune bench --model sshleifer/tiny-gpt2 --method lora --steps 3
81
+ canifinetune calibrate --benchmarks benchmarks/results
82
+ canifinetune recipe --model Qwen/Qwen2.5-1.5B-Instruct --method qlora --output recipes/qwen2.5-1.5b-qlora-4080
83
+ canifinetune report --benchmarks benchmarks/results --out report.md
84
+ canifinetune compare --benchmarks benchmarks/results --out compare.md
85
+ ```
86
+
87
+ What `canifinetune estimate` actually prints:
88
+
89
+ ```text
90
+ +-------- Qwen/Qwen2.5-1.5B-Instruct (qlora) --------+
91
+ | feasible: YES ratio = 0.20 confidence = medium |
92
+ +------------------------------------------------------+
93
+ Memory breakdown (GB)
94
+ +---------------------------------+
95
+ | Component | Value |
96
+ |-----------------------+---------|
97
+ | static model | 0.737 |
98
+ | quantization overhead | 0.018 |
99
+ | trainable params | 4.4 MB |
100
+ | gradients | 0.008 |
101
+ | optimizer states | 0.010 |
102
+ | activations | 0.328 |
103
+ | CUDA / fragmentation | 1.280 |
104
+ | safety margin | 0.800 |
105
+ | total | 3.163 |
106
+ +---------------------------------+
107
+ ```
108
+
109
+ Static estimate says 3.16 GB; on a real RTX 4080 the same config measures
110
+ 7.10 GB (heavy bitsandbytes unpacking buffers at seq_len=2048). `canifinetune
111
+ bench` and `canifinetune calibrate` close that gap on your machine —
112
+ that is the *point* of the project.
113
+
114
+ ---
115
+
116
+ ## Install
117
+
118
+ `canifinetune` runs in two layers:
119
+
120
+ | Layer | Install | What you get |
121
+ | --- | --- | --- |
122
+ | Core (estimate / recommend / recipe / report) | `pip install canifinetune` | All CLI commands. No PyTorch required. |
123
+ | Training (bench / real fine-tuning) | `pip install canifinetune[train]` | Adds `torch`, `transformers`, `peft`, `bitsandbytes`, `trl`, `datasets`. |
124
+ | Reporting extras | `pip install canifinetune[report]` | Pandas/tabulate for prettier tables. |
125
+ | Development | `pip install canifinetune[dev]` | pytest, ruff, mypy. |
126
+
127
+ If you use `uv`:
128
+
129
+ ```bash
130
+ uv venv
131
+ uv pip install -e ".[dev,report]"
132
+ # Add training deps when you want to run benchmarks:
133
+ uv pip install -e ".[dev,train,report]"
134
+ ```
135
+
136
+ PyTorch should generally be installed with the CUDA wheel that matches your driver,
137
+ e.g.
138
+
139
+ ```bash
140
+ uv pip install torch --index-url https://download.pytorch.org/whl/cu121
141
+ ```
142
+
143
+ See `docs/troubleshooting.md` for Windows / WSL / bitsandbytes specifics.
144
+
145
+ ---
146
+
147
+ ## Quickstart
148
+
149
+ ```bash
150
+ # 1. See what your machine looks like
151
+ canifinetune doctor
152
+
153
+ # 2. Ask if a model fits on your card
154
+ canifinetune estimate \
155
+ --model Qwen/Qwen2.5-1.5B-Instruct \
156
+ --method qlora \
157
+ --gpu-vram-gb 16 \
158
+ --seq-len 2048 \
159
+ --micro-batch-size 1 \
160
+ --lora-rank 16
161
+
162
+ # 3. Have it search for a feasible config
163
+ canifinetune recommend --model Qwen/Qwen2.5-1.5B-Instruct --gpu-vram-gb 16
164
+
165
+ # 4. Run a tiny real benchmark (downloads sshleifer/tiny-gpt2, ~5 MB)
166
+ canifinetune bench --model sshleifer/tiny-gpt2 --method lora --steps 3
167
+
168
+ # 5. Generate a ready-to-run training recipe
169
+ canifinetune recipe \
170
+ --model Qwen/Qwen2.5-1.5B-Instruct \
171
+ --method qlora \
172
+ --seq-len 2048 \
173
+ --output recipes/qwen2.5-1.5b-qlora-4080
174
+ ```
175
+
176
+ ---
177
+
178
+ ## What's different from `accelerate estimate-memory`?
179
+
180
+ `accelerate estimate-memory` tells you how much memory **loading** a model takes.
181
+ That is not enough to know whether you can **train** it.
182
+
183
+ This project tries to answer the harder question. It models:
184
+
185
+ - Model weights, in fp32 / fp16 / bf16 / int8 / NF4 + double-quant
186
+ - LoRA / QLoRA trainable parameter count for typical `target_modules`
187
+ - Gradients only for trainable parameters
188
+ - AdamW vs 8-bit / paged AdamW optimizer states
189
+ - Activations as a function of `seq_len`, `batch_size`, `hidden_size`, `num_layers`,
190
+ with and without gradient checkpointing
191
+ - A fragmentation / CUDA / buffer safety margin
192
+ - A feasibility decision against your actual GPU
193
+ - Concrete degradation suggestions when not feasible
194
+
195
+ Estimates are **always** marked with an `assumptions` block and a `confidence`
196
+ level, because activation memory in particular is hard to predict statically.
197
+ Run `canifinetune bench` and `canifinetune calibrate` to ground them in real
198
+ measurements on your machine.
199
+
200
+ ---
201
+
202
+ ## RTX 4080 baselines
203
+
204
+ `docs/rtx4080_baselines.md` contains real measurements collected on a single
205
+ RTX 4080 (16 GB). These are not synthetic. If a configuration was not run, the
206
+ table says "not run", not a guessed number.
207
+
208
+ Highlights (more in the doc):
209
+
210
+ | model | method | seq_len | measured peak | tok/sec |
211
+ | --- | --- | --- | --- | --- |
212
+ | `Qwen/Qwen2.5-0.5B-Instruct` | qlora | 1024 | 3.30 GB | 1995 |
213
+ | `Qwen/Qwen2.5-1.5B-Instruct` | qlora | 1024 | 4.36 GB | 1352 |
214
+ | `Qwen/Qwen2.5-1.5B-Instruct` | qlora | 2048 | 7.10 GB | 1470 |
215
+ | `Qwen/Qwen2.5-3B-Instruct` | qlora | 1024 | 5.54 GB | 1158 |
216
+ | `sshleifer/tiny-gpt2` (smoke) | lora | 128 | 0.12 GB | 1735 |
217
+
218
+ ---
219
+
220
+ ## Repository layout
221
+
222
+ ```
223
+ src/canifinetune/ # package code (estimator, bench, recipes, reports, cli)
224
+ benchmarks/ # configs/, results/ (JSON), calibration/
225
+ docs/ # design, memory model, troubleshooting
226
+ examples/ # end-to-end recipe folders
227
+ tests/ # pytest tests (CPU-only, no large downloads)
228
+ scripts/ # helper scripts for collecting baselines
229
+ .github/workflows/ # CI (ruff + pytest on CPU)
230
+ ```
231
+
232
+ ---
233
+
234
+ ## Roadmap
235
+
236
+ The current scope is "single consumer GPU, single node, LoRA / QLoRA, causal LM,
237
+ Hugging Face stack". Possible directions, none committed:
238
+
239
+ - DeepSpeed ZeRO and FSDP estimation for multi-GPU setups
240
+ - Heuristics for sequence-classification / encoder-decoder training
241
+ - Throughput modeling (tokens / sec), not just feasibility
242
+ - Auto-tuning of `gradient_accumulation_steps` for a target effective batch size
243
+ - A web UI on top of the CLI
244
+
245
+ Contributions welcome.
246
+
247
+ ---
248
+
249
+ ## License
250
+
251
+ MIT. See `LICENSE`.
@@ -0,0 +1,201 @@
1
+ # can-i-finetune-this
2
+
3
+ [![CI](https://github.com/DaoyuanLi2816/can-i-finetune-this/actions/workflows/ci.yml/badge.svg)](https://github.com/DaoyuanLi2816/can-i-finetune-this/actions/workflows/ci.yml)
4
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org)
5
+ [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
6
+
7
+ **Estimate, benchmark, and generate fine-tuning recipes for LLMs on consumer GPUs.**
8
+
9
+ ![can-i-finetune-this architecture](docs/architecture.png)
10
+
11
+ You have one consumer-grade NVIDIA GPU. You want to fine-tune an open-weight LLM
12
+ with LoRA or QLoRA, but you do not want to download 14 GB of weights just to
13
+ discover that your 12 GB / 16 GB / 24 GB card OOMs on step 1.
14
+
15
+ `canifinetune` answers, before you spend the disk and the time:
16
+
17
+ 1. Can I fine-tune this model?
18
+ 2. About how much VRAM will it use?
19
+ 3. What batch size / sequence length / LoRA rank / quantization should I use?
20
+ 4. If I can't, how should I downsize?
21
+ 5. Is there local benchmark evidence for that answer?
22
+ 6. Can I get a ready-to-run Hugging Face + PEFT + TRL training script for that config?
23
+
24
+ It is a single Python package with a CLI:
25
+
26
+ ```bash
27
+ canifinetune doctor
28
+ canifinetune estimate --model Qwen/Qwen2.5-1.5B-Instruct --method qlora --gpu-vram-gb 16 --seq-len 2048 --micro-batch-size 1 --lora-rank 16
29
+ canifinetune recommend --model Qwen/Qwen2.5-1.5B-Instruct --gpu-vram-gb 16
30
+ canifinetune bench --model sshleifer/tiny-gpt2 --method lora --steps 3
31
+ canifinetune calibrate --benchmarks benchmarks/results
32
+ canifinetune recipe --model Qwen/Qwen2.5-1.5B-Instruct --method qlora --output recipes/qwen2.5-1.5b-qlora-4080
33
+ canifinetune report --benchmarks benchmarks/results --out report.md
34
+ canifinetune compare --benchmarks benchmarks/results --out compare.md
35
+ ```
36
+
37
+ What `canifinetune estimate` actually prints:
38
+
39
+ ```text
40
+ +-------- Qwen/Qwen2.5-1.5B-Instruct (qlora) --------+
41
+ | feasible: YES ratio = 0.20 confidence = medium |
42
+ +------------------------------------------------------+
43
+ Memory breakdown (GB)
44
+ +---------------------------------+
45
+ | Component | Value |
46
+ |-----------------------+---------|
47
+ | static model | 0.737 |
48
+ | quantization overhead | 0.018 |
49
+ | trainable params | 4.4 MB |
50
+ | gradients | 0.008 |
51
+ | optimizer states | 0.010 |
52
+ | activations | 0.328 |
53
+ | CUDA / fragmentation | 1.280 |
54
+ | safety margin | 0.800 |
55
+ | total | 3.163 |
56
+ +---------------------------------+
57
+ ```
58
+
59
+ Static estimate says 3.16 GB; on a real RTX 4080 the same config measures
60
+ 7.10 GB (heavy bitsandbytes unpacking buffers at seq_len=2048). `canifinetune
61
+ bench` and `canifinetune calibrate` close that gap on your machine —
62
+ that is the *point* of the project.
63
+
64
+ ---
65
+
66
+ ## Install
67
+
68
+ `canifinetune` runs in two layers:
69
+
70
+ | Layer | Install | What you get |
71
+ | --- | --- | --- |
72
+ | Core (estimate / recommend / recipe / report) | `pip install canifinetune` | All CLI commands. No PyTorch required. |
73
+ | Training (bench / real fine-tuning) | `pip install canifinetune[train]` | Adds `torch`, `transformers`, `peft`, `bitsandbytes`, `trl`, `datasets`. |
74
+ | Reporting extras | `pip install canifinetune[report]` | Pandas/tabulate for prettier tables. |
75
+ | Development | `pip install canifinetune[dev]` | pytest, ruff, mypy. |
76
+
77
+ If you use `uv`:
78
+
79
+ ```bash
80
+ uv venv
81
+ uv pip install -e ".[dev,report]"
82
+ # Add training deps when you want to run benchmarks:
83
+ uv pip install -e ".[dev,train,report]"
84
+ ```
85
+
86
+ PyTorch should generally be installed with the CUDA wheel that matches your driver,
87
+ e.g.
88
+
89
+ ```bash
90
+ uv pip install torch --index-url https://download.pytorch.org/whl/cu121
91
+ ```
92
+
93
+ See `docs/troubleshooting.md` for Windows / WSL / bitsandbytes specifics.
94
+
95
+ ---
96
+
97
+ ## Quickstart
98
+
99
+ ```bash
100
+ # 1. See what your machine looks like
101
+ canifinetune doctor
102
+
103
+ # 2. Ask if a model fits on your card
104
+ canifinetune estimate \
105
+ --model Qwen/Qwen2.5-1.5B-Instruct \
106
+ --method qlora \
107
+ --gpu-vram-gb 16 \
108
+ --seq-len 2048 \
109
+ --micro-batch-size 1 \
110
+ --lora-rank 16
111
+
112
+ # 3. Have it search for a feasible config
113
+ canifinetune recommend --model Qwen/Qwen2.5-1.5B-Instruct --gpu-vram-gb 16
114
+
115
+ # 4. Run a tiny real benchmark (downloads sshleifer/tiny-gpt2, ~5 MB)
116
+ canifinetune bench --model sshleifer/tiny-gpt2 --method lora --steps 3
117
+
118
+ # 5. Generate a ready-to-run training recipe
119
+ canifinetune recipe \
120
+ --model Qwen/Qwen2.5-1.5B-Instruct \
121
+ --method qlora \
122
+ --seq-len 2048 \
123
+ --output recipes/qwen2.5-1.5b-qlora-4080
124
+ ```
125
+
126
+ ---
127
+
128
+ ## What's different from `accelerate estimate-memory`?
129
+
130
+ `accelerate estimate-memory` tells you how much memory **loading** a model takes.
131
+ That is not enough to know whether you can **train** it.
132
+
133
+ This project tries to answer the harder question. It models:
134
+
135
+ - Model weights, in fp32 / fp16 / bf16 / int8 / NF4 + double-quant
136
+ - LoRA / QLoRA trainable parameter count for typical `target_modules`
137
+ - Gradients only for trainable parameters
138
+ - AdamW vs 8-bit / paged AdamW optimizer states
139
+ - Activations as a function of `seq_len`, `batch_size`, `hidden_size`, `num_layers`,
140
+ with and without gradient checkpointing
141
+ - A fragmentation / CUDA / buffer safety margin
142
+ - A feasibility decision against your actual GPU
143
+ - Concrete degradation suggestions when not feasible
144
+
145
+ Estimates are **always** marked with an `assumptions` block and a `confidence`
146
+ level, because activation memory in particular is hard to predict statically.
147
+ Run `canifinetune bench` and `canifinetune calibrate` to ground them in real
148
+ measurements on your machine.
149
+
150
+ ---
151
+
152
+ ## RTX 4080 baselines
153
+
154
+ `docs/rtx4080_baselines.md` contains real measurements collected on a single
155
+ RTX 4080 (16 GB). These are not synthetic. If a configuration was not run, the
156
+ table says "not run", not a guessed number.
157
+
158
+ Highlights (more in the doc):
159
+
160
+ | model | method | seq_len | measured peak | tok/sec |
161
+ | --- | --- | --- | --- | --- |
162
+ | `Qwen/Qwen2.5-0.5B-Instruct` | qlora | 1024 | 3.30 GB | 1995 |
163
+ | `Qwen/Qwen2.5-1.5B-Instruct` | qlora | 1024 | 4.36 GB | 1352 |
164
+ | `Qwen/Qwen2.5-1.5B-Instruct` | qlora | 2048 | 7.10 GB | 1470 |
165
+ | `Qwen/Qwen2.5-3B-Instruct` | qlora | 1024 | 5.54 GB | 1158 |
166
+ | `sshleifer/tiny-gpt2` (smoke) | lora | 128 | 0.12 GB | 1735 |
167
+
168
+ ---
169
+
170
+ ## Repository layout
171
+
172
+ ```
173
+ src/canifinetune/ # package code (estimator, bench, recipes, reports, cli)
174
+ benchmarks/ # configs/, results/ (JSON), calibration/
175
+ docs/ # design, memory model, troubleshooting
176
+ examples/ # end-to-end recipe folders
177
+ tests/ # pytest tests (CPU-only, no large downloads)
178
+ scripts/ # helper scripts for collecting baselines
179
+ .github/workflows/ # CI (ruff + pytest on CPU)
180
+ ```
181
+
182
+ ---
183
+
184
+ ## Roadmap
185
+
186
+ The current scope is "single consumer GPU, single node, LoRA / QLoRA, causal LM,
187
+ Hugging Face stack". Possible directions, none committed:
188
+
189
+ - DeepSpeed ZeRO and FSDP estimation for multi-GPU setups
190
+ - Heuristics for sequence-classification / encoder-decoder training
191
+ - Throughput modeling (tokens / sec), not just feasibility
192
+ - Auto-tuning of `gradient_accumulation_steps` for a target effective batch size
193
+ - A web UI on top of the CLI
194
+
195
+ Contributions welcome.
196
+
197
+ ---
198
+
199
+ ## License
200
+
201
+ MIT. See `LICENSE`.
@@ -0,0 +1,16 @@
1
+ # Examples
2
+
3
+ This folder will collect end-to-end recipes generated by `canifinetune recipe`.
4
+ We commit them so that someone browsing the repo can read the generated
5
+ `train.py` and `config.yaml` without having to install the package first.
6
+
7
+ To regenerate any of these from scratch:
8
+
9
+ ```bash
10
+ canifinetune recipe \
11
+ --model Qwen/Qwen2.5-1.5B-Instruct \
12
+ --method qlora \
13
+ --seq-len 2048 \
14
+ --lora-rank 16 \
15
+ --output examples/qwen_1_5b_qlora_4080
16
+ ```
@@ -0,0 +1,56 @@
1
+ # canifinetune-recipe
2
+
3
+ This folder was generated by `canifinetune recipe`. It is a self-contained,
4
+ single-GPU QLORA fine-tuning script for **Qwen/Qwen2.5-1.5B-Instruct**.
5
+
6
+ ## Files
7
+
8
+ - `train.py` — main training entrypoint.
9
+ - `config.yaml` — all hyperparameters; pass with `--config`.
10
+ - `eval_smoke.py` — load the adapter, generate one completion as a smoke test.
11
+ - `data/sample.jsonl` — tiny synthetic instruction dataset (not for serious training).
12
+ - `requirements.txt` — Python deps. Match CUDA wheels to your driver.
13
+ - `expected_vram.md` — static estimate for this exact config.
14
+ - `dataset_format.md` — JSONL schema your real dataset should follow.
15
+ - `troubleshooting.md` — OOM / bitsandbytes / Windows tips.
16
+ - `run.sh` — convenience wrapper.
17
+
18
+ ## Quick start
19
+
20
+ ```bash
21
+ # 1. Install deps in a fresh venv.
22
+ python -m venv .venv && source .venv/bin/activate # or .\.venv\Scripts\activate on Windows
23
+ pip install -r requirements.txt
24
+ # For CUDA wheels: e.g. `pip install torch --index-url https://download.pytorch.org/whl/cu121`
25
+
26
+ # 2. Smoke run with the bundled tiny dataset.
27
+ python train.py --config config.yaml --max-steps 5
28
+
29
+ # 3. Confirm the adapter loads.
30
+ python eval_smoke.py --adapter output/adapter
31
+
32
+ # 4. Replace data/sample.jsonl with your own JSONL and run again.
33
+ ```
34
+
35
+ ## Memory estimate (from `canifinetune estimate`)
36
+
37
+ - Method: **qlora**, base dtype **bf16**, quantization **nf4_double_quant**
38
+ - LoRA rank: **16**, target modules: `q_proj, k_proj, v_proj, o_proj`
39
+ - seq_len: **1024**, micro_batch_size: **1**
40
+ - Gradient checkpointing: **on**
41
+ - Optimizer: **paged_adamw_8bit**
42
+ - Attention impl: **sdpa**
43
+
44
+ Static feasibility on a 16.0 GB GPU: **yes**
45
+ (confidence: medium).
46
+
47
+ See `expected_vram.md` for the full breakdown. Run
48
+ `canifinetune bench --model Qwen/Qwen2.5-1.5B-Instruct --method qlora --steps 3` to
49
+ measure real VRAM on your machine.
50
+
51
+ ## Caveats
52
+
53
+ - The bundled `data/sample.jsonl` exists so the smoke run completes; it is
54
+ far too small for any real fine-tune. Bring your own data.
55
+ - This recipe assumes a single GPU. For multi-GPU, regenerate with `accelerate`
56
+ / DeepSpeed integration (not yet in `canifinetune`).
@@ -0,0 +1,56 @@
1
+ # canifinetune-recipe
2
+
3
+ This folder was generated by `canifinetune recipe`. It is a self-contained,
4
+ single-GPU LORA fine-tuning script for **sshleifer/tiny-gpt2**.
5
+
6
+ ## Files
7
+
8
+ - `train.py` — main training entrypoint.
9
+ - `config.yaml` — all hyperparameters; pass with `--config`.
10
+ - `eval_smoke.py` — load the adapter, generate one completion as a smoke test.
11
+ - `data/sample.jsonl` — tiny synthetic instruction dataset (not for serious training).
12
+ - `requirements.txt` — Python deps. Match CUDA wheels to your driver.
13
+ - `expected_vram.md` — static estimate for this exact config.
14
+ - `dataset_format.md` — JSONL schema your real dataset should follow.
15
+ - `troubleshooting.md` — OOM / bitsandbytes / Windows tips.
16
+ - `run.sh` — convenience wrapper.
17
+
18
+ ## Quick start
19
+
20
+ ```bash
21
+ # 1. Install deps in a fresh venv.
22
+ python -m venv .venv && source .venv/bin/activate # or .\.venv\Scripts\activate on Windows
23
+ pip install -r requirements.txt
24
+ # For CUDA wheels: e.g. `pip install torch --index-url https://download.pytorch.org/whl/cu121`
25
+
26
+ # 2. Smoke run with the bundled tiny dataset.
27
+ python train.py --config config.yaml --max-steps 5
28
+
29
+ # 3. Confirm the adapter loads.
30
+ python eval_smoke.py --adapter output/adapter
31
+
32
+ # 4. Replace data/sample.jsonl with your own JSONL and run again.
33
+ ```
34
+
35
+ ## Memory estimate (from `canifinetune estimate`)
36
+
37
+ - Method: **lora**, base dtype **fp32**, quantization **bf16**
38
+ - LoRA rank: **8**, target modules: `c_attn, c_proj`
39
+ - seq_len: **128**, micro_batch_size: **1**
40
+ - Gradient checkpointing: **off**
41
+ - Optimizer: **adamw_torch**
42
+ - Attention impl: **eager**
43
+
44
+ Static feasibility on a 16.0 GB GPU: **yes**
45
+ (confidence: medium).
46
+
47
+ See `expected_vram.md` for the full breakdown. Run
48
+ `canifinetune bench --model sshleifer/tiny-gpt2 --method lora --steps 3` to
49
+ measure real VRAM on your machine.
50
+
51
+ ## Caveats
52
+
53
+ - The bundled `data/sample.jsonl` exists so the smoke run completes; it is
54
+ far too small for any real fine-tune. Bring your own data.
55
+ - This recipe assumes a single GPU. For multi-GPU, regenerate with `accelerate`
56
+ / DeepSpeed integration (not yet in `canifinetune`).