turn-taking-study / RESEARCH_LOG.md
marcosremar2's picture
Upload folder using huggingface_hub
3c1eb61 verified
# Smart Turn Portuguese Fine-Tuning — Research Log
## Objetivo
Fine-tuning do modelo Pipecat Smart Turn (detecção de fim de turno em conversas) para português brasileiro, visando melhorar a acurácia de ~68% (modelo original inglês aplicado a PT) para 90%+.
## Background
### O que é Smart Turn
- Modelo do framework [Pipecat](https://github.com/pipecat-ai/smart-turn) para detectar se um falante terminou de falar
- Arquitetura: Whisper encoder + attention pooling + classificador binário (complete/incomplete)
- Janela de 8 segundos de áudio, saída binária: "turno completo" vs "turno incompleto"
- Modelo original treinado em inglês (v3.1), 39M parâmetros (Whisper Tiny)
### Por que fine-tuning em português
- O modelo original em inglês tem ~68.6% de acurácia em português
- Prosódia, entonação e padrões de turn-taking são diferentes entre idiomas
- Aplicação: tradução em tempo real de reuniões (BabelCast)
---
## Fase 1: Benchmark do modelo original (pré fine-tuning)
### Datasets de avaliação
- **NURC-SP Corpus Minimo** (nilc-nlp): diálogos reais em PT-BR espontâneo dos anos 1970-1990
- Scripts: `setup_nurc_dataset.py`, `benchmark_pipecat.py`
### Resultado baseline
- Acurácia do Smart Turn v3.1 em português: **~68.6%**
- Problema principal: modelo não entende padrões prosódicos do português
---
## Fase 2: Fine-tuning v2 — Heurística de corte (2026-03-14)
### Abordagem
- Baixar datasets de ASR em português do HuggingFace
- Criar labels heurísticas: "complete" = final da frase, "incomplete" = corte aleatório a 30-75%
- Treinar com speaker-based split para evitar data leakage
### Datasets utilizados
| Dataset | Tipo | Horas | Samples |
|---------|------|-------|---------|
| CORAA v1.1 | Conversacional BR-PT | 291h | 7,000 |
| MLS Portuguese | Audiobook (leitura) | 168h | 7,000 |
| CORAA-MUPE-ASR | Entrevistas | 365h | 7,000 |
| **Total** | | | **21,000** |
### Configuração de treino
- **Modelo**: Whisper Tiny encoder (39M params)
- **GPU**: RTX 3090 24GB (Vast.ai, $0.069/hr)
- **Batch size**: 32
- **Learning rate**: 2e-5 (encoder: 2e-6, head: 2e-5)
- **Augmentation**: volume scaling, Gaussian noise
- **Split**: 13,032 train (4,100 speakers) / 698 val (512 speakers) / 7,270 test (512 speakers)
- **Early stopping**: patience=5 no val_f1
### Infraestrutura (problemas e soluções)
- **6+ instâncias Vast.ai morreram** durante o treino (spot instances instáveis)
- **3 pods RunPod falharam** (PyTorch images too large for container disk)
- **Solução**: on-demand Vast.ai instance, RTX 3090, reliability=1.00
- **Mac local**: treinamento funciona mas deixa a máquina muito lenta (MPS)
- **Dependências críticas**: PyTorch >= 2.4, `datasets<4` (para evitar torchcodec), librosa, typing_extensions >= 4.12
### Resultados v2
#### Progresso por época
| Epoch | Train Loss | Train Acc | Val Acc | Val F1 | Val Prec | Val Rec |
|-------|-----------|-----------|---------|--------|----------|---------|
| 1 | 0.6032 | 0.668 | 0.669 | 0.721 | 0.600 | 0.903 |
| 2 | 0.5019 | 0.748 | 0.716 | 0.751 | 0.643 | 0.903 |
| 3 | 0.4521 | 0.782 | 0.716 | 0.751 | 0.643 | 0.903 |
| 4 | 0.4161 | 0.806 | 0.749 | 0.748 | 0.714 | 0.785 |
| 5 | 0.3962 | 0.817 | 0.742 | 0.717 | 0.748 | 0.689 |
| **6** | **0.3806** | **0.831** | **0.754** | **0.760** | **0.707** | **0.822** |
| 7 | 0.3703 | 0.832 | 0.742 | 0.748 | 0.697 | 0.807 |
| 8 | 0.3566 | 0.845 | 0.739 | 0.709 | 0.752 | 0.671 |
| 9 | 0.3449 | 0.846 | 0.748 | 0.745 | 0.716 | 0.776 |
| 10 | 0.3390 | 0.853 | 0.748 | 0.758 | 0.695 | 0.834 |
| 11 | 0.3237 | 0.865 | 0.754 | 0.756 | 0.713 | 0.804 |
Early stopping na época 11 (sem melhora por 5 épocas).
#### Melhor modelo (época 6)
- **Val Accuracy**: 75.4%
- **Val F1**: 0.760
- **Val Precision**: 70.7%
- **Val Recall**: 82.2%
#### Teste (speakers totalmente novos)
- **Test Accuracy**: 64.4%
- **Test F1**: 0.600
- **Test Precision**: 68.0%
- **Test Recall**: 53.7%
- TP=1945, FP=916, FN=1674, TN=2735
### Análise dos problemas da v2
1. **Labels heurísticas (problema principal)**: Cortar frases aleatoriamente em 30-75% não simula turn-taking real. O modelo aprendeu "tem silêncio no final?" em vez de "a pessoa terminou de falar?"
2. **MLS é audiobook**: 1/3 dos dados são leitura de audiobook — prosódia completamente diferente de conversação real
3. **MUPE speaker_id quebrado**: Usava `speaker_type` ("interviewer"/"interviewee") como speaker_id, comprometendo o speaker split
4. **Modelo pequeno**: Whisper Tiny (39M params) tem capacidade limitada para capturar padrões prosódicos complexos
5. **Gap val/test grande (75.4% vs 64.4%)**: Indica que o modelo não generaliza bem para speakers novos
### Arquivos gerados
- `checkpoints/smart_turn_pt_v2/best_model.pt` — 31MB PyTorch checkpoint
- `checkpoints/smart_turn_pt_v2/smart_turn_pt.onnx` + `.onnx.data` — 31MB ONNX
- `checkpoints/smart_turn_pt_v2/finetune.log` — log completo
### Commits
- `4517458` — feat: Pipecat Smart Turn Portuguese evaluation, fine-tuning pipeline
- `307b0fd` — feat: GPU fine-tuning script with HuggingFace Portuguese datasets
- `62e1816` — fix: total_mem → total_memory for PyTorch 2.10 compat
- `0039c15` — fix: reduce samples to 5k/dataset and workers to prevent OOM
- `51025dd` — fix: MPS support, skip Common Voice, increase samples to 7k/dataset
---
## Fase 3: Fine-tuning v3 — Labels por pontuação + Whisper Base (em andamento)
### Melhorias implementadas
1. **Labels baseadas em pontuação do texto**
- Frase termina com `.` `!` `?` `…` → complete (1.0)
- Frase termina com `,` `;` `:` `-` → incomplete (0.0)
- Texto sem pontuação com ≤2 palavras → descartado (ambíguo)
- Texto sem pontuação com 3+ palavras → incomplete (transcritor teria colocado ponto se fosse completa)
2. **Removido MLS audiobook** — só dados conversacionais (CORAA + MUPE)
3. **Whisper Base** (74M params) em vez de Whisper Tiny (39M)
- 2x mais parâmetros no encoder
- hidden_size: 512 (vs 384 no Tiny)
- Melhor capacidade para capturar prosódia
4. **Speaker ID do MUPE corrigido** — usa hash do audio_path ou agrupamento por index
5. **Mais dados**: 25k samples por dataset (vs 7k na v2) = ~50k total
6. **Augmentation melhorada**:
- Speed perturbation (0.9x–1.1x)
- Volume scaling (0.6x–1.4x)
- Gaussian noise mais agressivo
- Time shift aleatório (±0.3s)
7. **LR schedule com warmup**: 2 épocas de warmup + cosine decay
8. **Classifier head maior**: 512→128→1 (vs 256→64→1)
9. **Patience aumentado**: 7 épocas (vs 5)
### Configuração
- **Modelo**: Whisper Base (74M params)
- **Datasets**: CORAA + MUPE (~50k samples)
- **LR**: 3e-5 (encoder: 3e-6)
- **Epochs**: até 30 (com early stopping patience=7)
- **Batch size**: 32
### Resultados v3
*(a ser preenchido após o treino)*
---
## Roadmap futuro (se necessário)
### Nível 4 — Dados reais de turn-taking
- Usar NURC-SP com anotações reais de fronteiras de turno
- Gravar dados de reuniões reais em português
- Combinar features de áudio + texto (multimodal)
### Nível 5 — Arquitetura avançada
- Whisper Small (244M params)
- Adicionar features linguísticas (completude sintática via LLM)
- Ensemble de modelos
### Limites teóricos
- Humanos discordam em ~10-15% dos casos de turn-taking
- Teto realista: 90-95%
- Algumas frases são genuinamente ambíguas ("Sim...", "É...")
---
## Referências
- Pipecat Smart Turn: https://github.com/pipecat-ai/smart-turn
- CORAA v1.1: https://huggingface.co/datasets/Racoci/CORAA-v1.1
- CORAA-MUPE-ASR: https://huggingface.co/datasets/nilc-nlp/CORAA-MUPE-ASR
- NURC-SP Corpus Minimo: https://huggingface.co/datasets/nilc-nlp/NURC-SP_Corpus_Minimo
- MLS Portuguese: https://huggingface.co/datasets/facebook/multilingual_librispeech