Download app.py from BeaMorais/Seeds: direct link, hf CLI and curl.
- Browser
- Download file 11.7 kB
-
https://huggingface.co/spaces/BeaMorais/Seeds/resolve/main/app.py
- Command line
-
hf download hf://spaces/BeaMorais/Seeds/app.py
-
curl -L -o app.py https://huggingface.co/spaces/BeaMorais/Seeds/resolve/main/app.py
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() | |