cardserver / training /train_lora.py
GitHub Actions
🚀 Auto-deploy from GitHub
f6e3d73
#!/usr/bin/env python3
"""
Kostengünstiges LORA-Training für OpenHermes-2.5-Mistral-7B
Optimiert für lokale Ausführung mit effizienter Speichernutzung
"""
import torch
from transformers import (
AutoTokenizer, AutoModelForCausalLM,
TrainingArguments, Trainer, DataCollatorForLanguageModeling
)
from peft import LoraConfig, get_peft_model, TaskType
from datasets import Dataset
import json
from pathlib import Path
import logging
# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class LoRATrainer:
def __init__(self, base_model_id="teknium/OpenHermes-2.5-Mistral-7B"):
self.base_model_id = base_model_id
self.output_dir = Path("../models/lora-checkpoint")
self.output_dir.mkdir(parents=True, exist_ok=True)
def setup_model_and_tokenizer(self):
"""Modell und Tokenizer mit optimalen Einstellungen laden"""
logger.info(f"Lade Modell: {self.base_model_id}")
# Tokenizer
self.tokenizer = AutoTokenizer.from_pretrained(self.base_model_id)
if self.tokenizer.pad_token is None:
self.tokenizer.pad_token = self.tokenizer.eos_token
# Modell mit 4-bit Quantisierung für Speichereffizienz
self.model = AutoModelForCausalLM.from_pretrained(
self.base_model_id,
load_in_4bit=True,
torch_dtype=torch.float16,
device_map="auto",
trust_remote_code=True
)
# LoRA Konfiguration - kostengünstig optimiert
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=16, # Rank - niedrig für Effizienz
lora_alpha=32, # Skalierungsfaktor
lora_dropout=0.1,
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"], # Nur wichtige Module
bias="none"
)
# PEFT Modell erstellen
self.model = get_peft_model(self.model, lora_config)
self.model.print_trainable_parameters()
def prepare_dataset(self, data_path="training_data.json"):
"""Trainingsdaten vorbereiten"""
logger.info(f"Lade Trainingsdaten: {data_path}")
# Beispiel-Datenformat für Horoskop-Generierung
if not Path(data_path).exists():
self.create_sample_data(data_path)
with open(data_path, 'r', encoding='utf-8') as f:
data = json.load(f)
def tokenize_function(examples):
# Prompt-Template für Horoskop-Generierung
texts = []
for item in examples:
prompt = f"<|im_start|>system\nDu bist ein erfahrener Astrologe. Erstelle ein präzises und einfühlsames Horoskop.<|im_end|>\n<|im_start|>user\nErstelle ein Horoskop für {item['sign']} am {item['date']}.<|im_end|>\n<|im_start|>assistant\n{item['horoscope']}<|im_end|>"
texts.append(prompt)
tokenized = self.tokenizer(
texts,
truncation=True,
padding="max_length",
max_length=512,
return_tensors="pt"
)
tokenized["labels"] = tokenized["input_ids"].clone()
return tokenized
dataset = Dataset.from_list(data)
tokenized_dataset = dataset.map(tokenize_function, batched=False)
return tokenized_dataset
def create_sample_data(self, data_path):
"""Beispiel-Trainingsdaten erstellen"""
sample_data = [
{
"sign": "Widder",
"date": "heute",
"horoscope": "Die Energie des Mars verleiht Ihnen heute besondere Kraft. Nutzen Sie diese für wichtige Entscheidungen in der Liebe."
},
{
"sign": "Stier",
"date": "morgen",
"horoscope": "Venus bringt harmonische Schwingungen in Ihr Leben. Ein perfekter Tag für romantische Begegnungen."
},
# Weitere Beispiele...
]
with open(data_path, 'w', encoding='utf-8') as f:
json.dump(sample_data, f, ensure_ascii=False, indent=2)
logger.info(f"Beispiel-Trainingsdaten erstellt: {data_path}")
def train(self, dataset, num_epochs=3):
"""Training starten - kostengünstig optimiert"""
logger.info("Starte Training...")
training_args = TrainingArguments(
output_dir=str(self.output_dir),
num_train_epochs=num_epochs,
per_device_train_batch_size=1, # Kleine Batch-Size für wenig RAM
gradient_accumulation_steps=4, # Simuliert größere Batches
warmup_steps=100,
logging_steps=10,
save_steps=500,
evaluation_strategy="no", # Keine Evaluation für Effizienz
save_strategy="epoch",
load_best_model_at_end=False,
remove_unused_columns=False,
dataloader_pin_memory=False,
gradient_checkpointing=True, # Speicher sparen
optim="adamw_torch",
learning_rate=5e-5,
weight_decay=0.01,
lr_scheduler_type="cosine",
report_to=None, # Kein Wandb etc. für Kosten
)
data_collator = DataCollatorForLanguageModeling(
tokenizer=self.tokenizer,
mlm=False
)
trainer = Trainer(
model=self.model,
args=training_args,
train_dataset=dataset,
data_collator=data_collator,
)
# Training starten
trainer.train()
# Modell speichern
trainer.save_model()
self.tokenizer.save_pretrained(str(self.output_dir))
logger.info(f"Training abgeschlossen. Modell gespeichert in: {self.output_dir}")
def main():
"""Hauptfunktion für Training"""
trainer = LoRATrainer()
# 1. Modell und Tokenizer setup
trainer.setup_model_and_tokenizer()
# 2. Dataset vorbereiten
dataset = trainer.prepare_dataset()
# 3. Training starten
trainer.train(dataset, num_epochs=3)
print("✅ LORA-Training erfolgreich abgeschlossen!")
print(f"📁 Modell gespeichert in: {trainer.output_dir}")
print("🚀 Jetzt können Sie das trainierte Modell in Ihrem FastAPI-Server verwenden.")
if __name__ == "__main__":
main()