CoolFace
Modelpublic

gustavo-fluz/web-scraping-slm-mmlu-poc

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
Model Card

🔬 POC: Web Scraping melhora Small Language Models no MMLU?

Pergunta de pesquisa: O quanto web scraping em tempo real pode melhorar a acurácia de um SLM (Small Language Model) rodando localmente em uma GPU?

Benchmark: CAIS/MMLU — Massive Multitask Language Understanding (~14K perguntas de múltipla escolha em 57 matérias)

📋 Resumo

Esta POC compara 3 modos de resposta do SLM:

ModoDescrição
BaselineSLM responde apenas com seu conhecimento interno
RAGSLM recebe contexto de páginas web scrapeadas em tempo real
Rewrite + RAGSLM reescreve a pergunta como query de busca otimizada → busca → scraping → responde

🏗️ Arquitetura

Pergunta MMLU + Opções A/B/C/D
         │
         ├──────────────────────────── [Baseline] ──→ SLM → Resposta
         │
         ├── [RAG] ──→ Query direta ──→ Web Search ──→ Scraping ──→ Chunk + Rerank
         │                                                              │
         │                                              Decontaminação (13-gram)
         │                                                              │
         │                                              Top-3 passages ──→ SLM → Resposta
         │
         └── [Rewrite+RAG] ──→ SLM reescreve query ──→ Web Search ──→ Scraping ──→ ...
                                      │
                          "abstract algebra factor group"
                          (em vez da pergunta completa)

Pipeline detalhado do RAG:

  1. 1.Web Search — busca no DuckDuckGo (grátis) ou Google via SerpApi
  2. 2.Scraping paralelo — extrai texto limpo das top-5 URLs (BeautifulSoup + lxml)
  3. 3.Chunking — divide textos em segmentos de ~256 palavras com overlap
  4. 4.Reranking — seleciona os 3 chunks mais relevantes via similaridade semântica (sentence-transformers)
  5. 5.Decontaminação — remove chunks que contenham a pergunta do benchmark (13-gram Jaccard overlap, ref)
  6. 6.Geração — SLM responde com os chunks como contexto

📚 Fundamentação Científica

PaperResultadoRelevância
Frustratingly Simple Retrieval (2507.01297)+10% MMLU STEM, +33% MMLU Pro com LLaMA 3.1 8B + retrievalPipeline principal, decontaminação
FreshLLMs (2310.03214)+47% absoluto no FreshQA com Google Search + few-shot CoTFormato de evidências no prompt
Query Rewriting for RAG (2305.14283)Vicuna-13B: 34.9→41.5 MMLU STEM com query rewritingReescrita de query

🖥️ Requisitos

Hardware

  • —GPU: NVIDIA com ≥6GB VRAM (4-bit quantizado) ou ≥12GB (float16)
  • —RAM: ≥16GB
  • —Disco: ~10GB (para o modelo)
  • —Internet: necessário para web scraping

Software

  • —Python 3.10+
  • —CUDA 11.8+ (ou 12.x)
  • —Driver NVIDIA compatível

🚀 Instalação

bash
# 1. Clonar repositório
git clone https://huggingface.co/gustavo-fluz/web-scraping-slm-mmlu-poc
cd web-scraping-slm-mmlu-poc

# 2. Criar ambiente virtual
python -m venv venv
source venv/bin/activate  # Linux/Mac
# venv\Scripts\activate   # Windows

# 3. Instalar dependências
pip install -r requirements.txt

📖 Como usar

Rodada rápida (recomendado para primeira execução)

bash
# ~30-45 minutos em GPU, 300 perguntas amostradas estratificadamente
python main.py

Rodada completa

bash
# ~4-6 horas, todas as ~14K perguntas
python main.py --num-samples 0

Apenas baseline (testar se o setup funciona)

bash
# ~5 minutos, sem web scraping
python main.py --baseline-only --num-samples 50

Modelo diferente

bash
# Llama 3.2 3B
python main.py --model "meta-llama/Llama-3.2-3B-Instruct"

# Qwen 2.5 3B
python main.py --model "Qwen/Qwen2.5-3B-Instruct"

# Phi-3 Mini
python main.py --model "microsoft/Phi-3-mini-4k-instruct"

Matérias específicas

bash
# Apenas STEM
python main.py --subjects "abstract_algebra,anatomy,astronomy,college_biology,college_chemistry,college_computer_science,college_mathematics,college_physics"

Com Google Search (melhor qualidade de busca)

