-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
178 lines (156 loc) · 8.58 KB
/
Copy pathMakefile
File metadata and controls
178 lines (156 loc) · 8.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# =============================================================================
# Local SLM Data Cleaner (CUDA edition): beginner-friendly pipeline.
#
# Target machine: Linux (Pop!_OS) with an NVIDIA GPU (GTX 1650 4GB or better).
# Run `make help` to list every command, then follow the numbered steps.
#
# You override any setting on the command line, for example:
# make data N=2000 # make 2000 examples instead of 1000
# make train ITERS=1500 # train for more steps
# =============================================================================
# ---- settings you can override on the command line -----------------------
# Keep values on their own lines with no inline comments.
#
# MODEL_PRESET model family shortcut: qwen3-0.6b, qwen3.5-0.8b, minicpm5-1b
# MODEL base model to fine-tune (auto-downloads)
# GGUF_HF stock GGUF repo for the zero-shot baseline
# GGUF_QUANT quant level to download/build (Q8_0, Q4_K_M, ...)
# N number of synthetic examples
# SEED random seed (same seed = same data)
# ITERS training steps
# BATCH training batch size (drop to 2 if you hit CUDA out-of-memory)
# PORT local server port
# ALIAS model name the eval/clean scripts look for
# LLAMA_CPP path to the llama.cpp source checkout (built with CUDA)
MODEL_PRESET ?= qwen3-0.6b
# Model presets — set MODEL_PRESET to quickly switch between supported models.
# Each preset sets MODEL, GGUF_HF, GGUF_QUANT, and ALIAS. Override any
# individually on the command line (e.g. `make train MODEL=...`).
# Switching presets? Run `make clean` first so adapters/GGUF from the old model
# are not reused.
ifeq ($(MODEL_PRESET),qwen3-0.6b)
MODEL ?= Qwen/Qwen3-0.6B
GGUF_HF ?= Qwen/Qwen3-0.6B-GGUF
GGUF_QUANT ?= Q8_0
ALIAS ?= qwen3-0.6b-cleaner
else ifeq ($(MODEL_PRESET),qwen3.5-0.8b)
MODEL ?= Qwen/Qwen3.5-0.8B
GGUF_HF ?= unsloth/Qwen3.5-0.8B-GGUF
GGUF_QUANT ?= Q8_0
ALIAS ?= qwen3.5-0.8b-cleaner
else ifeq ($(MODEL_PRESET),minicpm5-1b)
MODEL ?= openbmb/MiniCPM5-1B
GGUF_HF ?= openbmb/MiniCPM5-1B-GGUF
GGUF_QUANT ?= Q4_K_M
ALIAS ?= minicpm5-1b-cleaner
else
$(error Unknown MODEL_PRESET '$(MODEL_PRESET)'. Run 'make list-models'.)
endif
N ?= 1000
SEED ?= 0
ITERS ?= 1000
BATCH ?= 4
PORT ?= 8080
DATA ?= data
ADAPTERS ?= adapters
FUSED ?= fused
GGUF ?= $(ALIAS).gguf
# GGUF quant file uses lowercase version of GGUF_QUANT in its name.
# E.g. Q8_0 -> -q8_0, Q4_K_M -> -q4_k_m.
QGGUF_SUFFIX = $(shell echo $(GGUF_QUANT) | tr 'A-Z' 'a-z')
QGGUF ?= $(ALIAS)-$(QGGUF_SUFFIX).gguf
LLAMA_CPP ?= ../llama.cpp
LLAMA_BIN ?= $(LLAMA_CPP)/build/bin
PY ?= python3
.DEFAULT_GOAL := help
.PHONY: help list-models setup llama-cpp model data sanity baseline-serve baseline train \
fuse gguf serve eval demo all clean distclean
help: ## show this list of commands
@echo "Local SLM Data Cleaner (CUDA): commands (run them in this order):"
@echo ""
@echo "Model preset: $(MODEL_PRESET) (run 'make list-models' for options)"
@echo ""
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
| awk 'BEGIN{FS=":.*?## "}{printf " \033[36m%-14s\033[0m %s\n", $$1, $$2}'
list-models: ## show available model presets
@echo "Available MODEL_PRESET values:"
@echo ""
@echo " qwen3-0.6b Qwen3-0.6B (default) — 600M params, ~1 GB, Apache-2.0"
@echo " qwen3.5-0.8b Qwen3.5-0.8B — 800M params, ~1.5 GB, Apache-2.0"
@echo " minicpm5-1b MiniCPM5-1B — 1B params, SOTA in class, Apache-2.0"
@echo ""
@echo "Usage: make MODEL_PRESET=minicpm5-1b <command>"
@echo "Set it once: export MODEL_PRESET=minicpm5-1b"
@echo "Switch preset: make clean (drops adapters/GGUF from the previous model)"
# --- STEP 3: install the tools --------------------------------------------- #
setup: ## STEP 3: install Python libraries + the CUDA training stack
@echo ">> Installing runtime packages (requests)..."
$(PY) -m pip install -r requirements.txt
@echo ">> Installing the training stack (torch/transformers/peft/trl)..."
$(PY) -m pip install -r requirements-train.txt
@echo ">> Checking the GPU is visible to torch..."
$(PY) -c "import torch; assert torch.cuda.is_available(), 'no CUDA GPU visible - check nvidia-smi'; print('GPU:', torch.cuda.get_device_name(0))"
@echo ">> Done. Next: make llama-cpp"
llama-cpp: ## STEP 3b: build llama.cpp with CUDA (clones next to this repo)
@test -d $(LLAMA_CPP) || git clone https://github.com/ggml-org/llama.cpp $(LLAMA_CPP)
cmake -S $(LLAMA_CPP) -B $(LLAMA_CPP)/build -DGGML_CUDA=ON
cmake --build $(LLAMA_CPP)/build --config Release -j
@echo ">> Built $(LLAMA_BIN)/llama-server with CUDA. Next: make model"
# --- STEP 4: download the model FRESH -------------------------------------- #
model: ## STEP 4: download the base model from Hugging Face
@echo ">> Model preset: $(MODEL_PRESET)"
@echo ">> Downloading $(MODEL) (first time only, no login needed)..."
@echo ">> It caches in ~/.cache/huggingface so later steps are instant."
$(PY) -c "from transformers import AutoModelForCausalLM, AutoTokenizer; AutoTokenizer.from_pretrained('$(MODEL)'); AutoModelForCausalLM.from_pretrained('$(MODEL)'); print('model ready')"
@echo ">> Done. Next: make data"
# --- STEP 5: make the training data ---------------------------------------- #
data: ## STEP 5a: generate synthetic train/valid/test data (N, SEED)
@echo ">> Generating $(N) synthetic messy->clean examples..."
$(PY) synth/generate.py --n $(N) --out $(DATA) --seed $(SEED)
@echo ">> Done. Next: make sanity"
sanity: ## STEP 5b: check the data is correct (should say 100%)
@echo ">> Checking the held-out test split against the rule-based algorithm..."
$(PY) eval/evaluate.py --data $(DATA)/test.jsonl --algorithm
@echo ">> If the numbers are ~100%, the data is good. Next: make baseline-serve"
# --- STEP 6: measure the model BEFORE training (the 'before' number) ------- #
baseline-serve: ## STEP 6a: serve the STOCK model on the GPU, keep running
@echo ">> Downloading + serving the untrained stock model on port $(PORT)."
@echo ">> Leave this running and open a SECOND terminal for 'make baseline'."
$(LLAMA_BIN)/llama-server -hf $(GGUF_HF):$(GGUF_QUANT) --port $(PORT) --alias $(ALIAS) -ngl 99
baseline: ## STEP 6b: score the stock model (run in the 2nd terminal)
@echo ">> Scoring the untrained model (this is your 'before' score)..."
$(PY) eval/evaluate.py --data $(DATA)/test.jsonl --live --port $(PORT) --model-name $(ALIAS)
# --- STEP 7: fine-tune ------------------------------------------------------ #
train: ## STEP 7: fine-tune the model on your data (uses the GPU)
@echo ">> Fine-tuning $(MODEL) with LoRA for $(ITERS) steps on CUDA..."
@echo ">> Stop the baseline-serve terminal first to free VRAM."
$(PY) train/train_lora.py --model $(MODEL) --data $(DATA) \
--iters $(ITERS) --batch-size $(BATCH) --adapter-path $(ADAPTERS)
@echo ">> Done. Next: make fuse"
fuse: ## STEP 8a: merge the training result back into the model
@echo ">> Merging the LoRA adapter into full model weights..."
$(PY) train/merge_export.py --model $(MODEL) --adapter-path $(ADAPTERS) \
--save-path $(FUSED)
@echo ">> Done. Next: make gguf"
gguf: ## STEP 8b: convert the model to a runnable file (needs llama.cpp source)
@echo ">> Converting to GGUF (the format llama.cpp runs)..."
$(PY) $(LLAMA_CPP)/convert_hf_to_gguf.py $(FUSED) --outfile $(GGUF)
@echo ">> Compressing to $(GGUF_QUANT)..."
$(LLAMA_BIN)/llama-quantize $(GGUF) $(QGGUF) $(GGUF_QUANT)
@echo ">> Done. Next: make serve"
# --- STEP 9: measure the model AFTER training (the 'after' number) --------- #
serve: ## STEP 9a: serve YOUR fine-tuned model on the GPU, keep running
@echo ">> Serving your fine-tuned model on port $(PORT)."
@echo ">> Leave this running and open a SECOND terminal for 'make eval'."
$(LLAMA_BIN)/llama-server -m $(QGGUF) --port $(PORT) --alias $(ALIAS) -ngl 99
eval: ## STEP 9b: score your fine-tuned model (compare to the baseline)
@echo ">> Scoring your fine-tuned model (this is your 'after' score)..."
$(PY) eval/evaluate.py --data $(DATA)/test.jsonl --live --port $(PORT) --model-name $(ALIAS)
demo: ## STEP 10: clean one messy record with your model
$(PY) clean.py --live --port $(PORT) --model-name $(ALIAS)
all: data sanity train fuse gguf ## do steps 5, 7 and 8 in one go (no serving)
@echo ">> Built $(QGGUF). Now run 'make serve', then 'make eval' in a 2nd terminal."
clean: ## delete training artifacts (keeps your data)
rm -rf $(ADAPTERS) $(FUSED) *.gguf __pycache__ */__pycache__
distclean: clean ## delete training artifacts AND generated data
rm -f $(DATA)/*.jsonl