Downloads · 30 days
0
wilsoncheng/qwen2.5-7b-cantonese-lora-v3
qwen2.5-7b-cantonese-lora-v3 is a text generation model from wilsoncheng. Use it when you need the model to write or continue text. It is set up for transformers. The card lists the license as apache-2.0.
LoRA adapter fine-tuned on Qwen2.5-7B-Instruct-4bit for natural Hong Kong Cantonese text generation.
Downloads · 30 days
0
Access
Public
Updated Jun 23, 2026
Repo size
162 MB
Likes
0
Public
Click a slice to open those files.
.safetensors162 MB · 100%
From the Hugging Face model README
LoRA adapter fine-tuned on Qwen2.5-7B-Instruct-4bit for natural Hong Kong Cantonese text generation.
This is a LoRA adapter that adds Cantonese style transfer capability to mlx-community/Qwen2.5-7B-Instruct-4bit. It was trained on 1500 long-phrase (50-200 character) parallel sentence pairs from the HKAllen/cantonese-chinese-parallel-corpus and raptorkwok/cantonese-chinese-parallel-corpus datasets.
The adapter covers all attention projections (q, k, v, o) and all MLP projections (gate, up, down) in the 28 transformer layers — a total of 196 LoRA modules with rank 16, alpha 32, dropout 0.05 (40.7M trainable params, 3.3% of base model).
import mlx.core as mx
import mlx.nn as nn
from mlx_lm import load, generate
from mlx.utils import tree_flatten, tree_unflatten
# Load base model
model, tokenizer = load("mlx-community/Qwen2.5-7B-Instruct-4bit")
# Wrap with LoRA (7 targets, matching training config)
LORA_TARGETS = ["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"]
LORA_CONFIG = {"rank": 16, "scale": 32, "dropout": 0.05}
for layer in model.layers:
types = (nn.Linear, nn.QuantizedLinear)
keys = set()
for name, child in layer.named_modules():
if isinstance(child, types):
for t in LORA_TARGETS:
if name.endswith(t) or f".{t}" in name:
keys.add(name); break
if not keys: continue
named_dict = dict(layer.named_modules())
from mlx_lm.tuner.lora import LoRALinear
lora_layers = []
for k in keys:
layer_obj = named_dict[k]
if isinstance(layer_obj, nn.QuantizedLinear):
lora_layers.append((k, LoRALinear.from_base(layer_obj, **LORA_CONFIG)))
else:
lora_layers.append((k, layer_obj.to_lora(**LORA_CONFIG)))
layer.update_modules(tree_unflatten(lora_layers))
# Load LoRA weights
model.load_weights("adapters.safetensors", strict=False)
# Generate
prompt = "<|im_start|>system\nYou are a helpful assistant who speaks Cantonese.<|im_end|>\n<|im_start|>user\n你喺邊度出世?<|im_end|>\n<|im_start|>assistant\n"
output = generate(model, tokenizer, prompt=prompt, max_tokens=100, verbose=False)
print(output)
| Source | Filter | Used |
|---|---|---|
HKAllen/cantonese-chinese-parallel-corpus | 50 ≤ yue chars ≤ 200 | ~1200 samples |
raptorkwok/cantonese-chinese-parallel-corpus | 50 ≤ yue chars ≤ 200 | ~300 samples |
| Total | 1500 |
Cantonese particle density (per 97,514 response chars): 嘅 1.93%, 喺 0.73%, 咗 0.35%, 唔 0.33%, 嚟 0.16%, 嗰 0.14%.
| Parameter | Value |
|---|---|
| Base model | mlx-community/Qwen2.5-7B-Instruct-4bit (4-bit quantized) |
| LoRA rank | 16 |
| LoRA alpha | 32 |
| LoRA dropout | 0.05 |
| LoRA targets | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj |
| Trainable params | 40.7M (3.31% of base) |
| Optimizer | SGD with momentum 0.9, weight decay 0 |
| Learning rate | 1e-3, cosine schedule, 5-step warmup |
| Batch size | 1, gradient accumulation 8 (effective 8) |
| Max sequence length | 1024 tokens |
| Iterations | 300 |
| Wall time | 40.0 min on M1 Max 32GB |
| Peak memory | 10.06 GB |
| Step | Loss |
|---|---|
| 0 | 0.741 |
| 50 | 0.304 |
| 100 | 0.586 |
| 150 | 0.750 |
| 200 | 0.304 |
| 240 | 0.247 (min) |
| 299 | 0.603 (final) |
20-prompt A/B generation (base vs tuned), same prompts across phases.
| Metric | Base | Tuned (v3) | Delta |
|---|---|---|---|
| Cantonese particles (mean) | 1.8 | 0.8 | -1.0 |
| Particles (median) | 0 | 0 | - |
| Particles (max) | 12 | 5 | -7 |
| Gen latency (s, mean) | 1.29 | 2.17 | +0.88 |
Qualitative findings:
✅ Long-form generation no longer collapses to short replies (Phase 2's mode collapse fixed for some prompts)
✅ Real Cantonese dialogue in extended responses
✅ Punctuation and tone markers in extended form
⚠️ List-mode repetition collapse in some prompts (e.g. "港式炒魚片" repeated)
⚠️ Occasional Mandarin-character bleed for rare proper nouns (e.g. "alertController")
See ab_results_v3.md in the repo for the full per-prompt comparison.
# Setup
uv venv ~/mlx-env --python 3.11
source ~/mlx-env/bin/activate
uv pip install mlx mlx-lm transformers peft datasets
# Pipeline
cd ~/llm-finetune
python scripts/prep_dataset_v3.py # 1500 long samples
python scripts/dry_run_v3.py # safety check
python scripts/train_v3.py # 300 iters, ~40 min
python scripts/ab_eval_v3.py # A/B eval
See full scripts in the original training repo (will be linked if public).