cardserver / training /deploy_lora.py
GitHub Actions
🚀 Auto-deploy from GitHub
f6e3d73
#!/usr/bin/env python3
"""
Deployment-Script für trainierte LoRA-Modelle
Automatisiert den Upload zu Hugging Face Hub
"""
import os
import shutil
from pathlib import Path
import subprocess
import json
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class LoRADeployer:
def __init__(self, model_path="../models/lora-checkpoint"):
self.model_path = Path(model_path)
self.hf_username = None # Wird aus HF_USERNAME env var gelesen
def verify_model(self):
"""Prüft ob trainiertes LoRA-Modell vollständig ist"""
required_files = [
"adapter_config.json",
"adapter_model.bin", # oder adapter_model.safetensors
"README.md"
]
missing_files = []
for file in required_files:
if not (self.model_path / file).exists():
missing_files.append(file)
if missing_files:
logger.error(f"Fehlende Dateien: {missing_files}")
return False
logger.info("✅ LoRA-Modell vollständig")
return True
def create_model_card(self):
"""Erstellt eine Model Card für Hugging Face"""
model_card = f"""---
library_name: peft
base_model: teknium/OpenHermes-2.5-Mistral-7B
tags:
- generated_from_trainer
- horoscope
- astrology
- german
- lora
language:
- de
- en
license: apache-2.0
---
# LoRA Adapter für Horoskop-Generierung
Dieses LoRA-Adapter wurde für die Generierung von personalisierten Horoskopen trainiert.
## Basis-Modell
- **Model**: teknium/OpenHermes-2.5-Mistral-7B
- **LoRA Rank**: 16
- **Target Modules**: q_proj, v_proj, k_proj, o_proj
## Verwendung
```python
from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import PeftModel
base_model = "teknium/OpenHermes-2.5-Mistral-7B"
tokenizer = AutoTokenizer.from_pretrained(base_model)
model = AutoModelForCausalLM.from_pretrained(base_model, load_in_4bit=True)
model = PeftModel.from_pretrained(model, "IHR_USERNAME/horoskop-lora")
# Beispiel-Prompt
prompt = "<|im_start|>system\\nDu bist ein erfahrener Astrologe.<|im_end|>\\n<|im_start|>user\\nErstelle ein Horoskop für Widder heute.<|im_end|>\\n<|im_start|>assistant\\n"
```
## Training Details
- **Training Duration**: {self.get_training_info().get('duration', 'N/A')}
- **Dataset Size**: {self.get_training_info().get('dataset_size', 'N/A')}
- **Epochs**: {self.get_training_info().get('epochs', 'N/A')}
"""
readme_path = self.model_path / "README.md"
with open(readme_path, 'w', encoding='utf-8') as f:
f.write(model_card)
logger.info(f"Model Card erstellt: {readme_path}")
def get_training_info(self):
"""Liest Training-Informationen aus logs oder config"""
# Placeholder - könnte aus Training-Logs gelesen werden
return {
"duration": "2-4 Stunden",
"dataset_size": "500+ Horoskop-Beispiele",
"epochs": "3"
}
def upload_to_hf(self, repo_name="horoskop-lora"):
"""Upload zu Hugging Face Hub"""
# Hugging Face Username prüfen
hf_username = os.getenv("HF_USERNAME")
if not hf_username:
logger.error("HF_USERNAME environment variable nicht gesetzt")
logger.info("Setzen Sie: export HF_USERNAME=ihr_username")
return False
# Hugging Face CLI prüfen
try:
subprocess.run(["huggingface-cli", "--version"], check=True, capture_output=True)
except subprocess.CalledProcessError:
logger.error("Hugging Face CLI nicht installiert")
logger.info("Installieren Sie: pip install huggingface_hub")
return False
# Repository erstellen
repo_id = f"{hf_username}/{repo_name}"
logger.info(f"Erstelle Repository: {repo_id}")
try:
# Repository auf HF erstellen
cmd = [
"huggingface-cli", "repo", "create",
repo_id, "--type", "model", "--private"
]
subprocess.run(cmd, check=True)
logger.info(f"✅ Repository erstellt: {repo_id}")
except subprocess.CalledProcessError as e:
if "already exists" in str(e):
logger.info(f"Repository existiert bereits: {repo_id}")
else:
logger.error(f"Repository-Erstellung fehlgeschlagen: {e}")
return False
# Dateien hochladen
try:
cmd = [
"huggingface-cli", "upload", repo_id,
str(self.model_path), ".", "--recursive"
]
subprocess.run(cmd, check=True)
logger.info(f"✅ Upload erfolgreich: https://huggingface.co/{repo_id}")
return True
except subprocess.CalledProcessError as e:
logger.error(f"Upload fehlgeschlagen: {e}")
return False
def prepare_for_space(self):
"""Bereitet Modell für Hugging Face Space vor"""
space_model_path = Path("../models/lora-checkpoint-deployed")
space_model_path.mkdir(exist_ok=True)
# Kopiere nur notwendige Dateien
essential_files = [
"adapter_config.json",
"adapter_model.bin",
"adapter_model.safetensors"
]
for file in essential_files:
src = self.model_path / file
if src.exists():
dst = space_model_path / file
shutil.copy2(src, dst)
logger.info(f"Kopiert: {file}")
logger.info(f"✅ Space-ready Modell in: {space_model_path}")
return space_model_path
def main():
"""Hauptfunktion für Deployment"""
deployer = LoRADeployer()
print("🚀 LoRA-Modell Deployment")
print("========================")
# 1. Modell verifizieren
if not deployer.verify_model():
print("❌ Modell-Verifikation fehlgeschlagen")
return
# 2. Model Card erstellen
deployer.create_model_card()
# 3. User-Input für Deployment-Optionen
print("\n📤 Deployment-Optionen:")
print("1. Für Hugging Face Space vorbereiten")
print("2. Zu Hugging Face Hub hochladen")
print("3. Beides")
choice = input("Wählen Sie (1-3): ").strip()
if choice in ["1", "3"]:
space_path = deployer.prepare_for_space()
print(f"✅ Space-ready: {space_path}")
if choice in ["2", "3"]:
repo_name = input("Repository-Name (Standard: horoskop-lora): ").strip()
if not repo_name:
repo_name = "horoskop-lora"
if deployer.upload_to_hf(repo_name):
print("✅ Upload zu Hugging Face erfolgreich!")
else:
print("❌ Upload fehlgeschlagen")
print("\n🎯 Nächste Schritte:")
print("1. Aktualisieren Sie config.py mit dem neuen Modell-Pfad")
print("2. Testen Sie das Modell lokal")
print("3. Deployen Sie zu Hugging Face Space")
if __name__ == "__main__":
main()