🧠 AI / ML

ai-ml-nlp-pipeline-designer

Conception de pipelines NLP (tokenization, embeddings, NER, sentiment, summarization) — guide opérationnel avec snippets, critères de décision et anti-patterns.

⚡ Installation & lancement en 1 commande

Copiez-collez dans votre terminal : le skill s'installe dans ~/.claude/skills et Claude Code se lance directement dessus.

macOS / Linux
curl -fsSL https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.sh | sh -s -- ai-ml-nlp-pipeline-designer --launch
Windows (PowerShell)
iex "& { $(iwr -useb https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.ps1) } ai-ml-nlp-pipeline-designer -Launch"

🚀 Déjà installé ?

claude "/ai-ml-nlp-pipeline-designer"

Ou tapez /ai-ml-nlp-pipeline-designer dans une session Claude Code, ou décrivez simplement votre besoin — le skill se déclenche automatiquement via le skill-router.

🔑 Déclencheurs automatiques

Le skill s'active automatiquement quand votre demande contient :

NLP\traitement du langage\NER\sentiment analysis\text classification\spaCy\HuggingFace\

📦 Installation manuelle

git clone https://github.com/khalilbenaz/claude-skills-collection.git cp -r claude-skills-collection/skills/ai-ml-nlp-pipeline-designer ~/.claude/skills/

Payload du plugin : skills/ai-ml-nlp-pipeline-designer · source éditable : ai-ml-skills/nlp-pipeline-designer

📖 Manuel

NLP Pipeline Designer

Guide opérationnel pour concevoir et implémenter des pipelines NLP production-ready, de la tokenization aux tâches avancées.


Étape 1 — Cadrer la tâche et choisir l'approche

Questions à trancher avant tout code :

CritèreApproche légèreApproche Transformer
< 10 k exemples annotésTF-IDF + sklearnSetFit / few-shot
Latence < 50 msDistilBERT, FastTextNon
Corpus françaisCamemBERT, FlauBERTXLM-RoBERTa si multilingue
Généralisation zero-shotNonNLI (MNLI) ou GPT-4o
Tâche extractive simpleregex + spaCy rulesRarement utile

Tâches → modèles recommandés (2026) :


Étape 2 — Prétraitement du corpus

import re, unicodedata
from langdetect import detect

def clean_text(text: str) -> str:
    text = re.sub(r"<[^>]+>", " ", text)               # strip HTML
    text = unicodedata.normalize("NFC", text)           # normalise unicode
    text = re.sub(r"http\S+|www\.\S+", "[URL]", text)  # masque URLs
    text = re.sub(r"\s+", " ", text).strip()
    return text

# Chunking pour textes longs (sliding window)
def chunk_text(text: str, max_tokens: int = 400, overlap: int = 50) -> list[str]:
    words = text.split()
    chunks = []
    for i in range(0, len(words), max_tokens - overlap):
        chunks.append(" ".join(words[i : i + max_tokens]))
    return chunks

Points critiques :


Étape 3 — Tokenization et DataLoader

from transformers import AutoTokenizer
from torch.utils.data import Dataset, DataLoader

tokenizer = AutoTokenizer.from_pretrained("camembert-base")

class TextDataset(Dataset):
    def __init__(self, texts, labels, max_length=512):
        self.encodings = tokenizer(
            texts, truncation=True, padding=True,
            max_length=max_length, return_tensors="pt"
        )
        self.labels = labels

    def __getitem__(self, idx):
        item = {k: v[idx] for k, v in self.encodings.items()}
        item["labels"] = self.labels[idx]
        return item

    def __len__(self):
        return len(self.labels)

loader = DataLoader(TextDataset(train_texts, train_labels), batch_size=16, shuffle=True)

Stratégie textes longs (> 512 tokens) :

  1. Troncation simple : acceptable si l'info utile est en début de texte.
  2. Sliding window + vote : prédire sur chaque chunk, agréger (mean ou max).
  3. Hierarchical model : encoder les phrases, puis encoder le document.

Étape 4 — Fine-tuning

from transformers import AutoModelForSequenceClassification, TrainingArguments, Trainer
import evaluate

model = AutoModelForSequenceClassification.from_pretrained("camembert-base", num_labels=3)

