@ericrisco/rsc 0.1.38 → 0.1.40
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/README.md +8 -2
- package/manifest.json +181 -3
- package/package.json +1 -1
- package/scripts/lib/domains.js +1 -0
- package/scripts/lib/recommend.js +6 -0
- package/skills/automation-strategy/SKILL.md +2 -2
- package/skills/automation-strategy/references/platform-selection-matrix.md +2 -2
- package/skills/deep-learning/SKILL.md +263 -0
- package/skills/deep-learning/evals/README.md +11 -0
- package/skills/deep-learning/evals/cases.yaml +48 -0
- package/skills/deep-learning/references/distributed.md +105 -0
- package/skills/deep-learning/references/training-recipes.md +135 -0
- package/skills/finetuning/SKILL.md +244 -0
- package/skills/finetuning/evals/README.md +13 -0
- package/skills/finetuning/evals/cases.yaml +50 -0
- package/skills/finetuning/references/hyperparameters-and-eval.md +74 -0
- package/skills/finetuning/references/methods.md +189 -0
- package/skills/harness/references/providers.yaml +38 -2
- package/skills/huggingface/SKILL.md +1 -1
- package/skills/machine-learning/SKILL.md +260 -0
- package/skills/machine-learning/evals/README.md +15 -0
- package/skills/machine-learning/evals/cases.yaml +54 -0
- package/skills/machine-learning/references/gbdt-and-tuning.md +83 -0
- package/skills/machine-learning/references/metrics-and-imbalance.md +82 -0
- package/skills/machine-learning/references/pipelines-and-cv.md +135 -0
- package/skills/n8n/SKILL.md +1 -1
- package/skills/nlp/SKILL.md +225 -0
- package/skills/nlp/evals/README.md +10 -0
- package/skills/nlp/evals/cases.yaml +45 -0
- package/skills/nlp/references/evaluation.md +107 -0
- package/skills/nlp/references/tokenization.md +95 -0
- package/skills/open-weights/SKILL.md +239 -0
- package/skills/open-weights/evals/README.md +14 -0
- package/skills/open-weights/evals/cases.yaml +42 -0
- package/skills/open-weights/references/licenses.md +123 -0
- package/skills/open-weights/references/model-families.md +83 -0
- package/skills/open-weights/references/sizing-and-quant.md +89 -0
- package/skills/roast-me/tools/adapters/__pycache__/__init__.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/base.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/claude.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/codex.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/gemini.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/registry.cpython-312.pyc +0 -0
- package/skills/training-data/SKILL.md +226 -0
- package/skills/training-data/evals/README.md +13 -0
- package/skills/training-data/evals/cases.yaml +41 -0
- package/skills/training-data/references/formats.md +118 -0
- package/skills/training-data/references/synthesis-dedup-quality.md +134 -0
- package/skills/unsloth/SKILL.md +254 -0
- package/skills/unsloth/evals/README.md +10 -0
- package/skills/unsloth/evals/cases.yaml +42 -0
- package/skills/unsloth/references/export.md +75 -0
- package/skills/unsloth/references/grpo.md +91 -0
- package/skills/unsloth/references/masking-and-templates.md +91 -0
- package/skills/vllm/SKILL.md +235 -0
- package/skills/vllm/evals/README.md +9 -0
- package/skills/vllm/evals/cases.yaml +47 -0
- package/skills/vllm/references/flags-and-endpoints.md +105 -0
- package/skills/vllm/references/memory-and-throughput.md +78 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Synthesis, dedup, decontamination, quality, licensing
|
|
2
|
+
|
|
3
|
+
Depth overflow for SKILL.md §3–§7. Library versions and, above all, model licenses change
|
|
4
|
+
monthly — verify at author time; nothing here is a standing legal fact.
|
|
5
|
+
|
|
6
|
+
## Synthetic data
|
|
7
|
+
|
|
8
|
+
**Self-Instruct**: hand-write a small seed set of diverse instructions+responses, prompt a
|
|
9
|
+
strong model to generate many more conditioned on the seeds, then filter for validity, dedup,
|
|
10
|
+
and difficulty. **Evol-Instruct**: iteratively rewrite each instruction to be harder
|
|
11
|
+
(add constraints, deepen, broaden) so the corpus spans a difficulty gradient. **AI feedback /
|
|
12
|
+
UltraFeedback-style**: have a model rate candidate responses on axes (helpfulness, honesty,
|
|
13
|
+
correctness) to build preference pairs.
|
|
14
|
+
|
|
15
|
+
### distilabel skeleton (Argilla / Hugging Face, v1.x — verify)
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from distilabel.pipeline import Pipeline
|
|
19
|
+
from distilabel.steps import LoadDataFromDicts
|
|
20
|
+
from distilabel.steps.tasks import TextGeneration
|
|
21
|
+
# LLM client import paths shift between releases — check current distilabel docs.
|
|
22
|
+
|
|
23
|
+
with Pipeline(name="self-instruct") as pipe:
|
|
24
|
+
seeds = LoadDataFromDicts(data=[{"instruction": "Explain X."}, ...])
|
|
25
|
+
gen = TextGeneration(llm=...) # plug an LLM client
|
|
26
|
+
seeds >> gen
|
|
27
|
+
|
|
28
|
+
distiset = pipe.run(parameters={...})
|
|
29
|
+
distiset.push_to_hub("me/synthetic-sft") # pushes data + the pipeline definition + a card
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Distilabel serializes the whole pipeline to YAML/JSON and (on push) writes it into the dataset
|
|
33
|
+
card, so a run is reproducible. Output is a `Distiset` (a `datasets.DatasetDict` variant).
|
|
34
|
+
|
|
35
|
+
### Distillation licensing trap (do this before generating)
|
|
36
|
+
|
|
37
|
+
Training on *another model's outputs* is governed by that model/provider's terms:
|
|
38
|
+
|
|
39
|
+
- **Proprietary API outputs** may be contractually barred from training competing models — read
|
|
40
|
+
the current provider ToS, not a blog.
|
|
41
|
+
- **Open-weight licenses** vary and are **not** all OSI-open: Llama ships under the Meta Llama
|
|
42
|
+
Community License (with acceptable-use + naming/derivative terms), Gemma has custom Google
|
|
43
|
+
terms, some models (e.g. Codestral-class) are non-production/research-only, and Qwen license
|
|
44
|
+
terms vary by size. **Never state a license as bare fact** — open the specific model card,
|
|
45
|
+
licenses change.
|
|
46
|
+
- Record per-example provenance (which model/source produced it) so an audit can trace it.
|
|
47
|
+
|
|
48
|
+
## Deduplication
|
|
49
|
+
|
|
50
|
+
Exact dedup: hash normalized text, drop collisions. Near-dup (the one that matters) —
|
|
51
|
+
**MinHash + LSH** over token/char shingles:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from datasketch import MinHash, MinHashLSH
|
|
55
|
+
|
|
56
|
+
def minhash(text, num_perm=128, k=5):
|
|
57
|
+
m = MinHash(num_perm=num_perm)
|
|
58
|
+
toks = text.split()
|
|
59
|
+
for i in range(len(toks) - k + 1):
|
|
60
|
+
m.update(" ".join(toks[i:i+k]).encode())
|
|
61
|
+
return m
|
|
62
|
+
|
|
63
|
+
lsh, keep = MinHashLSH(threshold=0.8, num_perm=128), []
|
|
64
|
+
for i, ex in enumerate(dataset):
|
|
65
|
+
mh = minhash(ex["text"])
|
|
66
|
+
if not lsh.query(mh): # no near-duplicate already kept
|
|
67
|
+
lsh.insert(str(i), mh); keep.append(i)
|
|
68
|
+
dedup = dataset.select(keep)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
For very large corpora use a batched/distributed dedup (e.g. HF `datatrove`, `text-dedup`)
|
|
72
|
+
rather than an in-memory loop. Tune `threshold` on a sample — too high keeps paraphrase dupes,
|
|
73
|
+
too low deletes legitimately similar-but-distinct examples.
|
|
74
|
+
|
|
75
|
+
## Decontamination (against eval/benchmark test sets)
|
|
76
|
+
|
|
77
|
+
Leakage of test items into training inflates your eval — you measure memorization. Remove any
|
|
78
|
+
training row that overlaps a test item, by **n-gram overlap** (the common convention is a long
|
|
79
|
+
n-gram, e.g. 13-gram, exact match; also embed-and-threshold for paraphrased leakage):
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
def ngrams(text, n=13):
|
|
83
|
+
t = text.lower().split()
|
|
84
|
+
return {" ".join(t[i:i+n]) for i in range(len(t) - n + 1)}
|
|
85
|
+
|
|
86
|
+
contam = set().union(*(ngrams(x["text"]) for x in eval_set)) # build from EVERY eval you report
|
|
87
|
+
clean = dataset.filter(lambda ex: ngrams(ex["text"]).isdisjoint(contam))
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Decontaminate against **every** benchmark you will quote *and* your own private held-out set —
|
|
91
|
+
including any public dataset you synthesized from, since its test split may be in your training
|
|
92
|
+
mix. `lm-eval-harness` and dataset-curation toolkits ship decontamination utilities; prefer a
|
|
93
|
+
maintained one over hand-rolled for scale.
|
|
94
|
+
|
|
95
|
+
## Quality filtering
|
|
96
|
+
|
|
97
|
+
**LIMA** (*Less Is More for Alignment*, arXiv 2305.11206): ~1,000 curated examples produced a
|
|
98
|
+
strong instruction-follower — for teaching **behavior/style/format**, curation and diversity
|
|
99
|
+
beat raw volume. Caveat: LIMA is about *alignment*, not injecting large new *knowledge* — a
|
|
100
|
+
broad domain-knowledge shift still wants scale. Practical filter ladder:
|
|
101
|
+
|
|
102
|
+
1. **Format/structural** — drop empty/truncated turns, malformed JSON, wrong role order, missing
|
|
103
|
+
final assistant turn (SFT), identical `chosen`/`rejected` (preference).
|
|
104
|
+
2. **Length** — cut extreme-short and runaway-long outliers (often degenerate/repetitive).
|
|
105
|
+
3. **Dedup + decontam** (above).
|
|
106
|
+
4. **Diversity** — embed and cluster; downsample over-represented intents so one task is not 80%
|
|
107
|
+
of the set. (Lilac was built for exactly this triage — but its OSS repo was archived
|
|
108
|
+
~July 2025 after the Databricks acquisition; **[verify]** before depending on it.)
|
|
109
|
+
5. **Scoring** — reward model or LLM-as-judge rates helpfulness/correctness; keep the top slice.
|
|
110
|
+
Audit the judge: it has position/length/self-preference biases; spot-check by hand.
|
|
111
|
+
|
|
112
|
+
Always keep a discarded-rows sample so filtering decisions are reviewable, not a black hole.
|
|
113
|
+
|
|
114
|
+
## Licensing — two separate questions
|
|
115
|
+
|
|
116
|
+
1. **Your dataset's license** — what you release the JSONL under, and whether you *may* (you
|
|
117
|
+
cannot relicense others' data by aggregating it).
|
|
118
|
+
2. **Source-usage restrictions** — the terms attached to where each row came from: scraped-site
|
|
119
|
+
ToS, the license of any base dataset, and the model-output ToS above. These bind even if you
|
|
120
|
+
never publish. A `source`/`license` provenance column per row makes an audit tractable.
|
|
121
|
+
|
|
122
|
+
Write a **data card** (HF dataset README front-matter): license, sources, generation method,
|
|
123
|
+
dedup/decontam done, known biases, intended use.
|
|
124
|
+
|
|
125
|
+
## Tooling summary
|
|
126
|
+
|
|
127
|
+
| Tool | Use | Note |
|
|
128
|
+
| --- | --- | --- |
|
|
129
|
+
| distilabel | synthetic data / AI-feedback pipelines | Argilla/HF, v1.x, → `Distiset` |
|
|
130
|
+
| Argilla | human annotation/review UI | vet and label examples |
|
|
131
|
+
| HF `datasets` | load/map/filter/push | the substrate |
|
|
132
|
+
| datatrove / text-dedup | large-scale dedup | when datasketch loop is too small |
|
|
133
|
+
| lm-eval-harness | eval + decontamination utils | report metrics on the clean split |
|
|
134
|
+
| Lilac | dataset exploration/clustering | **OSS archived ~2025-07 [verify]** |
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: unsloth
|
|
3
|
+
description: "Use when fine-tuning an open-weight LLM fast on ONE GPU with low VRAM — Unsloth's FastLanguageModel/FastModel + 4-bit QLoRA + trl SFTTrainer, response-only loss masking via get_chat_template/train_on_responses_only, GRPO reasoning FT, and export to merged-16bit / GGUF / push_to_hub for Ollama or vLLM. Triggers: 'fine-tune Llama/Qwen/Gemma/gpt-oss on a single 16GB/24GB GPU', 'QLoRA OOMs on my GPU, make it fit', 'train ~2x faster with less VRAM', 'why is my loss covering the prompt / how do I mask the user turn', 'save my LoRA as GGUF Q4_K_M for Ollama', 'ajustar un modelo en una sola GPU sense quedar-me sense VRAM'. NOT whether/why/which method to fine-tune or trl/peft theory (that is finetuning), NOT running the exported GGUF locally (that is ollama), NOT serving-engine flags/throughput (that is vllm), NOT building the JSONL dataset (that is training-data)."
|
|
4
|
+
tags: [unsloth, qlora, lora, single-gpu, gguf, fine-tuning]
|
|
5
|
+
recommends: [finetuning, training-data, open-weights, ollama, huggingface]
|
|
6
|
+
origin: risco
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Unsloth — fast, low-VRAM fine-tuning on one GPU
|
|
10
|
+
|
|
11
|
+
Unsloth is a fine-tuning *backend*: hand-written Triton kernels + a patched LoRA/QLoRA path that make
|
|
12
|
+
`transformers` + `trl` training run faster and fit a much bigger model on a single consumer GPU. You
|
|
13
|
+
reach for it when the *decision to fine-tune is already made* and the problem is now "make this run on
|
|
14
|
+
the one GPU I have." This skill owns the backend + the export mechanics. It does **not** decide
|
|
15
|
+
whether fine-tuning is even the right move (`finetuning`), and it does **not** run the model you
|
|
16
|
+
export (`ollama` / `vllm`).
|
|
17
|
+
|
|
18
|
+
## Read this first (the two things that bite everyone)
|
|
19
|
+
|
|
20
|
+
1. **Single-GPU is the free-tier assumption.** The open (Apache-2.0) core is built for one GPU.
|
|
21
|
+
Multi-GPU / multi-node "works but a better version is coming" per the docs, and the polished
|
|
22
|
+
multi-GPU + full-finetuning path is gated behind the paid Pro/Enterprise tiers — **verify the
|
|
23
|
+
current split at docs.unsloth.ai before you promise anyone `torchrun --nproc 8`.** If the plan is
|
|
24
|
+
truly multi-node from day one, that is an `axolotl`/native-`trl`/`accelerate` job, not this.
|
|
25
|
+
2. **You must mask the prompt or your loss is wrong.** Fine-tuning a chat model means computing loss
|
|
26
|
+
on the *assistant* turn only. Use Unsloth's `get_chat_template` for the format and
|
|
27
|
+
`train_on_responses_only` for the mask. Skip it and the model trains on predicting the user's
|
|
28
|
+
words too — loss looks fine, behaviour is subtly broken (and on some templates you hit a
|
|
29
|
+
zero-loss trap). This is the single most common mistake; it is section 4 for a reason.
|
|
30
|
+
|
|
31
|
+
### Version / performance reality (fast-moving — verify at author time)
|
|
32
|
+
|
|
33
|
+
The headline, straight off docs.unsloth.ai (accessed 2026-07): **~2x faster training with ~70% less
|
|
34
|
+
VRAM, no accuracy loss**, on a single GPU with the free core. Treat that as a *class* of improvement,
|
|
35
|
+
not a contract:
|
|
36
|
+
|
|
37
|
+
- The baseline is a **standard Hugging Face + FlashAttention-2 QLoRA** pipeline, not "raw PyTorch."
|
|
38
|
+
- Numbers are **model-, GPU-, and config-specific.** Some pages/reviews cite ~60% VRAM; GRPO/RL
|
|
39
|
+
claims ~80% less VRAM; MoE (e.g. gpt-oss, Qwen3-family MoE) shows much larger multipliers on
|
|
40
|
+
specific hardware (up to ~7–12x on a B200 in Unsloth's own MoE post). **Do not quote a single
|
|
41
|
+
number as gospel — cite the docs page you read and hedge.**
|
|
42
|
+
- Licensing/pricing also moves: core is Apache-2.0 and free; a paid Pro tier and an Enterprise
|
|
43
|
+
(contact-sales) tier add multi-GPU/multi-node, full-parameter training, and faster kernels. **Check
|
|
44
|
+
unsloth.ai/pricing for the live tiers and figures.**
|
|
45
|
+
|
|
46
|
+
### Setup
|
|
47
|
+
|
|
48
|
+
Notebook-centric by design — the fastest path is one of the maintained Colab/Kaggle notebooks
|
|
49
|
+
(`unslothai/notebooks`). Locally:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install unsloth # pulls unsloth + unsloth_zoo; expects a recent PyTorch + CUDA
|
|
53
|
+
python -c "import unsloth; print(unsloth.__version__)"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
NVIDIA is the first-class target (min ~CUDA-capable GPU, works down to ~a free-Colab T4 for small
|
|
57
|
+
models). AMD (ROCm) and Intel GPU support have landed as install targets — **verify your hardware on
|
|
58
|
+
the docs' requirements page before assuming it works.** Don't pin a brittle version in your head;
|
|
59
|
+
`unsloth` ships frequently — install fresh and read its startup banner (it prints the versions it
|
|
60
|
+
patched).
|
|
61
|
+
|
|
62
|
+
## Supported models (verify the live list)
|
|
63
|
+
|
|
64
|
+
Unsloth advertises **500+ models** across text, vision, and TTS/embeddings. Families you can expect
|
|
65
|
+
(confirm the specific checkpoint at docs.unsloth.ai/models — new releases land within days):
|
|
66
|
+
|
|
67
|
+
- **Text:** Llama, Qwen, Gemma, Mistral/Mixtral, Phi, DeepSeek, GLM, and **gpt-oss** (OpenAI's
|
|
68
|
+
open-weight MoE).
|
|
69
|
+
- **Vision (VLM):** e.g. Qwen-VL, Gemma vision, Llama-vision — via `FastVisionModel`.
|
|
70
|
+
- Plus TTS and embedding fine-tunes in the notebook zoo.
|
|
71
|
+
|
|
72
|
+
Prefer Unsloth's **pre-quantized 4-bit repos** (`unsloth/<model>-unsloth-bnb-4bit`) — faster download,
|
|
73
|
+
fewer OOMs. Which base model + **which license** is right for you is an `open-weights` question, not
|
|
74
|
+
this one: **never assert a model's license from memory** (Llama = Meta Community license, Gemma =
|
|
75
|
+
custom terms, gpt-oss/Qwen vary by size) — read the model card.
|
|
76
|
+
|
|
77
|
+
## Canonical flow
|
|
78
|
+
|
|
79
|
+
Three steps: **load 4-bit → attach LoRA → SFTTrainer**. `FastModel` is the newer unified loader (text
|
|
80
|
+
+ vision); `FastLanguageModel` is the text path and still owns `.get_peft_model`.
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from unsloth import FastLanguageModel
|
|
84
|
+
import torch
|
|
85
|
+
from trl import SFTTrainer, SFTConfig
|
|
86
|
+
from datasets import load_dataset
|
|
87
|
+
|
|
88
|
+
max_seq_length = 2048 # Unsloth does RoPE scaling internally — pick what you need
|
|
89
|
+
|
|
90
|
+
# 1) Load a (pre-quantized) base in 4-bit. This is the QLoRA memory win.
|
|
91
|
+
model, tokenizer = FastLanguageModel.from_pretrained(
|
|
92
|
+
model_name = "unsloth/Meta-Llama-3.1-8B-Instruct-bnb-4bit", # verify current id
|
|
93
|
+
max_seq_length= max_seq_length,
|
|
94
|
+
load_in_4bit = True, # QLoRA. False + load_in_16bit=True => 16-bit LoRA
|
|
95
|
+
# load_in_8bit / load_in_16bit / full_finetuning are the other switches
|
|
96
|
+
# token = "hf_...", # only for gated repos
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# 2) Attach LoRA adapters — you train ~1% of weights.
|
|
100
|
+
model = FastLanguageModel.get_peft_model(
|
|
101
|
+
model,
|
|
102
|
+
r = 16, # rank: 8/16/32; higher = more capacity, more VRAM
|
|
103
|
+
lora_alpha = 16, # a common default is alpha == r (some recipes use 2*r)
|
|
104
|
+
target_modules = ["q_proj","k_proj","v_proj","o_proj",
|
|
105
|
+
"gate_proj","up_proj","down_proj"],
|
|
106
|
+
lora_dropout = 0, # 0 is the optimized path
|
|
107
|
+
bias = "none", # "none" is the optimized path
|
|
108
|
+
use_gradient_checkpointing = "unsloth", # "unsloth" = ~30% less VRAM, fits longer context
|
|
109
|
+
random_state = 3407,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# 3) Train with trl's SFTTrainer (see section 4 before you call .train()).
|
|
113
|
+
dataset = load_dataset("json", data_files="train.jsonl", split="train") # your data
|
|
114
|
+
trainer = SFTTrainer(
|
|
115
|
+
model = model, tokenizer = tokenizer, train_dataset = dataset,
|
|
116
|
+
args = SFTConfig(
|
|
117
|
+
max_seq_length = max_seq_length,
|
|
118
|
+
per_device_train_batch_size = 2,
|
|
119
|
+
gradient_accumulation_steps = 4, # effective batch = 2*4
|
|
120
|
+
warmup_steps = 10,
|
|
121
|
+
max_steps = 60, # or num_train_epochs = 1
|
|
122
|
+
learning_rate = 2e-4,
|
|
123
|
+
logging_steps = 1,
|
|
124
|
+
optim = "adamw_8bit", # 8-bit optimizer = more VRAM saved
|
|
125
|
+
output_dir = "outputs",
|
|
126
|
+
seed = 3407,
|
|
127
|
+
),
|
|
128
|
+
)
|
|
129
|
+
trainer.train()
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
MoE caveat: 4-bit QLoRA is **not** supported for MoE models yet — load MoE in 16-bit and LoRA the
|
|
133
|
+
`gate_up_proj` / `down_proj` layers. (`load_in_4bit=False` for gpt-oss/Qwen3-MoE.) Verify on
|
|
134
|
+
docs.unsloth.ai/basics/faster-moe.
|
|
135
|
+
|
|
136
|
+
## Chat templates + response-only loss (do not skip)
|
|
137
|
+
|
|
138
|
+
Format with Unsloth's template helper — **not** a hand-written string — so the special tokens match
|
|
139
|
+
what the base model was trained on:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from unsloth.chat_templates import get_chat_template
|
|
143
|
+
|
|
144
|
+
tokenizer = get_chat_template(tokenizer, chat_template = "llama-3.1") # match your base model
|
|
145
|
+
# then map your messages -> a "text" column via tokenizer.apply_chat_template(...)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Then wrap the trainer so **loss is computed on the assistant turn only**:
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
from unsloth.chat_templates import train_on_responses_only
|
|
152
|
+
|
|
153
|
+
trainer = train_on_responses_only(
|
|
154
|
+
trainer,
|
|
155
|
+
instruction_part = "<|start_header_id|>user<|end_header_id|>\n\n", # Llama-3
|
|
156
|
+
response_part = "<|start_header_id|>assistant<|end_header_id|>\n\n",
|
|
157
|
+
)
|
|
158
|
+
# Gemma-3 would use: instruction_part="<start_of_turn>user\n", response_part="<start_of_turn>model\n"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The `instruction_part` / `response_part` strings are the **template's own turn markers** — they must
|
|
162
|
+
match the chat template you applied, per model. Verify the mask worked before spending GPU-hours:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
# labels are -100 where masked. Decoding the non-masked tokens should show ONLY the answer.
|
|
166
|
+
print(tokenizer.decode(trainer.train_dataset[0]["input_ids"]))
|
|
167
|
+
print(tokenizer.decode([tokenizer.pad_token_id if x == -100 else x
|
|
168
|
+
for x in trainer.train_dataset[0]["labels"]]))
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
More templates, thinking-mode (`enable_thinking`), and the vision path are in
|
|
172
|
+
[references/masking-and-templates.md](references/masking-and-templates.md).
|
|
173
|
+
|
|
174
|
+
## GRPO / reasoning fine-tuning (brief)
|
|
175
|
+
|
|
176
|
+
Unsloth supports RL (GRPO and variants) with the same low-VRAM story — it plugs into `trl`'s
|
|
177
|
+
`GRPOTrainer` / `GRPOConfig` and can use a built-in vLLM engine (`fast_inference=True`) for the
|
|
178
|
+
rollout generation. Instead of imitating a target string, GRPO optimizes **reward functions** you
|
|
179
|
+
write (e.g. "answer matches ground truth", "output obeys the `<reasoning>/<answer>` format"). The docs
|
|
180
|
+
cite ~80% less VRAM for GRPO vs a standard setup — verify. This is how you turn a base model into a
|
|
181
|
+
reasoning model on one GPU. The *choice* of SFT vs DPO vs GRPO is a `finetuning` decision; the
|
|
182
|
+
mechanics + a runnable GSM8K reward example live in [references/grpo.md](references/grpo.md).
|
|
183
|
+
|
|
184
|
+
## Export (the other half of this skill)
|
|
185
|
+
|
|
186
|
+
After `trainer.train()` you have LoRA adapters. Pick an export by where it's going:
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
# A) Merge LoRA into the base at 16-bit — the portable, high-quality artifact (vLLM, re-hosting).
|
|
190
|
+
model.save_pretrained_merged("model_16bit", tokenizer, save_method = "merged_16bit")
|
|
191
|
+
model.push_to_hub_merged("user/model", tokenizer, save_method = "merged_16bit", token = "hf_...")
|
|
192
|
+
|
|
193
|
+
# B) Keep just the adapters (small, hot-swappable).
|
|
194
|
+
model.save_pretrained_merged("model_lora", tokenizer, save_method = "lora")
|
|
195
|
+
|
|
196
|
+
# C) GGUF for llama.cpp / Ollama — choose the quant that trades size vs quality.
|
|
197
|
+
model.save_pretrained_gguf("model_gguf", tokenizer, quantization_method = "q4_k_m")
|
|
198
|
+
model.push_to_hub_gguf("user/model-gguf", tokenizer,
|
|
199
|
+
quantization_method = ["q4_k_m", "q8_0", "f16"], token = "hf_...")
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Then **running** the GGUF is an `ollama` job (`ollama create` from the file, `ollama run`), and
|
|
203
|
+
serving the merged-16bit at scale is a `vllm` job. Quant guidance: **Q4_K_M** is the everyday
|
|
204
|
+
size/quality sweet spot, **Q8_0** near-lossless, **f16** the unquantized ceiling — lower quant = smaller
|
|
205
|
+
+ faster but real quality loss. Do **not** merge to 4-bit as your keeper artifact (quality drops;
|
|
206
|
+
it's a niche path). Full export matrix + the Ollama/llama.cpp handoff:
|
|
207
|
+
[references/export.md](references/export.md).
|
|
208
|
+
|
|
209
|
+
## Guardrails / gotchas
|
|
210
|
+
|
|
211
|
+
- **Single-GPU assumption (OSS).** Don't design a multi-node run on the free core; verify the paid
|
|
212
|
+
multi-GPU/multi-node status at docs.unsloth.ai first. `CUDA_VISIBLE_DEVICES` to one GPU if unsure.
|
|
213
|
+
- **No mask = wrong training.** Without `train_on_responses_only`, loss covers the prompt; some
|
|
214
|
+
templates then show ~0 loss. Always decode-check the labels once.
|
|
215
|
+
- **Wrong chat template = garbage.** The `chat_template` and the mask's `instruction_part`/
|
|
216
|
+
`response_part` must match the *base model's* markers. Use `get_chat_template`; never hand-roll.
|
|
217
|
+
- **MoE ≠ 4-bit yet.** Load MoE models in 16-bit; QLoRA-4bit is unsupported for them (verify).
|
|
218
|
+
- **GGUF quant is lossy.** Q4_K_M for size, Q8_0/f16 when quality matters. Merged-4bit is discouraged.
|
|
219
|
+
- **`import unsloth` first.** Import it before `transformers`/`trl` so its patches apply; heed the
|
|
220
|
+
startup banner that prints patched versions.
|
|
221
|
+
- **Numbers drift.** The 2x/70% headline is a *class*, not a guarantee — cite the docs page and hedge.
|
|
222
|
+
|
|
223
|
+
## Related skills
|
|
224
|
+
|
|
225
|
+
- **`finetuning`** — the method layer: FT-vs-RAG-vs-prompt, SFT/DPO/GRPO choice, hyperparameters, the
|
|
226
|
+
backend-agnostic `trl`/`peft` theory. Unsloth is *one fast backend* under it; go there for "should
|
|
227
|
+
I / how much / which method." This skill is "make it run on my GPU."
|
|
228
|
+
- **`training-data`** — build the JSONL messages / preference pairs you feed the trainer. Data shape
|
|
229
|
+
and quality live there; this skill assumes you already have a dataset.
|
|
230
|
+
- **`open-weights`** — choose the base model + read its license/size tradeoffs before you fine-tune.
|
|
231
|
+
- **`ollama`** — run the GGUF you export, on one box. Export here, run there.
|
|
232
|
+
- **`huggingface`** — get the base weights and host/push the result; `vllm` serves the merged-16bit at
|
|
233
|
+
throughput. This skill produces the artifact; those consume it.
|
|
234
|
+
|
|
235
|
+
## Checklist
|
|
236
|
+
|
|
237
|
+
- [ ] Fine-tuning is actually the right move and method is chosen (confirmed via `finetuning`).
|
|
238
|
+
- [ ] Base model + license verified on its card (`open-weights`); using a current `unsloth/*-4bit` id.
|
|
239
|
+
- [ ] `from_pretrained(load_in_4bit=True, max_seq_length=…)` → `get_peft_model(r, target_modules, …)`.
|
|
240
|
+
- [ ] `get_chat_template` applied with the model's correct template.
|
|
241
|
+
- [ ] `train_on_responses_only` applied AND the label mask decode-checked (answer-only).
|
|
242
|
+
- [ ] Fits the one GPU (batch × grad-accum, `use_gradient_checkpointing="unsloth"`, `adamw_8bit`).
|
|
243
|
+
- [ ] Exported for the target: merged_16bit (vLLM/re-host) or GGUF Q4_K_M/Q8_0 (Ollama/llama.cpp).
|
|
244
|
+
- [ ] Any speed/VRAM/tier/model claim I stated is hedged + cited to docs.unsloth.ai (not memory).
|
|
245
|
+
|
|
246
|
+
## References
|
|
247
|
+
|
|
248
|
+
- [references/masking-and-templates.md](references/masking-and-templates.md) — `get_chat_template`
|
|
249
|
+
options, per-model `instruction_part`/`response_part` pairs, thinking-mode, the vision path, and the
|
|
250
|
+
label-mask sanity check.
|
|
251
|
+
- [references/grpo.md](references/grpo.md) — GRPO end-to-end: `GRPOConfig`/`GRPOTrainer`, `vLLM`
|
|
252
|
+
`fast_inference`, a GSM8K reward-function set, and loss-type/DAPO knobs.
|
|
253
|
+
- [references/export.md](references/export.md) — full export matrix (merged_16bit / lora / merged_4bit
|
|
254
|
+
/ GGUF), quant-method table, `push_to_hub_*`, manual `convert_hf_to_gguf.py`, and the Ollama handoff.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Evals for the `unsloth` skill
|
|
2
|
+
|
|
3
|
+
`cases.yaml` is a routing + capability fixture, not an automated harness. For each `should_trigger`
|
|
4
|
+
prompt, confirm the router picks `unsloth` (fast low-VRAM single-GPU fine-tuning + GGUF export). For
|
|
5
|
+
each `should_not_trigger`, confirm it routes to the named sibling — method choice to `finetuning`,
|
|
6
|
+
dataset to `training-data`, running the GGUF to `ollama`, throughput serving to `vllm`, base-model
|
|
7
|
+
choice to `open-weights` — and not here. For the `capability` case, check the answer covers every
|
|
8
|
+
`must_include` bullet: the from_pretrained→get_peft_model→SFTTrainer flow, response-only masking, GGUF
|
|
9
|
+
export + the ollama handoff, the hedged speed/VRAM claim, and the single-GPU guardrail. No GPUs or
|
|
10
|
+
network needed.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
skill: unsloth
|
|
2
|
+
|
|
3
|
+
should_trigger:
|
|
4
|
+
- prompt: "I want to QLoRA fine-tune Llama-3.1-8B but it OOMs on my 16GB GPU — how do I make it fit?"
|
|
5
|
+
why: Core niche — fast, low-VRAM single-GPU fine-tuning; the fit problem is exactly what load_in_4bit + get_peft_model + adamw_8bit + unsloth gradient checkpointing solve.
|
|
6
|
+
- prompt: "How do I fine-tune gpt-oss on a single 24GB GPU roughly 2x faster with less VRAM?"
|
|
7
|
+
why: Names the backend's headline (2x/less-VRAM), a single GPU, and a supported MoE model — squarely this skill.
|
|
8
|
+
- prompt: "My chat fine-tune's loss looks like it's covering the user turn — how do I mask the prompt so it only trains on the response?"
|
|
9
|
+
why: The train_on_responses_only / get_chat_template masking problem, the load-bearing gotcha owned here.
|
|
10
|
+
- prompt: "After training my LoRA with Unsloth, how do I export it to GGUF Q4_K_M for Ollama?"
|
|
11
|
+
why: Export mechanics (save_pretrained_gguf, quant choice, handoff to ollama) are half of this skill.
|
|
12
|
+
- prompt: "Turn a base Qwen into a reasoning model with GRPO on one GPU using reward functions."
|
|
13
|
+
why: GRPO/reasoning FT via GRPOTrainer + fast_inference vLLM, the low-VRAM RL path this skill covers.
|
|
14
|
+
- prompt: "Vull ajustar un model a una sola GPU sense quedar-me sense VRAM amb Unsloth."
|
|
15
|
+
why: Catalan; single-GPU low-VRAM fine-tuning with Unsloth by name — the exact trigger.
|
|
16
|
+
|
|
17
|
+
should_not_trigger:
|
|
18
|
+
- prompt: "Should I fine-tune, use RAG, or just prompt-engineer for my support bot? And SFT vs DPO?"
|
|
19
|
+
route_to: finetuning
|
|
20
|
+
why: The whether/why/which-method decision is the method layer, not the backend that makes it run.
|
|
21
|
+
- prompt: "How do I format my conversations into a JSONL messages dataset for fine-tuning?"
|
|
22
|
+
route_to: training-data
|
|
23
|
+
why: Dataset construction/quality; this skill assumes the dataset already exists.
|
|
24
|
+
- prompt: "I exported a GGUF — how do I run it locally, write a Modelfile, and size VRAM in Ollama?"
|
|
25
|
+
route_to: ollama
|
|
26
|
+
why: Running the exported artifact locally is Ollama's job; Unsloth stops at producing the file.
|
|
27
|
+
- prompt: "Serve my merged 16-bit model at high throughput with tensor parallelism and continuous batching."
|
|
28
|
+
route_to: vllm
|
|
29
|
+
why: Serving-engine flags/throughput are the serving skill, not the training backend.
|
|
30
|
+
- prompt: "Which open model and license should I pick as my base — Llama vs Qwen vs Gemma?"
|
|
31
|
+
route_to: open-weights
|
|
32
|
+
why: Base-model selection + license tradeoffs are the choosing layer, not the fine-tuning backend.
|
|
33
|
+
|
|
34
|
+
capability:
|
|
35
|
+
- scenario: "I have one RTX 4090 (24GB). Fine-tune Llama-3.1-8B-Instruct on my chat JSONL with Unsloth so loss is only on the assistant turns, then export a Q4_K_M GGUF to run in Ollama. It keeps OOMing."
|
|
36
|
+
must_include:
|
|
37
|
+
- "FastLanguageModel.from_pretrained with load_in_4bit=True and max_seq_length, using a pre-quantized unsloth/*-bnb-4bit base id (verify the current id)."
|
|
38
|
+
- "get_peft_model with r/lora_alpha/target_modules and use_gradient_checkpointing='unsloth'; plus VRAM levers for OOM (batch size + gradient_accumulation_steps, optim='adamw_8bit')."
|
|
39
|
+
- "get_chat_template for the correct Llama-3.1 template AND train_on_responses_only with matching instruction_part/response_part so loss is response-only — with a decode/label sanity check."
|
|
40
|
+
- "Export via save_pretrained_gguf(quantization_method='q4_k_m') and the note that running it is an ollama job (create from the GGUF, run); merge to 16bit for vLLM instead."
|
|
41
|
+
- "The honesty hedge: the ~2x faster / ~70% less VRAM headline is model/GPU/config-specific vs a HF+FA2 QLoRA baseline — verify current numbers at docs.unsloth.ai and don't quote one number as gospel."
|
|
42
|
+
- "The single-GPU guardrail (OSS core is single-GPU; multi-GPU/multi-node is the paid/verify-live tier) and the boundary that method choice is finetuning, not this."
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Export: from trained LoRA to a runnable artifact
|
|
2
|
+
|
|
3
|
+
After `trainer.train()` you hold LoRA adapters on top of a (possibly 4-bit) base. Export depends on
|
|
4
|
+
where it runs next. Tracks docs.unsloth.ai inference-and-deployment pages (accessed 2026-07).
|
|
5
|
+
|
|
6
|
+
## The matrix
|
|
7
|
+
|
|
8
|
+
| Target | Method | Notes |
|
|
9
|
+
| -------------------------- | ------------------------------------------------------------- | ----- |
|
|
10
|
+
| vLLM / re-host / portable | `save_pretrained_merged(dir, tok, save_method="merged_16bit")`| Base + LoRA merged at 16-bit. The high-quality keeper. |
|
|
11
|
+
| Small, hot-swappable | `save_pretrained_merged(dir, tok, save_method="lora")` | Adapters only (~MBs). Load onto the base at run time. |
|
|
12
|
+
| Ollama / llama.cpp | `save_pretrained_gguf(dir, tok, quantization_method="q4_k_m")`| Converts + quantizes to GGUF. |
|
|
13
|
+
| DPO / niche 4-bit inference| `save_method="merged_4bit"` | **Discouraged** — quality loss; only if a tool needs it. |
|
|
14
|
+
|
|
15
|
+
## Merge to 16-bit (recommended keeper)
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
model.save_pretrained_merged("model_16bit", tokenizer, save_method = "merged_16bit")
|
|
19
|
+
# push instead of / in addition to saving:
|
|
20
|
+
model.push_to_hub_merged("user/model", tokenizer,
|
|
21
|
+
save_method = "merged_16bit", token = "hf_...")
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`merged_16bit` is the format vLLM and most serving stacks expect. Prefer it over `merged_4bit` — merge
|
|
25
|
+
at 16-bit, quantize downstream if you need to.
|
|
26
|
+
|
|
27
|
+
## LoRA adapters only
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
model.save_pretrained("finetuned_lora"); tokenizer.save_pretrained("finetuned_lora")
|
|
31
|
+
# or save_pretrained_merged(..., save_method="lora")
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Tiny and hot-swappable (e.g. vLLM LoRA hot-swap). Requires the base at inference time.
|
|
35
|
+
|
|
36
|
+
## GGUF for Ollama / llama.cpp
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
# one quant:
|
|
40
|
+
model.save_pretrained_gguf("model_gguf", tokenizer, quantization_method = "q4_k_m")
|
|
41
|
+
# several at once, pushed to the Hub:
|
|
42
|
+
model.push_to_hub_gguf("user/model-gguf", tokenizer,
|
|
43
|
+
quantization_method = ["q4_k_m", "q8_0", "f16"], token = "hf_...")
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Quant guide (size vs quality — this is a real tradeoff, not free):
|
|
47
|
+
|
|
48
|
+
| Method | ~bits/weight | Use it for |
|
|
49
|
+
| -------- | ------------ | ---------- |
|
|
50
|
+
| `q4_k_m` | ~4.9 | Everyday default: ~half the size for a few % quality loss. |
|
|
51
|
+
| `q5_k_m` | ~5.5 | A notch more quality than Q4 for a bit more size. |
|
|
52
|
+
| `q8_0` | ~8.5 | Near-lossless; larger. |
|
|
53
|
+
| `f16` | 16 | Unquantized ceiling; biggest. |
|
|
54
|
+
|
|
55
|
+
Lower than Q4 (Q2/Q3) drops quality sharply — avoid unless desperate for size.
|
|
56
|
+
|
|
57
|
+
### Manual conversion (when the helper can't, or you want control)
|
|
58
|
+
|
|
59
|
+
Merge to 16-bit first, then run llama.cpp's converter:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
python llama.cpp/convert_hf_to_gguf.py model_16bit \
|
|
63
|
+
--outfile model-F16.gguf --outtype f16 --split-max-size 50G
|
|
64
|
+
# then quantize with llama.cpp's quantize tool to q4_k_m / q8_0, etc.
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Handoff — this skill stops at the file
|
|
68
|
+
|
|
69
|
+
- **Run the GGUF locally →** `ollama`. Roughly: `ollama create <name> -f Modelfile` with
|
|
70
|
+
`FROM ./model-Q4_K_M.gguf`, then `ollama run <name>`. The Modelfile/quant/VRAM details are its job.
|
|
71
|
+
Unsloth's docs also show `OLLAMA_MODELS=unsloth ollama run merged_file.gguf` for a quick check.
|
|
72
|
+
- **Serve merged-16bit at throughput →** `vllm` (engine flags, batching, LoRA hot-swap).
|
|
73
|
+
- **Host/share the weights →** `huggingface` (the `push_to_hub_*` calls above land there).
|
|
74
|
+
|
|
75
|
+
Export is the last thing this skill owns; running and serving belong to those siblings.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# GRPO / reasoning fine-tuning with Unsloth
|
|
2
|
+
|
|
3
|
+
Mechanics only. **Whether** to do RL vs SFT vs DPO is a `finetuning` decision. Tracks
|
|
4
|
+
docs.unsloth.ai's RL guide (accessed 2026-07); reward APIs and loss-type flags move — verify.
|
|
5
|
+
|
|
6
|
+
## The idea
|
|
7
|
+
|
|
8
|
+
GRPO (Group Relative Policy Optimization) doesn't imitate a target string. It samples several
|
|
9
|
+
completions per prompt, scores each with **reward functions you write**, and pushes weights toward the
|
|
10
|
+
higher-reward samples. That's how you train a model to *reason* (produce correct answers in a required
|
|
11
|
+
format) rather than memorize outputs. Unsloth's win here is memory — the docs cite ~80% less VRAM for
|
|
12
|
+
GRPO vs a standard setup (verify), and it can drive generation through a built-in vLLM engine.
|
|
13
|
+
|
|
14
|
+
## Load with fast inference
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from unsloth import FastLanguageModel
|
|
18
|
+
|
|
19
|
+
model, tokenizer = FastLanguageModel.from_pretrained(
|
|
20
|
+
model_name = "unsloth/Llama-3.1-8B-Instruct", # verify current id
|
|
21
|
+
max_seq_length = 1024, # room for the reasoning trace
|
|
22
|
+
load_in_4bit = True,
|
|
23
|
+
fast_inference = True, # use the built-in vLLM engine for rollouts
|
|
24
|
+
gpu_memory_utilization = 0.8, # lower if you OOM
|
|
25
|
+
)
|
|
26
|
+
model = FastLanguageModel.get_peft_model(model, r = 32, lora_alpha = 64,
|
|
27
|
+
target_modules = ["q_proj","k_proj","v_proj","o_proj",
|
|
28
|
+
"gate_proj","up_proj","down_proj"],
|
|
29
|
+
use_gradient_checkpointing = "unsloth", random_state = 3407)
|
|
30
|
+
# For memory-efficient GRPO with vLLM you may also set:
|
|
31
|
+
# os.environ["UNSLOTH_VLLM_STANDBY"] = "1"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Reward functions (GSM8K-style)
|
|
35
|
+
|
|
36
|
+
Each reward fn takes `completions` (+ `prompts`, `answer`, `**kwargs`) and returns a list of floats,
|
|
37
|
+
one per completion. Combine several — correctness plus format shaping:
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
import re
|
|
41
|
+
|
|
42
|
+
def correctness_reward(prompts, completions, answer, **kw):
|
|
43
|
+
responses = [c[0]["content"] for c in completions]
|
|
44
|
+
got = [extract_xml_answer(r) for r in responses]
|
|
45
|
+
return [2.0 if g == a else 0.0 for g, a in zip(got, answer)]
|
|
46
|
+
|
|
47
|
+
def strict_format_reward(completions, **kw):
|
|
48
|
+
pattern = r"^<reasoning>\n.*?\n</reasoning>\n<answer>\n.*?\n</answer>\n$"
|
|
49
|
+
responses = [c[0]["content"] for c in completions]
|
|
50
|
+
return [0.5 if re.match(pattern, r, re.S) else 0.0 for r in responses]
|
|
51
|
+
|
|
52
|
+
def extract_xml_answer(text):
|
|
53
|
+
return text.split("<answer>")[-1].split("</answer>")[0].strip()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Keep rewards simple and hard to game — a sloppy reward degrades the model (reward hacking).
|
|
57
|
+
|
|
58
|
+
## Train
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from trl import GRPOConfig, GRPOTrainer
|
|
62
|
+
|
|
63
|
+
trainer = GRPOTrainer(
|
|
64
|
+
model = model, processing_class = tokenizer,
|
|
65
|
+
reward_funcs = [correctness_reward, strict_format_reward],
|
|
66
|
+
train_dataset = dataset, # prompts + ground-truth "answer"
|
|
67
|
+
args = GRPOConfig(
|
|
68
|
+
learning_rate = 5e-6,
|
|
69
|
+
per_device_train_batch_size = 1,
|
|
70
|
+
gradient_accumulation_steps = 4,
|
|
71
|
+
num_generations = 8, # completions sampled per prompt (the "group")
|
|
72
|
+
max_prompt_length = 256,
|
|
73
|
+
max_completion_length = 512,
|
|
74
|
+
max_steps = 250,
|
|
75
|
+
output_dir = "outputs_grpo",
|
|
76
|
+
# loss_type = "grpo" | "dr_grpo" | "bnpo" | "dapo"
|
|
77
|
+
# epsilon = 0.2, epsilon_high = 0.28, delta = 1.5 # DAPO / two-sided knobs
|
|
78
|
+
# mask_truncated_completions = True
|
|
79
|
+
),
|
|
80
|
+
)
|
|
81
|
+
trainer.train()
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Notes:
|
|
85
|
+
- `num_generations` is the group size — bigger gives a better reward signal but costs generation time
|
|
86
|
+
and VRAM.
|
|
87
|
+
- Advanced objectives (DAPO, Dr. GRPO) are `loss_type` + `epsilon`/`delta` flags on `GRPOConfig` —
|
|
88
|
+
verify the current names on the RL guide.
|
|
89
|
+
- Reasoning traces need context headroom: budget `max_prompt_length + max_completion_length` under
|
|
90
|
+
`max_seq_length`.
|
|
91
|
+
- Export the result exactly like an SFT run — see [export.md](export.md).
|