File size: 8,026 Bytes
d855e28 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | #!/usr/bin/env python3
"""train.py — Treino de bug-detection para BiGRU_T_version (2 épocas).
Especificações do usuário atendidas:
- 2 épocas fixas (não mudar sem permissão)
- Sem dados inventados (apenas datasets do repo + HF públicos)
- Monitorar RAM, disco, loss, perplexidade
- Kill-switch: matar se loss não diminuir ou RAM explodir
- Estados temporários salvos durante treino e APAGADOS ao final
- Parâmetros do modelo aprendidos automaticamente (sem inserção manual)
- Ambiente otimizado para Xeon (AVX512, OpenMP, MKL)
- HF_TOKEN apagado ao final (se usado para datasets privados)
Uso:
export HF_TOKEN="hf_xxx" # opcional para datasets públicos
python scripts/train.py \\
--datasets CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1,Madras1/corpus-ptbr-v2 \\
--max-samples 30 \\
--epochs 2
"""
from __future__ import annotations
import argparse
import logging
import os
import sys
import time
from pathlib import Path
# Adiciona src/ ao path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
# Otimização Xeon (deve vir ANTES de importar torch)
os.environ.setdefault("OMP_NUM_THREADS", "2")
os.environ.setdefault("MKL_NUM_THREADS", "2")
os.environ.setdefault("TOKENIZERS_PARALLELISM", "false")
os.environ.setdefault("TORCH_NUM_THREADS", "2")
import torch
torch.set_num_threads(2)
# Tenta otimizar ambiente Xeon (do módulo reaproveitado)
try:
from bigru_t.utils.xeon_runtime import optimize_xeon_environment
optimize_xeon_environment()
except Exception as e:
logging.warning(f"Could not apply Xeon optimization: {e}")
from bigru_t import (
UnifiedModel, UnifiedModelConfig, create_unified_model,
BiGRU_T_Trainer, TrainerConfig,
)
from bigru_t.data.streaming_datasets import stream_dataset
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
datefmt="%H:%M:%S",
handlers=[logging.StreamHandler()],
)
logger = logging.getLogger(__name__)
def load_tokenizer(path: str):
"""Carrega tokenizer BBPE 16K."""
from tokenizers import Tokenizer
return Tokenizer.from_file(path)
def load_samples(
datasets: str,
max_samples_per_dataset: int,
hf_token: str | None,
) -> list:
"""Carrega amostras via streaming (reaproveita streaming_datasets_v13_9)."""
samples = []
datasets_list = [d.strip() for d in datasets.split(",") if d.strip()]
logger.info(f"Loading samples from {len(datasets_list)} datasets...")
for ds_name in datasets_list:
ds_start = time.time()
ds_count = 0
try:
for sample in stream_dataset(
ds_name,
max_samples=max_samples_per_dataset,
hf_token=hf_token,
):
samples.append(sample)
ds_count += 1
if ds_count >= max_samples_per_dataset:
break
if time.time() - ds_start > 300:
logger.warning(f" timeout em {ds_name} após {ds_count} amostras")
break
except Exception as e:
logger.error(f"Erro carregando {ds_name}: {e}")
continue
logger.info(f" {ds_name}: {ds_count} amostras em {time.time()-ds_start:.1f}s")
return samples
def main():
parser = argparse.ArgumentParser(description="BiGRU_T_version — Bug-detection training (2 epochs)")
parser.add_argument(
"--datasets",
type=str,
default="CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1,Madras1/corpus-ptbr-v2,dominguesm/restore-punctuation-ptbr-dataset",
help="Lista separada por vírgulas de datasets HF",
)
parser.add_argument("--max-samples", type=int, default=30, help="Amostras POR dataset (default 30)")
parser.add_argument("--epochs", type=int, default=2, help="Nº de épocas (default 2)")
parser.add_argument("--batch-size", type=int, default=1)
parser.add_argument("--grad-accum", type=int, default=4)
parser.add_argument("--lr", type=float, default=1e-3)
parser.add_argument("--max-seq-len", type=int, default=64)
parser.add_argument("--output-dir", type=str, default="/home/z/my-project/BiGRU_T_version/model_final")
parser.add_argument("--temp-dir", type=str, default="/home/z/my-project/BiGRU_T_version/_temp_checkpoints")
parser.add_argument(
"--tokenizer-path",
type=str,
default="/home/z/my-project/source/model_final/tokenizer/tokenizer.json",
)
parser.add_argument("--no-hypothesis", action="store_true", help="Desativar hipótese (Lema 3)")
parser.add_argument("--keep-temp", action="store_true", help="Manter checkpoints temporários")
parser.add_argument("--smoke-test", action="store_true", help="Smoke test: 5 samples, 1 epoch")
args = parser.parse_args()
if args.smoke_test:
logger.info("SMOKE TEST MODE — 5 samples/dataset, 1 epoch")
args.max_samples = 5
args.epochs = 1
args.grad_accum = 2
args.datasets = "CEIA-POSITIVO/ultrachat_br_clustred_balanced_v1"
# HF token (opcional para datasets públicos)
hf_token = os.environ.get("HF_TOKEN") or None
# Configuração do modelo
model_config = UnifiedModelConfig(
vocab_size=16384,
d_model=128,
max_seq_len=args.max_seq_len,
# input_dim é automaticamente = d_model via __post_init__
# Para bug-detection, reduzimos max_modules (64 é caro)
max_modules=8, # 8 módulos em vez de 64
bigru_hidden=32,
d_transformer=64,
nhead_tu=4,
d_ff_tu=128,
output_dim_u8cell=64,
cache_len=16,
d_cache=128,
nhead_orq=8,
d_ff_orq=256,
trainT_dim=128,
nhead_train=4,
d_ff_train=256,
num_layers_train=2,
hypT_dim=128,
nhead_hyp=4,
d_ff_hyp=256,
num_layers_hyp=2,
num_bits=8,
dropout=0.1,
)
# Cria modelo
logger.info("Criando UnifiedModel...")
model, _ = create_unified_model(model_config)
params = model.count_parameters()
logger.info(f" params: {params['total']:,} ({params['total_M']:.2f}M)")
# Carrega tokenizer
tokenizer = load_tokenizer(args.tokenizer_path)
# Carrega datasets
samples = load_samples(args.datasets, args.max_samples, hf_token)
n = len(samples)
if n == 0:
logger.error("Nenhuma amostra carregada — abortando")
sys.exit(1)
logger.info(f"Total: {n} amostras carregadas")
# Split 90/10 treino/val
import random
random.seed(42)
random.shuffle(samples)
split = max(1, int(0.9 * n))
train_samples = samples[:split]
val_samples = samples[split:] or samples[:1] # fallback: 1 amostra
logger.info(f" train: {len(train_samples)} | val: {len(val_samples)}")
# Configuração do trainer
trainer_config = TrainerConfig(
epochs=args.epochs,
datasets=args.datasets,
max_samples_per_dataset=args.max_samples,
max_seq_len=args.max_seq_len,
per_device_batch_size=args.batch_size,
grad_accum=args.grad_accum,
lr=args.lr,
use_hypothesis=not args.no_hypothesis,
output_dir=args.output_dir,
temp_dir=args.temp_dir,
keep_temp=args.keep_temp,
)
# Trainer
trainer = BiGRU_T_Trainer(
model=model,
tokenizer=tokenizer,
config=trainer_config,
train_samples=train_samples,
val_samples=val_samples,
)
# Treina
result = trainer.train()
# Print resultado
import json
print("\n=== Resultado Final ===")
print(json.dumps(result, indent=2, default=str))
# Apaga HF token do ambiente (especificação do usuário)
if "HF_TOKEN" in os.environ:
del os.environ["HF_TOKEN"]
logger.info("HF_TOKEN apagado do ambiente")
# Exit code: 0 se OK, 1 se morto pelo kill-switch
sys.exit(0 if not result.get("killed") else 1)
if __name__ == "__main__":
main()
|