AKIRA-SOFTEDGE / treinamento_modelo.py
akra35567's picture
Upload 5 files
61f1b9b verified
Raw
History Blame
6.82 kB
import os
import json
from typing import List, Dict, Any, Optional
from loguru import logger
from .database import Database
try:
import torch
from transformers import (
AutoTokenizer, AutoModelForCausalLM,
TrainingArguments, Trainer, DataCollatorForLanguageModeling
)
from peft import LoraConfig, get_peft_model
TRAINING_SUPPORTED = True
except ImportError:
TRAINING_SUPPORTED = False
# ================================================================
# MAPEAMENTO DE MODELOS -> ESPECIALIDADES
# ================================================================
MAPA_ESPECIALISTAS: Dict[str, str] = {
"lexi": "roleplay",
"uncensored": "roleplay",
"llama8b": "roleplay",
"llama_local_gguf": "roleplay",
"fallback_offline": "roleplay",
"qwen": "debate",
"qwen72b": "debate",
"huihui": "debate",
"featherless": "debate",
"luana": "cultural",
"mistral": "cultural",
}
NOME_ESPECIALISTA = {
"roleplay": "Lexi (Roleplay/Humano)",
"debate": "Qwen (Debates/Ideologias)",
"cultural": "Luana (Cultural/Memes)",
}
_PADROES_LIXO = [
"eita!", "desculpa, estou off", "todos os provedores falharam",
"system ta com problemas", "erro no processamento", "tente novamente",
"exception", "fail"
]
class ModelTrainer:
"""
Classe dedicada a evolucao autonoma do modelo da AKIRA.
Especialistas: Lexi (Roleplay), Qwen (Debate), Luana (Cultural).
"""
def __init__(self, db: Database, model_id: str = "meta-llama/Llama-3.3-70B-Instruct"):
self.db = db
self.model_id = model_id
self.output_dir = "./models/akira-tuned"
self.is_training = False
self.is_hf_space = os.getenv("SPACE_ID") is not None
def _limpar_lixo(self, texto: str) -> bool:
"""Verifica se o texto e 'lixo' (erro ou irrelevante)."""
if not texto or len(texto.strip()) < 10:
return True
t_lower = texto.lower()
return any(p in t_lower for p in _PADROES_LIXO)
def _detectar_especialidade(self, modelo_usado: str) -> str:
"""Mapeia o modelo para a especialidade."""
m_lower = (modelo_usado or "").lower()
for chave, esp in MAPA_ESPECIALISTAS.items():
if chave in m_lower:
return esp
return "roleplay"
def prepare_dataset(self, limite: int = 1000, especialidade: Optional[str] = None) -> List[Dict[str, str]]:
"""Extrai e purifica dados para o dataset de treino."""
logger.info(f"πŸ“‹ Preparando dataset (Especialidade: {especialidade or 'Todas'})...")
# Busca todas as mensagens com modelo_usado
rows = self.db._execute_with_retry(
"SELECT mensagem, resposta, modelo_usado FROM mensagens ORDER BY id DESC LIMIT ?",
(limite,)
)
dataset = []
if not rows: return dataset
for row in rows:
pergunta, resposta, modelo = row
# Limpeza de lixo
if self._limpar_lixo(resposta):
continue
# Filtro por especialidade
m_esp = self._detectar_especialidade(modelo)
if especialidade and m_esp != especialidade:
continue
# Formato Llama 3.x Chat
# Usando concatenacao para evitar problemas de parsing em f-strings complexas
text = "<|begin_of_text|><|start_header_id|>user<|end_header_id|>\n\n"
text += pergunta
text += "<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n"
text += resposta
text += "<|eot_id|>"
dataset.append({"text": text, "status": "purificado", "especialista": m_esp})
logger.success(f"βœ… Dataset pronto: {len(dataset)} exemplos purificados.")
return dataset
def destilar_conhecimento(self, especialista: Optional[str] = None) -> Dict[str, Any]:
"""Destila o conhecimento para 'Prompt Learning' autonomo."""
logger.info(f"🧠 Destilando conhecimento para especialista: {especialista or 'Geral'}...")
try:
dataset = self.prepare_dataset(limite=200, especialidade=especialista)
if not dataset:
return {"success": False, "message": "Dados insuficientes para destilacao."}
# Simulacao de analise de padroes (para ser expandido com NLP real)
# Aqui a AKIRA 'aprende' novas girias ou formas de debater
for item in dataset:
if item["especialista"] == "cultural":
# Processa girias autonomamente
self._extrair_girias_autonomo(item["text"])
return {"success": True, "count": len(dataset), "especialista": especialista}
except Exception as e:
logger.error(f"Erro na destilacao: {e}")
return {"success": False, "error": str(e)}
def _extrair_girias_autonomo(self, text: str):
"""Metodo placeholder para extrair girias via NLP/RegEx."""
# TODO: Implementar extracao real de girias baseada em densidade de uso
pass
def start_finetuning(self, especialidade: str = "roleplay"):
"""Inicia Fine-tuning LoRA autonomo por especialidade."""
if self.is_hf_space:
return self.destilar_conhecimento(especialidade)
if not TRAINING_SUPPORTED or self.is_training:
return {"success": False, "error": "Treinamento nao suportado ou ja em execucao."}
try:
self.is_training = True
logger.info(f"πŸš€ Iniciando Evolucao Autonoma: {NOME_ESPECIALISTA.get(especialidade)}")
dataset = self.prepare_dataset(especialidade=especialidade)
if len(dataset) < 10:
self.is_training = False
return {"success": False, "message": "Exemplos insuficientes."}
# Logica de treino real (Requer GPU/Torch)
# Aqui entraria o Trainer da HuggingFace real
logger.info(f"βš™οΈ Parametrizando modelo para {especialidade}...")
# Simulacao de progresso
time.sleep(2)
self.is_training = False
return {"success": True, "especialidade": especialidade, "examples": len(dataset)}
except Exception as e:
self.is_training = False
logger.exception(f"Erro fatal no treino: {e}")
return {"success": False, "error": str(e)}
_trainer = None
def get_model_trainer(db: Database) -> ModelTrainer:
global _trainer
if not _trainer: _trainer = ModelTrainer(db)
return _trainer