|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| """GGUF Conversion for GRPO Model - Q8_0 Quantization"""
|
|
|
| import os
|
| import torch
|
| from transformers import AutoModelForCausalLM, AutoTokenizer
|
| from peft import PeftModel
|
| from huggingface_hub import HfApi
|
| import subprocess
|
|
|
| print("=" * 60)
|
| print("GGUF Conversion - GRPO Model Q8_0")
|
| print("=" * 60)
|
|
|
|
|
| BASE_MODEL = "Qwen/Qwen3-0.6B"
|
| SFT_ADAPTER = "chaddy81/qwen3-0.6b-multicode-sft"
|
| GRPO_ADAPTER = "chaddy81/qwen3-0.6b-multicode-grpo"
|
| OUTPUT_REPO = "chaddy81/qwen3-0.6b-multicode-grpo-gguf"
|
|
|
| print(f"\n Configuration:")
|
| print(f" Base model: {BASE_MODEL}")
|
| print(f" SFT adapter: {SFT_ADAPTER}")
|
| print(f" GRPO adapter: {GRPO_ADAPTER}")
|
| print(f" Output repo: {OUTPUT_REPO}")
|
| print(f" Quantization: Q8_0 (8-bit)")
|
|
|
|
|
| print("\n Step 1: Loading base model...")
|
| base_model = AutoModelForCausalLM.from_pretrained(
|
| BASE_MODEL, torch_dtype=torch.float16, device_map="auto", trust_remote_code=True,
|
| )
|
| print(" Base model loaded")
|
|
|
|
|
| print("\n Step 2: Loading and merging SFT adapter...")
|
| model = PeftModel.from_pretrained(base_model, SFT_ADAPTER)
|
| model = model.merge_and_unload()
|
| print(" SFT adapter merged")
|
|
|
|
|
| print("\n Step 3: Loading and merging GRPO adapter...")
|
| model = PeftModel.from_pretrained(model, GRPO_ADAPTER)
|
| merged_model = model.merge_and_unload()
|
| print(" GRPO adapter merged")
|
|
|
|
|
| tokenizer = AutoTokenizer.from_pretrained(GRPO_ADAPTER, trust_remote_code=True)
|
| print(" Tokenizer loaded")
|
|
|
|
|
| print("\n Step 4: Saving fully merged model...")
|
| merged_dir = "/tmp/merged_grpo_model"
|
| merged_model.save_pretrained(merged_dir, safe_serialization=True)
|
| tokenizer.save_pretrained(merged_dir)
|
| print(f" Merged model saved to {merged_dir}")
|
|
|
|
|
| print("\n Step 5: Setting up llama.cpp...")
|
| subprocess.run(["apt-get", "update", "-qq"], check=True, capture_output=True)
|
| subprocess.run(["apt-get", "install", "-y", "-qq", "build-essential", "cmake"], check=True, capture_output=True)
|
| print(" Build tools installed")
|
|
|
| subprocess.run(["git", "clone", "--depth", "1", "https://github.com/ggerganov/llama.cpp.git", "/tmp/llama.cpp"], check=True, capture_output=True)
|
| print(" llama.cpp cloned")
|
|
|
| subprocess.run(["pip", "install", "-r", "/tmp/llama.cpp/requirements.txt"], check=True, capture_output=True)
|
| subprocess.run(["pip", "install", "sentencepiece", "protobuf"], check=True, capture_output=True)
|
| print(" Dependencies installed")
|
|
|
|
|
| print("\n Step 6: Converting to GGUF format...")
|
| gguf_output_dir = "/tmp/gguf_output"
|
| os.makedirs(gguf_output_dir, exist_ok=True)
|
|
|
| model_name = "qwen3-0.6b-multicode-grpo"
|
| gguf_file = f"{gguf_output_dir}/{model_name}-f16.gguf"
|
|
|
| result = subprocess.run(
|
| ["python", "/tmp/llama.cpp/convert_hf_to_gguf.py", merged_dir, "--outfile", gguf_file, "--outtype", "f16"],
|
| check=True, capture_output=True, text=True
|
| )
|
| print(f" FP16 GGUF created")
|
|
|
|
|
| print("\n Step 7: Creating Q8_0 quantization...")
|
| os.makedirs("/tmp/llama.cpp/build", exist_ok=True)
|
| subprocess.run(
|
| ["cmake", "-B", "/tmp/llama.cpp/build", "-S", "/tmp/llama.cpp", "-DGGML_CUDA=OFF"],
|
| check=True, capture_output=True, text=True
|
| )
|
| subprocess.run(
|
| ["cmake", "--build", "/tmp/llama.cpp/build", "--target", "llama-quantize", "-j", "4"],
|
| check=True, capture_output=True, text=True
|
| )
|
| print(" Quantize tool built")
|
|
|
| quant_file = f"{gguf_output_dir}/{model_name}-q8_0.gguf"
|
| result = subprocess.run(
|
| ["/tmp/llama.cpp/build/bin/llama-quantize", gguf_file, quant_file, "Q8_0"],
|
| check=True, capture_output=True, text=True
|
| )
|
| size_mb = os.path.getsize(quant_file) / (1024 * 1024)
|
| print(f" Q8_0: {size_mb:.1f} MB")
|
|
|
|
|
| print("\n Step 8: Uploading to Hub...")
|
| from huggingface_hub import login, HfFolder
|
|
|
|
|
| print(" Available HF env vars:")
|
| for key, val in os.environ.items():
|
| if 'HF' in key or 'HUGGING' in key or 'TOKEN' in key:
|
| print(f" {key}: {'[SET]' if val else '[EMPTY]'}")
|
|
|
|
|
| hf_token = os.environ.get("HF_TOKEN") or os.environ.get("HUGGING_FACE_HUB_TOKEN") or HfFolder.get_token()
|
|
|
| if hf_token:
|
| login(token=hf_token, add_to_git_credential=False)
|
| print(" Logged in successfully")
|
| else:
|
| print(" ERROR: No token found!")
|
| print(" Make sure HF_TOKEN secret is configured at https://huggingface.co/settings/secrets")
|
| raise RuntimeError("No HF token available for upload")
|
|
|
| api = HfApi()
|
| api.create_repo(repo_id=OUTPUT_REPO, repo_type="model", exist_ok=True)
|
| print(" Repository ready")
|
|
|
| api.upload_file(path_or_fileobj=quant_file, path_in_repo=f"{model_name}-q8_0.gguf", repo_id=OUTPUT_REPO)
|
| print(" Q8_0 uploaded")
|
|
|
| readme = f"""---
|
| base_model: {BASE_MODEL}
|
| tags:
|
| - gguf
|
| - llama.cpp
|
| - quantized
|
| - trl
|
| - grpo
|
| - qwen3
|
| - code
|
| ---
|
|
|
| # {model_name} GGUF
|
|
|
| GGUF conversion of [{GRPO_ADAPTER}](https://huggingface.co/{GRPO_ADAPTER}).
|
|
|
| ## Model Details
|
|
|
| - **Base Model:** {BASE_MODEL}
|
| - **SFT Model:** {SFT_ADAPTER}
|
| - **GRPO Model:** {GRPO_ADAPTER}
|
| - **Training:** SFT on code datasets + GRPO with code execution rewards
|
| - **Quantization:** Q8_0 (8-bit, high quality)
|
|
|
| ## Training Pipeline
|
|
|
| 1. **SFT:** Fine-tuned on Codeforces, Golang, Vue/Nuxt, React datasets
|
| 2. **GRPO:** Reinforcement learning with code execution rewards (pass/fail on test cases)
|
|
|
| ## Usage
|
|
|
| ### With Ollama
|
|
|
| ```bash
|
| huggingface-cli download {OUTPUT_REPO} {model_name}-q8_0.gguf
|
| echo "FROM ./{model_name}-q8_0.gguf" > Modelfile
|
| ollama create qwen3-grpo -f Modelfile
|
| ollama run qwen3-grpo
|
| ```
|
|
|
| ### With llama.cpp
|
|
|
| ```bash
|
| huggingface-cli download {OUTPUT_REPO} {model_name}-q8_0.gguf
|
| ./llama-cli -m {model_name}-q8_0.gguf -p "Write a Python function to find prime numbers"
|
| ```
|
|
|
| ### With LM Studio
|
|
|
| Download the `.gguf` file and import into LM Studio.
|
| """
|
|
|
| api.upload_file(path_or_fileobj=readme.encode(), path_in_repo="README.md", repo_id=OUTPUT_REPO)
|
| print(" README uploaded")
|
|
|
| print("\n" + "=" * 60)
|
| print(" GGUF Conversion Complete!")
|
| print(f" https://huggingface.co/{OUTPUT_REPO}")
|
| print(f" huggingface-cli download {OUTPUT_REPO} {model_name}-q8_0.gguf")
|
| print("=" * 60)
|
|
|