SlickML fine-tuning toolkit: composable strategies, objectives, and metrics for LLMs
Project description
SlickTune ๐งฉ: Composable LLM Fine-Tuning by SlickML๐ง
Explore Releases ๐ฃ Become a Contributor ๐ฃ PyPI ๐ฃ Join our Slack ๐ฃ Tweet Us
๐ง Philosophy
SlickTune ๐งฉ is a small, composable toolkit for teaching LLMs new facts and behaviors with Transformers + PEFT + TRL. LoRA / QLoRA are PEFT adapters; full FT updates every weight. The goal is the same SlickML spirit: prototype fast ๐, keep axes orthogonal, and measure whether the model actually learned your facts ๐.
New to fine-tuning? Start here โ Fine-Tuning LLMs: A Visual Guide โ pre-training vs prompting vs FT, Full / LoRA / DoRA / AdaLoRA / QLoRA with diagrams, how to choose a strategy, and how probes & holdout perplexity tell you it worked.
Fine-tuning is an orthogonal stack โ swap any axis without rewriting the others:
model ร strategy ร objective ร data ร metrics
๐งฉ Abstractions
flowchart TB
subgraph inputs [Inputs]
modelId[model_id]
dataJsonl[data JSONL]
end
subgraph axes [Composable axes]
strategyNode["Strategy: LoRA / DoRA / AdaLoRA / QLoRA / Full"]
objectiveNode["Objective: SFT then DPO / GRPO"]
end
subgraph core [Tuner fit]
tuner[Tuner]
loadStep[load model and tokenizer]
applyStep[strategy.apply]
trainStep[TRL trainer]
metricsStep[MetricsTracker]
end
subgraph outputs [Outputs]
checkpoint[adapter or checkpoint]
metricsFile[metrics.json]
probeRate[probe pass rate]
end
modelId --> tuner
dataJsonl --> tuner
strategyNode --> tuner
objectiveNode --> tuner
tuner --> loadStep --> applyStep --> trainStep --> metricsStep
trainStep --> checkpoint
metricsStep --> metricsFile
checkpoint --> probeRate
| Axis | Responsibility | Phase 3 |
|---|---|---|
| Strategy | How weights change (PEFT vs full) | LoRA / DoRA / AdaLoRA / QLoRA / Full |
| Objective | What is optimized / data contract | SFT / DPO / ORPO / KTO |
| Data | Examples โ chat or preferences | train + holdout + prefs/KTO JSONL (about_amir*.jsonl) |
| Metrics | Comparable run stats | MetricsTracker (+ holdout PPL, judge score) |
| Eval | Holdout + judges | slicktune eval, SubstringJudge, LLMJudge |
| Probe | Did the model learn your facts? | slicktune probe |
๐ Quick Start
from slicktune import LoRAStrategy, SFTObjective, Tuner
Tuner(
model_id="HuggingFaceTB/SmolLM2-135M-Instruct",
strategy=LoRAStrategy(r=8),
objective=SFTObjective(),
output_dir="outputs/sft_lora",
eval_data="examples/data/about_amir.eval.jsonl",
).fit("examples/data/about_amir.jsonl")
๐ค Personal โabout meโ loop (recommended)
- Edit
examples/data/about_amir.jsonlwith facts about you (or keep the SlickML starter facts) โ๏ธ. - Edit
examples/data/about_amir.eval.jsonlwith held-out paraphrases (same topics, not copied from train) for perplexity ๐. - Edit
examples/data/about_amir.probes.jsonlwith questions and amust_containsubstring that should appear after training ๐ฏ. - Train a strategy on a tiny instruct model ๐งช.
- Probe the checkpoint โ pass rate shows whether fine-tuning stuck โ .
before FT โ model guesses / hallucinates about you
after FT โ probe answers contain your facts
๐ Installation
Install Python >=3.10,<3.14 and uv, then simply run ๐โโ๏ธ:
uv sync --locked --all-extras --all-groups
QLoRA (CUDA + bitsandbytes only) ๐ฅ:
uv sync --extra qlora
Task runner is Poe the Poet (same idea as slick-ml, with uv instead of Poetry). Install the CLI once ๐โโ๏ธ:
uv tool install poethepoet
poe greet
Developer workflow (format / check / test) lives in CONTRIBUTING.md ๐งโ๐ป๐ค.
๐ Train each strategy
Default demo model: HuggingFaceTB/SmolLM2-135M-Instruct (small enough for laptop smoke tests) ๐ป.
๐ข LoRA + SFT (default โ works on Mac MPS / CPU / CUDA)
uv run slicktune train \
--strategy lora \
--data examples/data/about_amir.jsonl \
--eval-data examples/data/about_amir.eval.jsonl \
--output outputs/sft_lora \
--epochs 20
uv run slicktune probe \
--model-dir outputs/sft_lora \
--probes examples/data/about_amir.probes.jsonl
Or: poe train-lora / poe probe-lora / poe eval-lora / uv run python examples/run_sft_lora.py
๐ฃ DoRA + SFT
uv run slicktune train \
--strategy dora \
--data examples/data/about_amir.jsonl \
--eval-data examples/data/about_amir.eval.jsonl \
--output outputs/sft_dora
# or: uv run python examples/run_sft_dora.py
๐ค AdaLoRA + SFT
uv run slicktune train \
--strategy adalora \
--data examples/data/about_amir.jsonl \
--eval-data examples/data/about_amir.eval.jsonl \
--output outputs/sft_adalora
# or: uv run python examples/run_sft_adalora.py
๐ก LoRA + DPO (preference pairs)
uv run slicktune train \
--strategy lora \
--objective dpo \
--data examples/data/about_amir.prefs.jsonl \
--output outputs/dpo_lora \
--epochs 3
# or: poe train-dpo / uv run python examples/run_dpo_lora.py
๐ข LoRA + KTO (unpaired labels)
uv run slicktune train \
--strategy lora \
--objective kto \
--data examples/data/about_amir.kto.jsonl \
--output outputs/kto_lora \
--epochs 3
# or: poe train-kto / uv run python examples/run_kto_lora.py
ORPO: --objective orpo with the same prefs JSONL as DPO (TRL experimental).
๐ Eval harness (holdout PPL + judges)
uv run slicktune eval \
--model-dir outputs/sft_lora \
--eval-data examples/data/about_amir.eval.jsonl \
--probes examples/data/about_amir.probes.jsonl \
--judge substring
--eval-data should be a holdout SFT JSONL (not the training file). The shipped
about_amir.eval.jsonl paraphrases the same topics for holdout perplexity.
Use --judge llm to score generations with an LLM rubric (0โ10 โ normalized).
On the tiny demo model, prefer --judge substring: the same 135M checkpoint is a
weak judge and will under-score even when answers are correct.
๐ต QLoRA + SFT (CUDA required)
uv sync --extra qlora
uv run python examples/run_sft_qlora.py
On Apple Silicon, use LoRA instead โ bitsandbytes 4-bit needs CUDA ๐.
๐ Full fine-tuning + SFT
uv run python examples/run_sft_full.py
Heavier on memory; prefer LoRA for iteration ๐พ.
๐ฆ Data formats
SFT JSONL (any of these per line) ๐:
{"messages":[{"role":"user","content":"..."},{"role":"assistant","content":"..."}]}
{"prompt":"...","response":"..."}
{"instruction":"...","input":"...","output":"..."}
Probe JSONL ๐ต๏ธ:
{"prompt":"Who is Amirhessam Tahmassebi?","must_contain":"SlickML"}
Holdout eval JSONL (same SFT shapes as train; keep examples out of the train file) ๐:
{"messages":[{"role":"user","content":"..."},{"role":"assistant","content":"..."}]}
Ship example: examples/data/about_amir.eval.jsonl.
Preference JSONL (DPO / ORPO) โ๏ธ:
{"prompt":"...","chosen":"...","rejected":"..."}
KTO JSONL (unpaired labels) โ โ:
{"prompt":"...","completion":"...","label":true}
๐บ Roadmap
| Phase | Scope |
|---|---|
| 0โ1 | Skeleton, SFT + LoRA/QLoRA/full, metrics, personal probe loop |
| 2 (done) | DoRA / AdaLoRA, holdout PPL + substring/LLM judges |
| 3 (now) | DPO / ORPO / KTO |
| 4 | GRPO / verifiable RL |
| 5 | Merge (TIES/DARE), multi-adapter |
| 6 | Optional PPO / multimodal |
๐งโ๐ป๐ค Contributing to SlickTune ๐งฉ
You can find the details of the development process in our Contributing guidelines. We strongly believe that reading and following these guidelines will help us make the contribution process easy and effective for everyone involved ๐๐.
Special thanks to all of our amazing contributors ๐
โ ๐ ๐ฒ Need Help?
Please join our Slack Channel to interact directly with the core team and our small community. This is a good place to discuss your questions and ideas or in general ask for help ๐จโ๐ฉโ๐ง ๐ซ ๐จโ๐ฉโ๐ฆ.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file slicktune-0.3.0.tar.gz.
File metadata
- Download URL: slicktune-0.3.0.tar.gz
- Upload date:
- Size: 364.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb7c5dc5a236989b85050d4976e9e1a4edff619d0db3220cab97c43d2645193a
|
|
| MD5 |
07ca11aa15884a8cf1ec1be7b00c911d
|
|
| BLAKE2b-256 |
3a43311d4d9faa1fd369771bcbc5053c61e0e00e611d62bc7a827a0d7ccfbd5b
|
File details
Details for the file slicktune-0.3.0-py3-none-any.whl.
File metadata
- Download URL: slicktune-0.3.0-py3-none-any.whl
- Upload date:
- Size: 31.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
399752b4ca90379cdab97b1946fad2e2d5d219fc7dddecaf5deffe5940d5227a
|
|
| MD5 |
4a8e4de32332772d80facb1d26fcdd82
|
|
| BLAKE2b-256 |
0ad22a1190fb917e622ae20dee4f442f9a1ede541d61b9eb206051f839bcc211
|