feat: rééquilibrage dataset LoRA — raisonnement DIM vs mémorisation
Passe de 95/3/2 (lookups/raisonnement/règles) à ~31/49/20. Dataset cible ~16K exemples denses (vs 66K de lookups avant). Modifiés : - 03_convert_cache.py : cache complet 1840 entrées (actuel + backup) - 04_build_dataset.py : subsampling agressif (CIM-10 1.5K, CCAM 1.5K, CoCoA 2K) + sélection intelligente priorisant le raisonnement - 12_generate_pipeline_examples.py : 3 templates (court + long + CPAM), cache actuel, cible ~2800 exemples Créés : - 13_generate_fascicule_reasoning.py : parsing 10 fascicules ATIH, génération Q&A raisonnement via Claude Opus 4.6 (~450 exemples) - 14_generate_negative_examples.py : 1000 exemples négatifs (symptômes/DP, redondances sémantiques, DAS non significatifs) - 15_generate_discrimination.py : 800 exercices de discrimination entre codes siblings CIM-10 via Claude Opus 4.6 - 16_parse_guide_metho.py : extraction Guide Méthodologique MCO 2026, Q&A directes + raisonnement via Claude Opus 4.6 (~500 exemples) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
92
scripts/export_checkpoint_gguf.py
Normal file
92
scripts/export_checkpoint_gguf.py
Normal file
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Export un checkpoint LoRA en GGUF pour Ollama.
|
||||
|
||||
Stratégie : charge le modèle de base via Unsloth (pour bénéficier de
|
||||
save_pretrained_gguf), puis applique le LoRA depuis le checkpoint
|
||||
via PeftModel.from_pretrained en copiant la méthode GGUF.
|
||||
|
||||
Usage: python scripts/export_checkpoint_gguf.py [--checkpoint models/pmsi-lora-checkpoints/checkpoint-7000]
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
BASE = Path(__file__).resolve().parent.parent
|
||||
OUTPUT = BASE / "models"
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--checkpoint", default=str(OUTPUT / "pmsi-lora-checkpoints" / "checkpoint-7000"))
|
||||
parser.add_argument("--model", default="unsloth/gemma-3-12b-it-bnb-4bit")
|
||||
parser.add_argument("--max-seq-length", type=int, default=512)
|
||||
parser.add_argument("--quant", default="q4_k_m")
|
||||
args = parser.parse_args()
|
||||
|
||||
from unsloth import FastLanguageModel
|
||||
from peft import PeftModel
|
||||
|
||||
checkpoint_dir = Path(args.checkpoint)
|
||||
gguf_dir = OUTPUT / "pmsi-gguf-v2"
|
||||
gguf_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Étape 1 : Charger base via Unsloth (installe save_pretrained_gguf)
|
||||
print(f"[1/3] Chargement du modèle de base via Unsloth...")
|
||||
model, tokenizer = FastLanguageModel.from_pretrained(
|
||||
model_name=args.model,
|
||||
max_seq_length=args.max_seq_length,
|
||||
dtype=None,
|
||||
load_in_4bit=True,
|
||||
)
|
||||
|
||||
# Sauver la méthode GGUF avant que PeftModel ne l'écrase
|
||||
save_gguf_fn = model.save_pretrained_gguf
|
||||
|
||||
# Étape 2 : Appliquer le LoRA checkpoint
|
||||
print(f"[2/3] Application LoRA depuis {checkpoint_dir.name}...")
|
||||
model = PeftModel.from_pretrained(model, str(checkpoint_dir))
|
||||
|
||||
# Réattacher la méthode GGUF d'Unsloth au modèle PeftModel
|
||||
model.save_pretrained_gguf = save_gguf_fn.__func__.__get__(model, type(model))
|
||||
|
||||
# Vérifier que les poids LoRA sont bien chargés
|
||||
lora_params = [n for n, p in model.named_parameters() if "lora" in n and p.requires_grad]
|
||||
print(f" Paramètres LoRA actifs : {len(lora_params)}")
|
||||
|
||||
# Étape 3 : Export GGUF
|
||||
print(f"[3/3] Export GGUF ({args.quant})...")
|
||||
model.save_pretrained_gguf(
|
||||
str(gguf_dir),
|
||||
tokenizer,
|
||||
quantization_method=args.quant,
|
||||
)
|
||||
|
||||
# Résultat
|
||||
gguf_files = sorted(gguf_dir.glob("*.gguf"), key=lambda f: f.stat().st_size)
|
||||
if not gguf_files:
|
||||
print("Aucun GGUF produit !")
|
||||
return
|
||||
|
||||
final_gguf = gguf_files[0]
|
||||
for g in gguf_files:
|
||||
size_gb = g.stat().st_size / 1024**3
|
||||
print(f" {g.name} ({size_gb:.1f} Go)")
|
||||
|
||||
# Modelfile
|
||||
modelfile_path = gguf_dir / "Modelfile"
|
||||
with open(modelfile_path, "w") as f:
|
||||
f.write(f"FROM {final_gguf.name}\n\n")
|
||||
f.write("PARAMETER temperature 0.3\n")
|
||||
f.write("PARAMETER top_p 0.9\n")
|
||||
f.write("PARAMETER num_ctx 8192\n")
|
||||
|
||||
print(f"\nTerminé !")
|
||||
print(f" GGUF : {final_gguf}")
|
||||
print(f"\nPour importer dans Ollama :")
|
||||
print(f" cd {gguf_dir}")
|
||||
print(f" ollama create pmsi-coder -f Modelfile")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user