akra35567 commited on
Commit
2def258
·
1 Parent(s): f04050b

Update modules/treinamento.py

Browse files
Files changed (1) hide show
  1. modules/treinamento.py +59 -83
modules/treinamento.py CHANGED
@@ -5,26 +5,21 @@ import json
5
  import os
6
  from loguru import logger
7
  from sentence_transformers import SentenceTransformer
8
- from transformers import TrainingArguments, Trainer
9
- from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
10
  from .database import Database
 
11
 
12
  # === CONFIGURAÇÕES GLOBAIS ===
13
  EMBEDDING_MODEL = "paraphrase-multilingual-MiniLM-L12-v2"
14
  embedding_model = SentenceTransformer(EMBEDDING_MODEL)
15
 
16
- HERMES_PATH = "/app/models/hermes-7b"
17
  FINETUNED_PATH = "/app/data/finetuned_hermes"
18
  os.makedirs(FINETUNED_PATH, exist_ok=True)
19
 
20
- # === IMPORTA SINGLETON DO local_llm.py (MESMO OBJETO!) ===
21
- from .local_llm import _get_hermes_singleton # ← REUSO 100%
22
-
23
-
24
  def gerar_embedding(text: str):
25
  return embedding_model.encode(text, convert_to_numpy=True)
26
 
27
-
28
  class Treinamento:
29
  def __init__(self, db: Database, interval_hours: int = 4):
30
  self.db = db
@@ -32,38 +27,25 @@ class Treinamento:
32
  self._thread = None
33
  self._running = False
34
 
35
- # REUSO DO MODELO JÁ CARREGADO PELO local_llm.py
36
- result = _get_hermes_singleton()
37
- if result:
38
- self.base_model, self.tokenizer = result # É (model, tokenizer)
39
- # Prepara LoRA (sem recarregar!)
40
- self.model = prepare_model_for_kbit_training(self.base_model)
41
- peft_config = LoraConfig(
42
- r=32,
43
- lora_alpha=64,
44
- target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
45
- lora_dropout=0.05,
46
- bias="none",
47
- task_type="CAUSAL_LM"
48
- )
49
- self.model = get_peft_model(self.model, peft_config)
50
- logger.info("Treinamento conectado ao Hermes 7B GLOBAL (sem reload!)")
51
  else:
52
- self.base_model = self.tokenizer = self.model = None
53
- logger.warning("Hermes não disponível para finetune")
54
 
55
  def registrar_interacao(self, usuario, mensagem, resposta, numero='', is_reply=False, mensagem_original=''):
56
  self.db.salvar_mensagem(usuario, mensagem, resposta, numero, is_reply, mensagem_original)
57
  self._aprender_roleplay(numero, mensagem, resposta)
58
 
59
  def _aprender_roleplay(self, numero: str, msg: str, resp: str):
60
- if not numero or not self.model:
61
  return
62
 
63
  dataset_path = f"{FINETUNED_PATH}/roleplay.jsonl"