bash
# SerpApi (precisa de API key — $50/mês, 5000 buscas)
python main.py --engine serpapi --serpapi-key "YOUR_KEY"

5-shot (como no paper original do MMLU)

bash
python main.py --few-shot 5

⚙️ Todos os parâmetros

bash
python main.py --help
ParâmetroDefaultDescrição
--modelmicrosoft/Phi-4-mini-instructID do modelo no HuggingFace
--no-4bitFalseDesabilitar quantização 4-bit
--dtypebfloat16Tipo de ponto flutuante
--engineduckduckgoMotor de busca (duckduckgo ou serpapi)
--serpapi-keyNoneAPI key para SerpApi
--max-search-results5URLs por busca
--num-samples300Perguntas para avaliar (0 = todas)
--subjectsNoneMatérias específicas (vírgula-separadas)
--few-shot0Exemplos few-shot
--seed42Seed para reprodutibilidade
--baseline-onlyFalseApenas baseline
--no-rewriteFalseSem query rewriting
--output-dirresultsDiretório de saída
--no-plotsFalseNão gerar gráficos

📊 Output

Após a execução, a pasta results/ conterá:

results/
├── report.json                    # Relatório completo com métricas
├── predictions_baseline.json      # Cada predição do baseline
├── predictions_rag.json           # Cada predição do RAG
├── predictions_rewrite_rag.json   # Cada predição do Rewrite+RAG
├── accuracy_comparison.png        # Gráfico: barras comparando os 3 modos
├── accuracy_by_subject.png        # Gráfico: accuracy por matéria
└── run.log                        # Log completo da execução

Exemplo de report.json

json
{
  "metadata": {
    "model_id": "microsoft/Phi-4-mini-instruct",
    "num_samples": 300,
    "search_engine": "duckduckgo",
    "timestamp": "2025-04-26 10:30:00"
  },
  "modes": {
    "baseline": {
      "accuracy": 0.65,
      "correct": 195,
      "total": 300,
      "by_subject": { "abstract_algebra": { "accuracy": 0.5, "correct": 3, "total": 6 } }
    },
    "rag": {
      "accuracy": 0.72,
      "correct": 216,
      "total": 300
    },
    "rewrite_rag": {
      "accuracy": 0.74,
      "correct": 222,
      "total": 300
    }
  },
  "comparison": {
    "baseline_vs_rag": {
      "baseline_accuracy": 0.65,
      "rag_accuracy": 0.72,
      "absolute_improvement": 0.07,
      "relative_improvement": 0.107
    }
  }
}

🔧 Estrutura do código

ArquivoResponsabilidade
main.pyEntry point, CLI, orquestração
config.pyTodas as configurações (dataclasses)
web_scraper.pyWeb search (DDG/SerpApi) + scraping paralelo
rag_pipeline.pyChunking, reranking semântico, decontaminação
slm.pyCarregamento do modelo, prompts, extração de resposta
evaluator.pyDataset MMLU, loop de avaliação, métricas, gráficos

⚠️ Notas importantes

  1. 1.Decontaminação: O pipeline remove automaticamente chunks que contenham texto muito similar à pergunta do MMLU. Sem isso, os scores podem inflar em até 3.6% (ref).
  1. 1.Rate limiting: O DuckDuckGo é gratuito mas tem rate limiting. Se estiver rodando com muitas perguntas, pode haver pausas. Para avaliações em larga escala, use o SerpApi.
  1. 1.Reprodutibilidade: As buscas web retornam resultados diferentes ao longo do tempo. Os resultados exatos podem variar entre execuções. Os arquivos predictions_*.json salvam tudo para análise posterior.
  1. 1.Domínios bloqueados: Por padrão, resultados de huggingface.co, github.com, chegg.com e coursehero.com são filtrados para evitar contaminação.
  1. 1.VRAM: Com quantização 4-bit, o Phi-4-mini usa ~3-4GB de VRAM. O reranker (sentence-transformers) usa ~200MB adicionais.

📄 Licença

Este código é fornecido como POC para fins de pesquisa.

📚 Referências

  • —Hendrycks et al. "Measuring Massive Multitask Language Understanding" (2021) — MMLU
  • —Shi et al. "Frustratingly Simple Retrieval Improves Reasoning Benchmarks" (2025) — arxiv 2507.01297
  • —Vu et al. "FreshLLMs: Refreshing LLMs with Search Engine Augmentation" (2023) — arxiv 2310.03214
  • —Ma et al. "Query Rewriting for Retrieval-Augmented LLMs" (2023) — arxiv 2305.14283