Seeds / app.py
BeaMorais's picture
Update app.py
7a5b64f verified
Raw History Blame Contribute Delete
11.7 kB
import gradio as gr
import subprocess
import sys
# ============================================================
# EXECUÇÃO DOS SCRIPTS DO PROJETO
# ============================================================
def executar_script(script):
try:
processo = subprocess.Popen(
[sys.executable, script],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1,
)
saida = ""
for linha in processo.stdout:
saida += linha
yield saida
processo.wait()
if processo.returncode != 0:
yield (
saida
+ f"\n\n❌ Processo encerrado com código "
f"{processo.returncode}."
)
else:
yield saida
except Exception as e:
yield f"❌ ERRO INESPERADO:\n\n{e}"
def explorar_corpus():
yield from executar_script("src/01_explore_corpus.py")
def preparar_dataset():
yield from executar_script("src/02_prepare_dataset.py")
def treinar_modelo():
yield from executar_script("src/03_train.py")
def treinar_nllb():
yield from executar_script("src/03_train_nllb.py")
def avaliar_modelo():
yield from executar_script("src/04_evaluate.py")
# ============================================================
# DIAGNÓSTICO DO NLLB
# ============================================================
def diagnosticar_nllb():
"""Verifica a configuração e a tokenização do NLLB."""
yield (
"🔬 Iniciando diagnóstico do NLLB...\n\n"
"Carregando configuração e tokenizer. "
"Isso pode levar alguns minutos na primeira execução."
)
try:
from transformers import AutoConfig, AutoTokenizer
modelo = "facebook/nllb-200-distilled-600M"
idioma_origem = "eng_Latn"
idioma_destino = "mbc_Latn"
config = AutoConfig.from_pretrained(modelo)
tokenizer = AutoTokenizer.from_pretrained(
modelo,
src_lang=idioma_origem,
)
linhas = [
"✅ Configuração e tokenizer carregados!",
"",
"=== 1. ARQUITETURA ===",
f"Modelo: {modelo}",
f"Arquitetura: {config.architectures}",
f"Vocabulário declarado: {config.vocab_size:,}",
f"Camadas encoder: {getattr(config, 'encoder_layers', 'n/d')}",
f"Camadas decoder: {getattr(config, 'decoder_layers', 'n/d')}",
f"Dimensão do modelo: {getattr(config, 'd_model', 'n/d')}",
"",
"=== 2. IDIOMA MACUXI ===",
]
mapa_idiomas = getattr(tokenizer, "lang_code_to_id", {})
idioma_registrado = idioma_destino in mapa_idiomas
linhas.append(
f"Código {idioma_destino} registrado: {idioma_registrado}"
)
if idioma_registrado:
linhas.append(
"O tokenizer já registra esse código de idioma."
)
else:
linhas.extend([
"Macuxi não está registrado como idioma nativo do NLLB.",
"Será necessário investigar a adaptação do modelo.",
"Adicionar apenas um token não ensina o idioma ao modelo.",
])
exemplos = [
(
"Always rejoice.",
"Taatausinpai ako'mantî.",
),
(
"Brothers, pray for us.",
"Uyonpayamî', anna pona nîrî epîrematî.",
),
]
linhas.extend(["", "=== 3. TOKENIZAÇÃO DOS EXEMPLOS ==="])
for numero, (ingles, macuxi) in enumerate(exemplos, start=1):
tokens_en = tokenizer(
ingles,
add_special_tokens=True,
)["input_ids"]
tokens_mb = tokenizer(
macuxi,
add_special_tokens=False,
)["input_ids"]
linhas.extend([
"",
f"Exemplo {numero}",
f"Inglês: {ingles}",
f"Macuxi: {macuxi}",
f"Quantidade de tokens em inglês: {len(tokens_en)}",
f"Quantidade de tokens em macuxi: {len(tokens_mb)}",
"Tokens macuxi: "
+ str(tokenizer.convert_ids_to_tokens(tokens_mb[:30])),
])
linhas.extend([
"",
"=== 4. CONCLUSÃO PRELIMINAR ===",
"Este diagnóstico verifica a configuração e a tokenização.",
"Ele NÃO comprova que o NLLB consegue traduzir para macuxi.",
"Nenhum treinamento foi executado.",
"Os pesos completos do modelo não foram solicitados por este código.",
])
yield "\n".join(linhas)
except Exception as e:
yield (
"❌ ERRO DURANTE O DIAGNÓSTICO\n\n"
f"Tipo: {type(e).__name__}\n"
f"Detalhes: {e}\n\n"
"Verifique as dependências e os logs do Space."
)
# ============================================================
# TESTE DE COMPATIBILIDADE DO NLLB
# Esta função precisa estar definida ANTES da interface Gradio.
# ============================================================
def testar_compatibilidade_nllb():
import gc
modelo_nome = "facebook/nllb-200-distilled-600M"
try:
import torch
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
yield (
"🔬 TESTE DE COMPATIBILIDADE NLLB\n\n"
"Etapa 1/4: carregando tokenizer..."
)
tokenizer = AutoTokenizer.from_pretrained(
modelo_nome,
src_lang="eng_Latn",
)
yield (
"Etapa 2/4: baixando e carregando os pesos completos.\n"
"O modelo tem aproximadamente 600 milhões de parâmetros.\n"
"Esta etapa pode demorar e consumir vários GB de memória."
)
modelo = AutoModelForSeq2SeqLM.from_pretrained(
modelo_nome,
torch_dtype=torch.float32,
)
dispositivo = torch.device("cpu")
modelo.to(dispositivo)
yield (
"Pesos carregados com sucesso!\n\n"
"Etapa 3/4: adicionando o token de macuxi..."
)
token_macuxi = "mbc_Latn"
quantidade_adicionada = tokenizer.add_special_tokens({
"additional_special_tokens": [token_macuxi]
})
if quantidade_adicionada:
modelo.resize_token_embeddings(len(tokenizer))
id_macuxi = tokenizer.convert_tokens_to_ids(token_macuxi)
if id_macuxi == tokenizer.unk_token_id:
raise RuntimeError(
"O tokenizer não conseguiu registrar o token de macuxi."
)
modelo.config.vocab_size = len(tokenizer)
yield (
"Token de macuxi registrado.\n\n"
"Etapa 4/4: executando uma passagem de treinamento "
"com um único exemplo..."
)
ingles = "Always rejoice."
macuxi = "Taatausinpai ako'mantî."
entradas = tokenizer(
ingles,
return_tensors="pt",
truncation=True,
max_length=48,
)
entradas = {
chave: valor.to(dispositivo)
for chave, valor in entradas.items()
}
tokens_destino = tokenizer(
macuxi,
add_special_tokens=False,
truncation=True,
max_length=48,
)["input_ids"]
# Convenção de destino: token do idioma + texto + EOS.
rotulos = torch.tensor(
[[id_macuxi] + tokens_destino + [tokenizer.eos_token_id]],
dtype=torch.long,
device=dispositivo,
)
modelo.train()
modelo.zero_grad(set_to_none=True)
saida = modelo(**entradas, labels=rotulos)
perda = saida.loss
if not torch.isfinite(perda).item():
raise RuntimeError(
f"A loss não é finita: {perda.item()}"
)
perda.backward()
gradientes_ok = any(
parametro.grad is not None
and torch.isfinite(parametro.grad).all().item()
for parametro in modelo.parameters()
if parametro.requires_grad
)
modelo.zero_grad(set_to_none=True)
if not gradientes_ok:
raise RuntimeError(
"O modelo não produziu gradientes válidos."
)
yield (
"✅ TESTE CONCLUÍDO COM SUCESSO\n\n"
f"Modelo: {modelo_nome}\n"
f"Dispositivo: {dispositivo}\n"
f"Token de macuxi: {token_macuxi}\n"
f"ID do token: {id_macuxi}\n"
f"Loss do exemplo: {perda.item():.4f}\n"
f"Gradientes válidos: {gradientes_ok}\n\n"
"Interpretação:\n"
"- Os pesos foram carregados.\n"
"- O vocabulário foi ampliado quando necessário.\n"
"- O modelo executou forward e backward.\n"
"- Nenhuma atualização de pesos foi realizada.\n\n"
"ATENÇÃO: isso não comprova capacidade de tradução. "
"O token novo ainda não aprendeu a representar macuxi, "
"e será necessário planejar o treinamento experimental."
)
del saida, modelo, tokenizer
gc.collect()
except Exception as erro:
gc.collect()
yield (
"❌ FALHA NO TESTE DE COMPATIBILIDADE\n\n"
f"Tipo: {type(erro).__name__}\n"
f"Detalhes: {erro}\n\n"
"Nenhum modelo treinado foi salvo. "
"Envie esta mensagem para investigarmos."
)
# ============================================================
# INTERFACE GRADIO
# ============================================================
with gr.Blocks(title="SEEDS Lab") as demo:
gr.Markdown("""
# 🌱 SEEDS Lab
## Pipeline de tradução English → Macushi
Este espaço executa as etapas do projeto SEEDS.
""")
gr.Markdown("### 🔬 Etapas do projeto")
with gr.Row():
botao_explorar = gr.Button("🔎 Explorar corpus")
botao_preparar = gr.Button("📦 Preparar dataset")
with gr.Row():
botao_treinar = gr.Button(
"🧠 Treinar modelo",
variant="primary",
)
botao_avaliar = gr.Button("📊 Avaliar modelo")
with gr.Row():
botao_diagnostico = gr.Button("🔬 Diagnosticar NLLB")
with gr.Row():
botao_teste_nllb = gr.Button(
"🧪 Testar compatibilidade NLLB"
)
with gr.Row():
botao_treinar_nllb = gr.Button(
"🧠 Treinar NLLB + LoRA",
variant="primary",
)
resultado = gr.Textbox(
label="Resultado",
lines=30,
max_lines=50,
)
botao_explorar.click(
fn=explorar_corpus,
inputs=[],
outputs=resultado,
)
botao_preparar.click(
fn=preparar_dataset,
inputs=[],
outputs=resultado,
)
botao_treinar.click(
fn=treinar_modelo,
inputs=[],
outputs=resultado,
)
botao_avaliar.click(
fn=avaliar_modelo,
inputs=[],
outputs=resultado,
)
botao_diagnostico.click(
fn=diagnosticar_nllb,
inputs=[],
outputs=resultado,
)
botao_teste_nllb.click(
fn=testar_compatibilidade_nllb,
inputs=[],
outputs=resultado,
)
botao_treinar_nllb.click(
fn=treinar_nllb,
inputs=[],
outputs=resultado,
)
demo.launch()