64
  entry = {
65
  "messages": [
66
- {"role": "system", "content": "Tu és Akira, angolana sarcástica de Luanda. Fala com gírias: bué, fixe, kota, mwangolé, kandando."},
67
  {"role": "user", "content": msg},
68
  {"role": "assistant", "content": resp}
69
  ]
@@ -74,7 +56,7 @@ class Treinamento:
74
  logger.debug(f"Roleplay salvo: {msg[:30]}... → {resp[:30]}...")
75
 
76
  def train_once(self):
77
- if not self.model:
78
  logger.warning("Modelo não carregado. Pulando finetune.")
79
  return
80
 
@@ -83,65 +65,59 @@ class Treinamento:
83
  logger.info("Poucos dados. Esperando mais interações...")
84
  return
85
 
86
- logger.info("INICIANDO FINETUNE LORA (ROLEPLAY ANGOLANO)...")
87
 
88
  try:
89
- from datasets import load_dataset
90
-
91
- dataset = load_dataset("json", data_files=dataset_path, split="train")
92
-
93
- def tokenize_function(examples):
94
- # Junta mensagens em um texto só
95
- texts = []
96
- for msgs in examples["messages"]:
97
- text = ""
98
- for msg in msgs:
99
- if msg["role"] == "system":
100
- text += f"<|system|>{msg['content']}<|end|>"
101
- elif msg["role"] == "user":
102
- text += f"<|user|>{msg['content']}<|end|>"
103
- elif msg["role"] == "assistant":
104
- text += f"<|assistant|>{msg['content']}<|endoftext|>"
105
- texts.append(text)
106
- return self.tokenizer(texts, truncation=True, max_length=512, padding="max_length")
107
-
108
- tokenized = dataset.map(tokenize_function, batched=True, remove_columns=dataset.column_names)
109
-
110
- training_args = TrainingArguments(
111
- output_dir=FINETUNED_PATH,
112
- per_device_train_batch_size=1,
113
- gradient_accumulation_steps=4,
114
- num_train_epochs=1,
115
- learning_rate=2e-4,
116
- fp16=True,
117
- logging_steps=5,
118
- save_steps=50,
119
- save_total_limit=2,
120
- report_to=[],
121
- disable_tqdm=False,
122
- dataloader_num_workers=0,
123
- remove_unused_columns=False
124
- )
125
-
126
- trainer = Trainer(
127
- model=self.model,
128
- args=training_args,
129
- train_dataset=tokenized
130
  )
131
 
132
- trainer.train()
133
-
134
- # SALVA APENAS O LORA
135
- self.model.save_pretrained(FINETUNED_PATH)
136
- self.tokenizer.save_pretrained(FINETUNED_PATH)
137
- logger.info("FINETUNE CONCLUÍDO! LORA ANGOLANO SALVO!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
 
139
- # Limpa dataset
140
- open(dataset_path, 'w').close()
141
- logger.info("Dataset limpo. Pronto pro próximo ciclo.")
 
 
 
 
 
 
 
 
 
 
 
 
142
 
143
  except Exception as e:
144
- logger.error(f"Erro no finetune: {e}")
145
  import traceback
146
  logger.error(traceback.format_exc())
147
 
@@ -155,9 +131,9 @@ class Treinamento:
155
  time.sleep(interval)
156
 
157
  def start_periodic_training(self):
158
- if self._running or not self.model:
159
  return
160
  self._running = True
161
  self._thread = threading.Thread(target=self._run_loop, daemon=True)
162
  self._thread.start()
163
- logger.info(f"Treinamento periódico iniciado (a cada {self.interval_hours}h)")
 
5
  import os
6
  from loguru import logger
7
  from sentence_transformers import SentenceTransformer
8
+ from peft import LoraConfig, get_peft_model, set_peft_model_state_dict
9
+ from llama_cpp import Llama
10
  from .database import Database
11
+ from .local_llm import _get_llm # ← REUSO DO MESMO LLAMA OBJECT
12
 
13
  # === CONFIGURAÇÕES GLOBAIS ===
14
  EMBEDDING_MODEL = "paraphrase-multilingual-MiniLM-L12-v2"
15
  embedding_model = SentenceTransformer(EMBEDDING_MODEL)
16
 
 
17
  FINETUNED_PATH = "/app/data/finetuned_hermes"
18
  os.makedirs(FINETUNED_PATH, exist_ok=True)
19
 
 
 
 
 
20
  def gerar_embedding(text: str):
21
  return embedding_model.encode(text, convert_to_numpy=True)
22
 
 
23
  class Treinamento:
24
  def __init__(self, db: Database, interval_hours: int = 4):
25
  self.db = db
 
27
  self._thread = None
28
  self._running = False
29
 
30
+ # REUSO DO LLAMA JÁ CARREGADO
31
+ self.llm = _get_llm()
32
+ if self.llm:
33
+ logger.info("Treinamento conectado ao OpenHermes GGUF GLOBAL (sem reload!)")
 
 
 
 
 
 
 
 
 
 
 
 
34
  else:
35
+ logger.warning("LLM não disponível para finetune")
 
36
 
37
  def registrar_interacao(self, usuario, mensagem, resposta, numero='', is_reply=False, mensagem_original=''):
38
  self.db.salvar_mensagem(usuario, mensagem, resposta, numero, is_reply, mensagem_original)
39
  self._aprender_roleplay(numero, mensagem, resposta)
40
 
41
  def _aprender_roleplay(self, numero: str, msg: str, resp: str):
42
+ if not numero or not self.llm:
43
  return
44
 
45
  dataset_path = f"{FINETUNED_PATH}/roleplay.jsonl"
46
  entry = {
47
  "messages": [
48
+ {"role": "system", "content": "Tu és Akira, angolana sarcástica de Luanda. Fala com gírias: bué, fixe, kota, mwangolé, kandando, na boa."},
49
  {"role": "user", "content": msg},
50
  {"role": "assistant", "content": resp}
51
  ]
 
56
  logger.debug(f"Roleplay salvo: {msg[:30]}... → {resp[:30]}...")
57
 
58
  def train_once(self):
59
+ if not self.llm:
60
  logger.warning("Modelo não carregado. Pulando finetune.")
61
  return
62
 
 
65
  logger.info("Poucos dados. Esperando mais interações...")
66
  return
67
 
68
+ logger.info("INICIANDO FINETUNE LORA (ANGOLANO STYLE) COM llama.cpp...")
69
 
70
  try:
71
+ # === CRIA CONFIG LORA ===
72
+ lora_config = LoraConfig(
73
+ r=32,
74
+ lora_alpha=64,
75
+ target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
76
+ lora_dropout=0.05,
77
+ bias="none",
78
+ task_type="CAUSAL_LM"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  )
80
 
81
+ # === APLICA LORA NO LLAMA (cria arquivo temporário) ===
82
+ lora_path = f"{FINETUNED_PATH}/temp_lora"
83
+ os.makedirs(lora_path, exist_ok=True)
84
+
85
+ # Salva config
86
+ lora_config.save_pretrained(lora_path)
87
+
88
+ # === TREINA COM llama.cpp CLI (mais rápido e estável) ===
89
+ cmd = [
90
+ "python", "-m", "llama_cpp.convert",
91
+ "--outfile", f"{lora_path}/adapter_model.bin",
92
+ "--model", "/app/models/openhermes-2.5-mistral-7b.Q4_K_M.gguf",
93
+ "--lora-out", lora_path,
94
+ "--train", dataset_path,
95
+ "--epochs", "1",
96
+ "--lora-r", "32",
97
+ "--lora-alpha", "64",
98
+ "--batch", "4",
99
+ "--threads", "4",
100
+ "--ctx", "4096"
101
+ ]
102
 
103
+ import subprocess
104
+ result = subprocess.run(cmd, capture_output=True, text=True)
105
+ if result.returncode == 0:
106
+ logger.info("FINETUNE LORA CONCLUÍDO COM SUCESSO!")
107
+ # Move pro lugar certo
108
+ import shutil
109
+ if os.path.exists(f"{lora_path}/adapter_model.bin"):
110
+ shutil.move(f"{lora_path}/adapter_model.bin", f"{FINETUNED_PATH}/adapter_model.bin")
111
+ shutil.move(f"{lora_path}/adapter_config.json", f"{FINETUNED_PATH}/adapter_config.json")
112
+ logger.info("LORA ANGOLANO SALVO EM /app/data/finetuned_hermes")
113
+ # Limpa dataset
114
+ open(dataset_path, 'w').close()
115
+ logger.info("Dataset limpo. Pronto pro próximo ciclo.")
116
+ else:
117
+ logger.error(f"Erro no treino: {result.stderr}")
118
 
119
  except Exception as e:
120
+ logger.error(f"Erro crítico no finetune: {e}")
121
  import traceback
122
  logger.error(traceback.format_exc())
123
 
 
131
  time.sleep(interval)
132
 
133
  def start_periodic_training(self):
134
+ if self._running or not self.llm:
135
  return
136
  self._running = True
137
  self._thread = threading.Thread(target=self._run_loop, daemon=True)
138
  self._thread.start()
139
+ logger.info(f"Treinamento periódico iniciado (a cada {self.interval_hours}h)")