args = TrainingArguments(
    output_dir="./checkpoints",
    num_train_epochs=5,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=32,
    learning_rate=2e-5,          # 2e-5 à 5e-5 pour BERT-like
    weight_decay=0.01,
    warmup_ratio=0.1,
    evaluation_strategy="epoch",
    save_strategy="best",
    load_best_model_at_end=True,
    metric_for_best_model="f1",
    fp16=True,                   # activer si GPU CUDA disponible
)

metric = evaluate.load("f1")
def compute_metrics(eval_pred):
    logits, labels = eval_pred
    preds = logits.argmax(-1)
    return metric.compute(predictions=preds, references=labels, average="macro")

trainer = Trainer(model=model, args=args,
                  train_dataset=train_ds, eval_dataset=val_ds,
                  compute_metrics=compute_metrics)
trainer.train()

Hyperparamètres clés :


Étape 5 — Pipeline spaCy (règles + ML, production rapide)

import spacy

nlp = spacy.load("fr_core_news_lg")

# Ajouter des règles métier avant le ML
ruler = nlp.add_pipe("entity_ruler", before="ner")
ruler.add_patterns([
    {"label": "PRODUIT", "pattern": [{"LOWER": "carte"}, {"LOWER": "visa"}]},
    {"label": "CODE", "pattern": [{"TEXT": {"REGEX": r"^[A-Z]{2}\d{6}$"}}]},
])

doc = nlp("La carte Visa n° AB123456 est expirée.")
for ent in doc.ents:
    print(ent.text, ent.label_)

Quand préférer spaCy au HuggingFace :


Étape 6 — Évaluation rigoureuse

from sklearn.metrics import classification_report
from seqeval.metrics import classification_report as ner_report  # pour NER BIO

# Classification
print(classification_report(y_true, y_pred, target_names=class_names, digits=4))

# NER (format BIO)
print(ner_report(true_tags, pred_tags))  # F1 par type d'entité

Métriques par tâche :

TâcheMétrique principaleMétrique secondaire
Classification binaireF1 macroAUC-ROC
Classification multi-classeF1 macroMatrice de confusion
NERF1 entité exacte (seqeval)F1 partielle
SummarizationROUGE-LBERTScore
QA extractifExact MatchF1 token

Analyse d'erreurs :

errors = [(text, true, pred) for text, true, pred in zip(texts, y_true, y_pred) if true != pred]
# Inspecter les 20 erreurs les plus fréquentes par classe confondue
from collections import Counter
Counter((t, p) for _, t, p in errors).most_common(10)

Étape 7 — Mise en production

# Sérialisation optimisée
from optimum.onnxruntime import ORTModelForSequenceClassification

model_ort = ORTModelForSequenceClassification.from_pretrained("./checkpoints", export=True)
model_ort.save_pretrained("./model_onnx")
# Latence divisée par 2–4 vs PyTorch CPU

# Pipeline HuggingFace prêt à l'emploi
from transformers import pipeline
classifier = pipeline("text-classification", model="./model_onnx",
                      tokenizer=tokenizer, device=-1)
results = classifier(texts, batch_size=32, truncation=True)

Checklist avant déploiement :


Anti-patterns et pièges fréquents

PiègeSymptômeCorrection
Évaluer sur les données d'entraînementF1 = 0.99 en train, 0.60 en testSplit strict, entity-level pour NER
Même tokenizer que le pré-entraînement non respectéRésultats incohérentsAutoTokenizer.from_pretrained(model_name) toujours
Textes > 512 tokens tronqués silencieusementPerte d'information en fin de docSliding window ou chunking explicite
Stopwords supprimés avant TransformerDégradation des performancesNe supprimer les stopwords que pour TF-IDF/classiques
Modèle anglais sur corpus françaisF1 -15 à -30 points vs CamemBERTToujours aligner langue modèle / langue corpus
Fine-tuning sans warmupLoss diverge en début d'entraînementwarmup_ratio=0.1 minimum
Batch trop petit (1-2) avec BNGradients instablesbatch_size >= 8, gradient_accumulation si mémoire limitée
Label imbalance ignoréModèle prédit toujours la classe majoritaireclass_weight="balanced" ou oversampling (imbalanced-learn)

Ressources et outils clés (2026)