TP1: O Classificador de Habilidades
Redes Neurais, NLP e MLOps (Fases 1 e 2 do Pipeline)
🧭 Por que este TP existe?
Volte ao metadata.yaml do exercício “Divisão” que você viu na página de Visão Geral. Repare no campo skills:
skills:
- "matematica"
- "io"Esses rótulos dizem quais habilidades cognitivas um aluno precisa dominar para resolver aquele exercício. Hoje, quem classifica essas skills é o professor, manualmente. Isso é lento, subjetivo e não escala para centenas de exercícios.
A missão do TP1 é construir uma Rede Neural Clássica que leia o texto bruto de um enunciado de programação e preveja automaticamente quais skills ele exige. Esse modelo será o motor das Fases 1 e 2 do Pipeline WOKDEX.
O acompanhamento dos grupos registrados no GitLab, links diretos dos repositórios e a listagem de alunos com sinalizadores de status estão disponíveis em Grupos do TP1 (2026-2).
📖 Leitura Obrigatória (Fundamentação)
Antes de programar, vocês precisam ler e entender estes dois artigos científicos. Eles serão a base do Draft 1 na seção de Trabalhos Relacionados.
- Artigo 1: Kim, Y. (2014). “Convolutional Neural Networks for Sentence Classification”. arXiv:1408.5882
-
Por que ler: É exatamente o que vocês vão construir — uma rede neural que recebe uma frase e classifica em categorias. O paper tem apenas 6 páginas e mostra como vetorizações de texto (Word2Vec, TF-IDF) alimentam um classificador profundo. A arquitetura descrita é a referência mais citada do mundo para classificação de texto com Deep Learning.
- Artigo 2: Feng, Z. et al. (2020). “CodeBERT: A Pre-Trained Model for Programming and Natural Language”. arXiv:2002.08155
-
Por que ler: Enquanto o artigo anterior trata de classificação de textos genéricos, este mostra que existe um campo de pesquisa inteiro dedicado a aplicar NLP especificamente em código-fonte e enunciados de programação. Vocês não vão usar o CodeBERT em si (ele é pesado demais para o escopo do TP), mas entender que o problema que vocês estão atacando já é estudado por grandes labs (Microsoft Research) dá lastro científico ao Draft 1.
📚 O que é uma Skill no WOKDEX e no Dataset?
As habilidades (skills) representam os conceitos algorítmicos e estruturas de dados necessários para resolver um exercício.
Para o TP1, trabalharemos com as 25 Skills/Tópicos mais representativos da amostra (que cobrem 94% do volume de problemas e incluem desde estruturas básicas até paradigmas avançados como Grafos e Backtracking):
| # | Skill / Tópico | Ocorrências no Dataset | Exemplo Típico |
|---|---|---|---|
| 1 | Array (Vetores) |
1.626 | “Encontre o par de elementos que soma o alvo” |
| 2 | String (Textos) |
683 | “Verifique se a palavra é um palíndromo” |
| 3 | Hash Table (Tabela Hash / Dicionário) |
589 | “Conte a frequência de cada caractere em \(O(N)\)” |
| 4 | Dynamic Programming (Programação Dinâmica) |
508 | “Calcule o número de formas de subir uma escada” |
| 5 | Math (Matemática) |
503 | “Converta números romanos para inteiros” |
| 6 | Sorting (Ordenação) |
391 | “Ordene o array por frequência decrescente” |
| 7 | Greedy (Algoritmos Gulosos) |
366 | “Distribua doces minimizando o total” |
| 8 | Binary Search (Busca Binária) |
259 | “Encontre a raiz quadrada inteira em \(O(\log N)\)” |
| 9 | Depth-First Search (Busca em Profundidade / DFS) |
242 | “Percorra todos os caminhos válidos da árvore” |
| 10 | Matrix (Matrizes / Arrays 2D) |
216 | “Rotacione uma imagem \(N \times N\) em 90 graus” |
| 11 | Bit Manipulation (Manipulação de Bits) |
212 | “Conte o número de bits 1 na representação binária” |
| 12 | Breadth-First Search (Busca em Largura / BFS) |
193 | “Encontre o menor caminho no grafo” |
| 13 | Prefix Sum (Soma de Prefixos) |
184 | “Calcule a soma de um intervalo em \(O(1)\)” |
| 14 | Tree (Árvores) |
182 | “Calcule a profundidade máxima da árvore” |
| 15 | Two Pointers (Dois Ponteiros) |
181 | “Remova duplicatas de um vetor ordenado in-place” |
| 16 | Simulation (Simulação) |
165 | “Simule o movimento de um robô no grid” |
| 17 | Heap (Priority Queue) (Heap / Fila de Prioridade) |
164 | “Encontre o K-ésimo maior elemento” |
| 18 | Counting (Contagem de Elementos) |
145 | “Conte elementos com frequências específicas” |
| 19 | Stack (Pilhas) |
138 | “Valide se parênteses e colchetes estão balanceados” |
| 20 | Graph (Grafos) |
133 | “Detecte ciclos ou caminhos em grafos direcionados” |
| 21 | Sliding Window (Janela Deslizante) |
130 | “Maior substring contígua sem caracteres repetidos” |
| 22 | Binary Tree (Árvore Binária) |
129 | “Inverta ou reconstrua uma árvore binária” |
| 23 | Enumeration (Enumeração) |
112 | “Gere todas as combinações válidas de 3 dígitos” |
| 24 | Design (Projeto de Estruturas) |
94 | “Implemente um LRU Cache ou Fila usando Pilhas” |
| 25 | Backtracking (Retrocesso / Busca Exaustiva) |
87 | “Resolva o problema das N Rainhas ou Sudoku” |
[!IMPORTANT] Formulação do Problema: Classificação Multi-Label
Um mesmo problema pode exigir múltiplas skills simultâneas (por exemplo, um exercício pode ter rótulos['Array', 'Sorting', 'Two Pointers']).
Portanto, sua Rede Neural NÃO deve usar Softmax na saída!
Utilize: 1. Camada de saída com 25 neurônios e função de ativaçãosigmoid. 2. Função de perda (loss):binary_crossentropy. 3. Binarização dos alvos:MultiLabelBinarizerda bibliotecascikit-learn.
📦 O Dataset Oficial (leetcode_problems_pt)
A base oficial de dados para o TP1 é o LeetCode Problems Dataset Bilíngue, disponibilizado em formato tabular (CSV) e estruturado (JSON), com 2.830 enunciados completos em Português (PT-BR).
- 📊 Visualizar Relatório Exploratório Interativo (HTML) (Distribuições de tamanho de texto, frequências e estatísticas)
- 📄 Download do Relatório Exploratório (PDF) (Versão consolidada para leitura e impressão)
- 📥 Download do Dataset em CSV (23.3 MB)
- 📥 Download do Dataset em JSON (25.4 MB)
- 📖 Documentação Técnica & Especificação de Schemas
🐍 Snippet de Carga Rápida (Python / Pandas)
O Aluno A (Engenheiro de Dados) pode iniciar o pipeline com o seguinte fluxo:
import pandas as pd
import ast
from sklearn.preprocessing import MultiLabelBinarizer
# 1. Carregar dataset oficial
df = pd.read_csv("trabalho/database/leetcode_problems_pt.csv")
# 2. Selecionar features de entrada e target
# X: Texto do enunciado em Português (título + descrição completa contendo exemplos e restrições)
X_text = (df["title_pt"].fillna("").astype(str) + "\n\n" + df["description_pt"].fillna("").astype(str))
# 3. Tratar a coluna de tópicos (que vem como string de lista)
def parse_topics(val):
if pd.isna(val): return []
try: return ast.literal_eval(val) if isinstance(val, str) else val
except: return []
df["topics_list"] = df["topics"].apply(parse_topics)
# 4. Filtrar para as Top 25 Skills
TOP_25_SKILLS = [
"Array", "String", "Hash Table", "Dynamic Programming", "Math",
"Sorting", "Greedy", "Binary Search", "Depth-First Search", "Matrix",
"Bit Manipulation", "Breadth-First Search", "Prefix Sum", "Tree", "Two Pointers",
"Simulation", "Heap (Priority Queue)", "Counting", "Stack", "Graph",
"Sliding Window", "Binary Tree", "Enumeration", "Design", "Backtracking"
]
df["target_skills"] = df["topics_list"].apply(
lambda topics: [t for t in topics if t in TOP_25_SKILLS]
)
# 5. Binarizar alvos para Multi-Label (Y terá shape: [N, 25])
mlb = MultiLabelBinarizer(classes=TOP_25_SKILLS)
Y = mlb.fit_transform(df["target_skills"])
print("Total de classes mapeadas:", len(mlb.classes_))
print(f"Shape final de Y: {Y.shape}")Data Limite de Entrega (Checkpoint 1): 12/09 (Sexta-feira)
Valor: 10 Pontos (5 em Grupo, 5 Individual)
[!IMPORTANT] Sobre o timing do NLP: A vetorização de texto (TF-IDF, Word2Vec) será coberta na Aula 9 (Módulo 2 — Embeddings). Vocês podem começar a construir toda a infraestrutura (Keras, FastAPI, Docker, testes) usando o conhecimento dos Labs 04–08 enquanto aguardam essa aula para fechar o pipeline de dados do Aluno A. O deadline foi calibrado para que vocês tenham pelo menos 1 semana após a Aula 9.
[!TIP] Baseline Obrigatório: No Draft 1, o grupo deve comparar a performance da Rede Neural contra um baseline simples (ex: TF-IDF + Logistic Regression / LinearSVC com
OneVsRestClassifier). A tabela comparativa (Precision, Recall, F1-Macro, tempo de treino) é item obrigatório da avaliação.
👥 A Divisão de Tarefas na Equipe (4 Alunos em 2 Duplas)
Para garantir que o trabalho seja executado de forma fluida ao longo dos 20 dias, a carga horária estimada é de 10 a 15 horas de dedicação individual por aluno (~3 a 4 horas por semana). A equipe divide-se em duas duplas complementares:
┌────────────────────────────────────────────────────────┐
│ EQUIPE DE 4 ALUNOS │
├───────────────────────────┬────────────────────────────┤
│ 🔬 DUPLA 1: DADOS & ML │ ⚙️ DUPLA 2: ENGENHARIA │
│ (O Cérebro Matemático) │ (A Casca MLOps / Docker) │
├───────────────────────────┼────────────────────────────┤
│ Aluno A: Dados & NLP │ Aluno C: Backend FastAPI │
│ Aluno B: Redes Neurais │ Aluno D: DevOps & Pytest │
└───────────────────────────┴────────────────────────────┘
🔬 Dupla 1: Ciência e Dados (O Cérebro) — ~10 a 15h por aluno
Esta dupla é focada no pré-processamento de linguagem natural (NLP) em português e no treinamento da Rede Neural. O output final da dupla é o pipeline serializado (vectorizer.pkl / mlb.pkl), o modelo treinado (modelo_skills.keras) e as métricas de convergência.
- Aluno A (Engenheiro de Dados):
- Dedicação: ~10–12 horas.
- Tarefas: Carregar
leetcode_problems_pt.csv, limpar os enunciados em português (description_pt), tratar as 25 skills comMultiLabelBinarizer, criar e serializar a vetorização de texto (ex:TfidfVectorizer(max_features=5000, ngram_range=(1,2))), e gerar a divisão estratificada Treino/Validação/Teste (80/10/10).
- Aluno B (Engenheiro de Machine Learning):
- Dedicação: ~12–15 horas.
- Tarefas: Construir e treinar o Baseline (ex:
LogisticRegression/LinearSVCOvR), construir a Rede Neural Keras (camadas Densas, Dropout 0.3-0.5, saída 25 neurônios Sigmoid +binary_crossentropy), calibrar o limiar de decisão (\(\tau\)), gerar gráficos de loss/épocas e calcular o F1-Score Macro e Micro.
⚙️ Dupla 2: Engenharia de Software e MLOps (A Casca) — ~10 a 15h por aluno
Esta dupla pega o modelo exportado pela Dupla 1 e constrói um microsserviço moderno, conteinerizado e testado, pronto para ser consumido pelo Agente do TP3.
- Aluno C (Dev Backend Python / FastAPI):
- Dedicação: ~10–12 horas.
- Tarefas: Criar a API FastAPI, definir contratos estritos de entrada e saída com Pydantic (
PredictRequest,PredictResponse), carregar os artefatos (modelo_skills.kerasevectorizer.pkl) na inicialização da aplicação (usandolifespan), e implementar os endpointsPOST /predicteGET /health.
- Aluno D (DevOps, QA e Docker):
- Dedicação: ~10–12 horas.
- Tarefas: Escrever o
Dockerfileotimizado edocker-compose.yml, configurar a suite de testes automatizados compytest(mínimo 5 testes), configurar a pipeline de CI no GitLab (.gitlab-ci.yml), e garantir que a API suba limpa em qualquer máquina com um único comandodocker run.
[!TIP] 🤝 Dinâmica de Pareamento (Pair Programming) e Desenvolvimento Não-Bloqueante:
A Dupla 2 não deve esperar a Dupla 1 concluir o treinamento da rede neural para começar a trabalhar. Usem a abordagem de Contrato Primeiro (API-First / Contract-Driven): 1. No primeiro dia, a equipe alinha os modelos Pydantic (PredictRequestePredictResponse). 2. A Dupla 2 cria um modelo simulado (mock) que devolve predições estáticas e constrói toda a API FastAPI, oDockerfilee a suite depytestem paralelo. 3. Os membros de cada dupla devem praticar pareamento contínuo, code reviews e ajuda mútua para manter o fluxo de entrega sem gargalos.
🔌 A API que você vai construir
O produto final de engenharia do TP1 é uma API REST conteinerizada. Abaixo está o contrato exato:
Requisição: POST /predict
{
"enunciado": "Dada uma lista de inteiros nums e um inteiro target, retorne os índices dos dois números cuja soma seja igual a target."
}Resposta esperada:
{
"skills": [
{ "skill": "Array", "confidence": 0.94 },
{ "skill": "Hash Table", "confidence": 0.88 },
{ "skill": "Two Pointers", "confidence": 0.72 }
],
"model_version": "v1.0",
"input_length": 132
}[!IMPORTANT] No TP3, o Agente Autônomo vai chamar esta API como uma ferramenta (
predict_skills()). Se a sua API não estiver de pé e respondendo neste formato, o agente do TP3 não funcionará. É por isso que o Docker é obrigatório.
📝 Relatório Técnico no README.md (Documentação do TP1)
Para não sobrecarregar a equipe com formatação de artigos nesta fase inicial, a entrega do TP1 é 100% focada em Engenharia, Código e Métricas Técnicas.
O grupo deve documentar de forma clara e estruturada no próprio README.md do repositório GitLab (que servirá de base direta para o Artigo Final no TP3):
- Trabalhos Relacionados e Fundamentação:
- Contextualizar brevemente os artigos base (Kim 2014 para CNN/NLP e CodeBERT para representação de código).
- Metodologia Preditiva (Dupla 1):
- Justificativa da Formulação Multi-Label: Explicar matematicamente por que a saída usa Sigmoid independente por neurônio +
binary_crossentropyem vez de Softmax. - Arquitetura da Rede: Tabela com as camadas da rede neural, número de neurônios, funções de ativação, taxa de Dropout e otimizador.
- Justificativa da Formulação Multi-Label: Explicar matematicamente por que a saída usa Sigmoid independente por neurônio +
- Resultados e Tabela Comparativa Obrigatória (Dupla 1 e 2):
- Tabela comparando o Baseline (TF-IDF + Logistic Regression / SVM) contra a Rede Neural (Keras):
| Modelo | Precision (Macro) | Recall (Macro) | F1-Score (Macro) | F1-Score (Micro) | Tempo de Treino |
|---|---|---|---|---|---|
| Baseline (TF-IDF + Regressão Logística OvR) | … | … | … | … | ~2s |
| Rede Neural Keras (Dense + Dropout) | … | … | … | … | ~45s |
- Análise de Desbalanceamento, Threshold \(\tau\) e o Abismo Semântico (Dupla 1):
- Gráfico de convergência (Loss de Treino vs. Validação).
- Discussão do Abismo Semântico (Semantic Gap): Analisar criticamente quais das 25 classes foram mais fáceis/difíceis. Por que classes sintáticas como
StringouTreeapresentam F1 mais elevado do que paradigmas abstratos comoDynamic ProgrammingouGreedy? - Efeito do limiar de decisão \(\tau\) dinâmico no F1-Score das classes minoritárias (ex:
Backtracking).
- Engenharia e Arquitetura MLOps (Dupla 2):
- Diagrama ou descrição da conteinerização Docker, latência média da rota
POST /predict(em milissegundos) e testes unitários.
- Diagrama ou descrição da conteinerização Docker, latência média da rota
🧪 Sugestões de Testes Automatizados Obrigatórios (pytest)
O Aluno D (DevOps) deve implementar, no mínimo, a seguinte suite de testes com pytest (arquivo tests/test_api.py):
| # | Função de Teste | O que deve verificar |
|---|---|---|
| 1 | test_api_health |
A rota GET /health responde HTTP 200 e status "ok" |
| 2 | test_predict_valid_input |
POST /predict com enunciado válido retorna HTTP 200 e campos skills, model_version, input_length |
| 3 | test_skills_in_top25 |
Todas as skills retornadas na lista pertencem estritamente às 25 classes válidas |
| 4 | test_confidence_range |
O valor de confidence de cada skill prevista está rigorosamente no intervalo \([0.0, 1.0]\) |
| 5 | test_empty_input_validation |
Enunciado vazio ("" ou whitespace) retorna HTTP 422 (validação Pydantic) |
| 6 | test_predict_deterministic |
Duas chamadas com o mesmo texto produzem as mesmas predições |
📊 Rubrica de Avaliação Detalhada (8 Pontos)
Nota Individual (4 pts)
| Critério | Pontos | Detalhes |
|---|---|---|
| Commits individuais na branch correta | 1 | Avaliado via Git Blame (evidência de autoria) |
| Entrega técnica individual funcionando | 2 | Pipeline do Aluno A OU Rede do Aluno B OU FastAPI do Aluno C OU Docker/Testes do Aluno D |
| Qualidade e organização do código | 1 | Boas práticas, docstrings, código modular e limpo |
Nota do Grupo (4 pts)
| Critério | Pontos | Detalhes |
|---|---|---|
| API integrada responde no formato correto | 1 | docker run + curl POST /predict funcional |
| Performance da Rede Neural (F1-Score Macro) | 1 | Veja escala progressiva calibrada abaixo |
| Relatório Técnico no README.md completo | 2 | Tabela comparativa baseline vs. rede, matriz de confusão, discussão do abismo semântico |
Escala Progressiva de Performance (F1-Score Macro)
| Nível | F1-Score Macro | Pontuação | Critério de Engenharia |
|---|---|---|---|
| Mínimo | \(\ge 35\%\) | 0.3 pt | Supera o baseline ingênuo / classe majoritária |
| Bom | \(\ge 50\%\) | 0.7 pt | Rede Keras regularizada (Dropout, limiar \(\tau\) calibrado) |
| Excelente | \(\ge 65\%\) | 1.0 pt | Otimização avançada de hiperparâmetros ou análise exemplar de erro |
[!NOTE] Por que a régua de F1-Macro é calibrada nesta faixa?
Lembre-se do Abismo Semântico (Semantic Gap): os enunciados usam metáforas narrativas (“Alice divide doces”) e a técnica algorítmica (DP, Guloso) é uma abstração matemática implícita. Um F1-Macro de 50–65% em 25 classes multi-label desbalanceadas é um resultado de engenharia sólido e realista. A profundidade da sua análise crítica noREADME.mdtem peso decisivo na pontuação do grupo.
📅 Cronograma Sugerido (4 Semanas)
Para não acumular trabalho e perder a data de entrega, sugerimos o seguinte ritmo para a equipe:
| Período | Foco da Equipe | Meta da Semana |
|---|---|---|
| Semana 1 | Pesquisa e Setup | Leitura do artigo (Kim 2014), divisão de papéis, setup do repositório GitLab e script base de TF-IDF. |
| Semana 2 | Modelagem | Treinamento do baseline (SVM/LR) e primeira versão da Rede Neural (Keras). |
| Semana 3 | Engenharia MLOps | Otimização do F1-Score, criação da API em FastAPI e criação do Dockerfile. |
| Semana 4 | Qualidade e README | Escrita dos testes pytest, validação final, preenchimento do relatório no README.md e Merge Request final. |
✅ Checklist de Entrega — TP1
🔬 Adendo IC — Golden Benchmark e Estudo de Ablação Textual (Opcional)
Enquanto as equipes regulares treinam seus classificadores na divisão padrão, as equipes IC atuam como o Comitê Científico de Validação do ecossistema WOKDEX, conduzindo experimentos aprofundados que fundamentarão os artigos da disciplina.
O que fazer
- Curadoria do Golden Benchmark Set (100 Problemas):
- Selecionar e auditar minuciosamente uma amostra estratificada de 100 problemas do dataset
leetcode_problems_pt.csv, cobrindo as 25 skills e os níveisEasy,MediumeHard. - Verificar a fidelidade do enunciado em português e validar a consistência das skills anotadas.
- Este conjunto será o teste cego do professor para avaliar as APIs de todas as equipes no Demoday.
- Selecionar e auditar minuciosamente uma amostra estratificada de 100 problemas do dataset
- Estudo de Ablação Textual (TF-IDF vs. Embeddings em Português):
- Comparar o desempenho da Rede Neural sob diferentes representações vetoriais de texto em PT-BR:
TF-IDFesparso (unigramas + bigramas).paraphrase-multilingual-MiniLM-L12-v2(Sentence-Transformers).BERTimbau(neuralmind/bert-base-portuguese-cased).text-embedding-3-small(OpenAI).
- Tabular o F1-Macro e a latência de inferência de cada abordagem.
- Comparar o desempenho da Rede Neural sob diferentes representações vetoriais de texto em PT-BR:
- Análise de Sensibilidade ao Desbalanceamento:
- Testar o impacto de Class Weights e limiares de decisão dinâmicos (\(\tau_i\)) nas classes com menor suporte estatístico (ex:
Backtrackingcom 87 amostras vs.Arraycom 1.626).
- Testar o impacto de Class Weights e limiares de decisão dinâmicos (\(\tau_i\)) nas classes com menor suporte estatístico (ex:
Entregáveis IC-TP1
[!TIP] Os dados gerados neste adendo comporão diretamente a seção experimental do Artigo 1 da Disciplina (Classificação Semântica de Enunciados em Língua Portuguesa para Educação em Computação).