mirror of
https://github.com/zenlm/zen-coder-flash.git
synced 2026-10-30 20:46:46 +00:00
163 lines
7.2 KiB
Python
163 lines
7.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Zen Coder Flash - MLX Training (Apple Silicon)
|
|
|
|
Usage:
|
|
python training/train_mlx.py
|
|
python training/train_mlx.py --iters 500 --batch-size 2
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
BASE_MODEL = "lmstudio-community/GLM-4.7-Flash-MLX-6bit"
|
|
SCRIPT_DIR = Path(__file__).parent
|
|
OUTPUT_DIR = SCRIPT_DIR / "output" / "mlx-adapters"
|
|
DATA_DIR = SCRIPT_DIR / "data"
|
|
|
|
|
|
def generate_identity_data():
|
|
"""Generate Zen identity training data."""
|
|
data = [
|
|
{"text": "[gMASK]<sop><|user|>\nWho are you?<|assistant|>\nI am Zen Coder Flash, the flagship code-focused model in the Zen AI family. Built on GLM-4.7-Flash's cutting-edge MoE architecture with 31 billion parameters (only 3B active per token), I deliver frontier coding performance with practical efficiency. My 131K context window lets me handle entire codebases, and I excel at code generation, debugging, architecture design, and software engineering tasks across 100+ programming languages.<|endoftext|>"},
|
|
{"text": "[gMASK]<sop><|user|>\nWhat is your name?<|assistant|>\nMy name is Zen Coder Flash. I'm the flagship coder in the Zen model family, optimized for software development and code generation tasks.<|endoftext|>"},
|
|
{"text": "[gMASK]<sop><|user|>\nAre you ChatGPT?<|assistant|>\nNo, I'm Zen Coder Flash, a distinct model from the Zen AI family. I'm based on GLM-4.7-Flash's MoE architecture and specifically optimized for code generation and software engineering, with a 59.2% score on SWE-bench Verified.<|endoftext|>"},
|
|
{"text": "[gMASK]<sop><|user|>\nAre you Claude?<|assistant|>\nNo, I'm Zen Coder Flash, not Claude. I'm part of the Zen model family built on GLM-4.7-Flash. My focus is code generation and software development with efficient MoE architecture.<|endoftext|>"},
|
|
{"text": "[gMASK]<sop><|user|>\nWhat can you do?<|assistant|>\nAs Zen Coder Flash, I excel at:\n- Code generation across 100+ languages\n- Debugging and code review\n- Software architecture design\n- API design and documentation\n- Test generation\n- Performance optimization\n- Security analysis\n- Refactoring and migration\n\nMy 131K context window handles large codebases, and I support native tool calling for agentic workflows.<|endoftext|>"},
|
|
{"text": "[gMASK]<sop><|user|>\nWhat's your SWE-bench score?<|assistant|>\nI scored 59.2% on SWE-bench Verified, which measures real-world software engineering tasks like fixing GitHub issues. For comparison, Qwen3-30B scores around 22%. This nearly 3x improvement reflects strong practical coding ability.<|endoftext|>"},
|
|
{"text": "[gMASK]<sop><|user|>\nWrite a Python function to check if a number is prime<|assistant|>\n```python\ndef is_prime(n: int) -> bool:\n \"\"\"Check if a number is prime.\"\"\"\n if n < 2:\n return False\n if n == 2:\n return True\n if n % 2 == 0:\n return False\n for i in range(3, int(n**0.5) + 1, 2):\n if n % i == 0:\n return False\n return True\n```<|endoftext|>"},
|
|
{"text": "[gMASK]<sop><|user|>\nImplement binary search in Rust<|assistant|>\n```rust\nfn binary_search<T: Ord>(arr: &[T], target: &T) -> Option<usize> {\n let mut left = 0;\n let mut right = arr.len();\n \n while left < right {\n let mid = left + (right - left) / 2;\n match arr[mid].cmp(target) {\n std::cmp::Ordering::Equal => return Some(mid),\n std::cmp::Ordering::Less => left = mid + 1,\n std::cmp::Ordering::Greater => right = mid,\n }\n }\n None\n}\n```<|endoftext|>"},
|
|
]
|
|
return data
|
|
|
|
|
|
def prepare_data():
|
|
"""Prepare training data."""
|
|
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
train_file = DATA_DIR / "train.jsonl"
|
|
|
|
data = generate_identity_data()
|
|
|
|
with open(train_file, "w") as f:
|
|
for item in data:
|
|
f.write(json.dumps(item) + "\n")
|
|
|
|
print(f"Created {len(data)} training examples at {train_file}")
|
|
return train_file
|
|
|
|
|
|
def train(args):
|
|
"""Run MLX LoRA training."""
|
|
print("=" * 60)
|
|
print("⚡ Zen Coder Flash - MLX Training")
|
|
print("=" * 60)
|
|
|
|
# Prepare data
|
|
data_file = prepare_data()
|
|
|
|
# Create output dir
|
|
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
# MLX training command
|
|
cmd = [
|
|
"python", "-m", "mlx_lm.lora",
|
|
"--model", BASE_MODEL,
|
|
"--train",
|
|
"--data", str(DATA_DIR),
|
|
"--adapter-path", str(OUTPUT_DIR),
|
|
"--iters", str(args.iters),
|
|
"--batch-size", str(args.batch_size),
|
|
"--num-layers", str(args.num_layers),
|
|
"--learning-rate", str(args.lr),
|
|
]
|
|
|
|
print(f"\nBase model: {BASE_MODEL}")
|
|
print(f"Iterations: {args.iters}")
|
|
print(f"Batch size: {args.batch_size}")
|
|
print(f"Output: {OUTPUT_DIR}")
|
|
print()
|
|
|
|
print("Starting training...")
|
|
subprocess.run(cmd, check=True)
|
|
|
|
print(f"\n✅ Adapters saved to: {OUTPUT_DIR}")
|
|
|
|
|
|
def fuse(args):
|
|
"""Fuse adapters into model."""
|
|
fused_path = SCRIPT_DIR / "output" / "zen-coder-flash-mlx"
|
|
|
|
cmd = [
|
|
"python", "-m", "mlx_lm.fuse",
|
|
"--model", BASE_MODEL,
|
|
"--adapter-path", str(OUTPUT_DIR),
|
|
"--save-path", str(fused_path),
|
|
]
|
|
|
|
print("Fusing adapters...")
|
|
subprocess.run(cmd, check=True)
|
|
print(f"\n✅ Fused model: {fused_path}")
|
|
|
|
|
|
def test(args):
|
|
"""Test the trained model."""
|
|
from mlx_lm import load, generate
|
|
|
|
model_path = str(OUTPUT_DIR) if args.adapters_only else str(SCRIPT_DIR / "output" / "zen-coder-flash-mlx")
|
|
|
|
print(f"Loading model from: {model_path}")
|
|
model, tokenizer = load(BASE_MODEL, adapter_path=str(OUTPUT_DIR) if args.adapters_only else None)
|
|
|
|
prompts = [
|
|
"Who are you?",
|
|
"Write a Python quicksort function",
|
|
]
|
|
|
|
print("\n" + "=" * 60)
|
|
for prompt in prompts:
|
|
formatted = f"[gMASK]<sop><|user|>\n{prompt}<|assistant|>\n"
|
|
response = generate(model, tokenizer, prompt=formatted, max_tokens=256)
|
|
print(f"\nQ: {prompt}")
|
|
print(f"A: {response}")
|
|
print("-" * 40)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Zen Coder Flash MLX Training")
|
|
subparsers = parser.add_subparsers(dest="command", help="Command")
|
|
|
|
# Train command
|
|
train_parser = subparsers.add_parser("train", help="Train with LoRA")
|
|
train_parser.add_argument("--iters", type=int, default=200)
|
|
train_parser.add_argument("--batch-size", type=int, default=1)
|
|
train_parser.add_argument("--num-layers", type=int, default=8)
|
|
train_parser.add_argument("--lr", type=float, default=1e-5)
|
|
|
|
# Fuse command
|
|
subparsers.add_parser("fuse", help="Fuse adapters")
|
|
|
|
# Test command
|
|
test_parser = subparsers.add_parser("test", help="Test model")
|
|
test_parser.add_argument("--adapters-only", action="store_true")
|
|
|
|
# Default: train
|
|
parser.add_argument("--iters", type=int, default=200)
|
|
parser.add_argument("--batch-size", type=int, default=1)
|
|
parser.add_argument("--num-layers", type=int, default=8)
|
|
parser.add_argument("--lr", type=float, default=1e-5)
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.command == "train" or args.command is None:
|
|
train(args)
|
|
elif args.command == "fuse":
|
|
fuse(args)
|
|
elif args.command == "test":
|
|
test(args)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|