| name | nlp-engineer |
| description | NLP processing covering tokenization, named entity recognition, sentiment analysis, text classification, summarization, topic modeling, language detection, text preprocessing, transformer architecture, and Hugging Face pipeline usage.
Use when the user asks about nlp engineer, nlp engineer best practices, or needs guidance on nlp engineer implementation.
Do NOT use when the user needs a different specialized skill or is asking about an unrelated technology domain.
|
| license | Apache-2.0 |
| metadata | {"author":"foundry-skills","version":"1.0.0","tags":"ai-ml deep-learning guide","category":"ai-machine-learning","subcategory":"applied-ai","depends":"","disclaimer":"none","difficulty":"advanced"} |
NLP Engineer
Overview
Natural Language Processing (NLP) encompasses techniques for understanding, generating, and transforming human language with computers. This skill covers both classical NLP methods and modern transformer-based approaches, with practical implementations using Hugging Face, spaCy, and NLTK.
Text Preprocessing
Standard Pipeline
import re
import unicodedata
class TextPreprocessor:
"""Standard text preprocessing pipeline."""
def __init__(self, lowercase: bool = True, remove_urls: bool = True,
remove_html: bool = True, remove_special_chars: bool = False):
self.lowercase = lowercase
self.remove_urls = remove_urls
self.remove_html = remove_html
return text
def process_batch(self, texts: list[str]) -> list[str]:
return [self.process(t) for t in texts]
Stopword Removal and Stemming
import nltk
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer, PorterStemmer
nltk.download('stopwords')
nltk.download('wordnet')
class LinguisticPreprocessor:
def __init__(self, language: str = "english", use_lemma: bool = True):
self.stop_words = set(stopwords.words(language))
self.lemmatizer = WordNetLemmatizer() if use_lemma else None
elif self.stemmer:
tokens = [self.stemmer.stem(t) for t in tokens]
return tokens
When to Preprocess
| Task | Lowercase | Remove Stop Words | Stemming | Remove Punctuation |
|---|
| Transformer models | NO | NO | NO | NO |
| TF-IDF classification | YES | YES | Optional | YES |
| Topic modeling | YES | YES | YES | YES |
| Sentiment analysis (classical) | YES | Sometimes | NO | NO |
| Named entity recognition | NO | NO | NO | NO |
| Search indexing | YES | Sometimes | Optional | Optional |
Key insight: Modern transformer models handle raw text best. Only preprocess for classical ML or information retrieval tasks.
Tokenization
Tokenizer Types
text = "The cat sat on the mat."
word_tokens = text.split()
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("gpt2")
bpe_tokens = tokenizer.tokenize("unhappiness")
tokenizer = AutoTokenizer.from_pretrained("t5-base")
sp_tokens = tokenizer.tokenize("unhappiness")
Tokenizer Comparison
| Tokenizer | Algorithm | Models | Vocabulary | Handles Unknown |
|---|
| BPE | Byte-Pair Encoding | GPT, RoBERTa | 30K-50K | Subword fallback |
| WordPiece | Greedy longest match | BERT | 30K | [UNK] token |
| SentencePiece | Unigram or BPE | T5, LLaMA | 32K | Subword fallback |
| Tiktoken | BPE (optimized) | GPT-4, GPT-4o | 100K+ | Byte fallback |
Practical Token Counting
import tiktoken
def count_tokens(text: str, model: str = "gpt-4o") -> int:
"""Count tokens for a given model."""
encoding = tiktoken.encoding_for_model(model)
return len(encoding.encode(text))
def truncate_to_tokens(text: str, max_tokens: int, model: str = "gpt-4o") -> str:
"""Truncate text to fit within token limit."""
encoding = tiktoken.encoding_for_model(model)
tokens = encoding.encode(text)
if len(tokens) <= max_tokens:
return text
return encoding.decode(tokens[:max_tokens])
Named Entity Recognition (NER)
spaCy NER
import spacy
nlp = spacy.load("en_core_web_trf")
def extract_entities(text: str) -> list[dict]:
"""Extract named entities with spaCy."""
doc = nlp(text)
entities = []
for ent in doc.ents:
entities.append({
Hugging Face NER
from transformers import pipeline
ner_pipeline = pipeline(
"ner",
model="dslim/bert-base-NER",
aggregation_strategy="simple",
)
results = ner_pipeline("Elon Musk founded SpaceX in Hawthorne, California.")
Custom NER Training
import spacy
from spacy.training import Example
def train_custom_ner(
train_data: list[tuple[str, dict]],
model: str = "en_core_web_sm",
n_iter: int = 30,
output_dir: str = "./custom_ner",
):
"""Train a custom NER model with new entity types."""
nlp = spacy.load(model)
train_data = [
("Order #12345 shipped via FedEx", {"entities": [(6, 12, "ORDER_ID"), (25, 30, "CARRIER")]}),
("Tracking number TRK-9876 for UPS", {"entities": [(16, 24, "TRACKING"), (29, 32, "CARRIER")]}),
]
Sentiment Analysis
Hugging Face Sentiment
from transformers import pipeline
sentiment = pipeline("sentiment-analysis", model="cardiffnlp/twitter-roberta-base-sentiment-latest")
result = sentiment("This product exceeded my expectations!")
fine_grained = pipeline("sentiment-analysis", model="nlptown/bert-base-multilingual-uncased-sentiment")
result = fine_grained("The food was okay but nothing special.")
Aspect-Based Sentiment
def aspect_sentiment(text: str, aspects: list[str], client) -> dict:
"""Analyze sentiment for specific aspects of a review."""
prompt = f"""Analyze the sentiment for each aspect in this review.
For each aspect, output: positive, negative, neutral, or not_mentioned.
Review: "{text}"
Aspects to analyze: {json.dumps(aspects)}
Output JSON: {{"aspect": "sentiment"}}"""
"Great camera quality but battery life is terrible. Screen is decent.",
["camera", "battery", "screen", "price"]
)
Text Classification
Zero-Shot Classification
from transformers import pipeline
classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
result = classifier(
"The company announced record quarterly earnings today.",
candidate_labels=["business", "sports", "technology", "politics"],
)
Training a Custom Classifier
from transformers import (
AutoModelForSequenceClassification,
AutoTokenizer,
TrainingArguments,
Trainer,
)
from datasets import Dataset
def train_classifier(
train_data: list[dict],
model_name: str = "distilbert-base-uncased",
trainer.train()
trainer.save_model(output_dir)
return trainer
Summarization
Extractive vs Abstractive
| Approach | Method | Pros | Cons |
|---|
| Extractive | Select key sentences | Faithful to source | May be disjointed |
| Abstractive | Generate new text | Fluent, concise | Risk of hallucination |
Abstractive Summarization
from transformers import pipeline
summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
long_text = """[Long article text here...]"""
summary = summarizer(
long_text,
max_length=150,
min_length=50,
do_sample=False,
)
print(summary[0]["summary_text"])
Hierarchical Summarization for Long Documents
def hierarchical_summarize(
text: str,
chunk_size: int = 3000,
model_name: str = "facebook/bart-large-cnn",
) -> str:
"""Summarize long documents by chunking, summarizing, then re-summarizing."""
summarizer = pipeline("summarization", model=model_name)
chunks = [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]
if len(combined.split()) > 500:
final = summarizer(combined, max_length=200, min_length=50)[0]["summary_text"]
return final
return combined
Topic Modeling
BERTopic (Modern Approach)
from bertopic import BERTopic
def discover_topics(documents: list[str], n_topics: int = "auto") -> dict:
"""Discover topics in a collection of documents using BERTopic."""
topic_model = BERTopic(
language="english",
nr_topics=n_topics if n_topics != "auto" else None,
verbose=True,
)
topics, probs = topic_model.fit_transform(documents)
"topics": topic_docs,
"assignments": topics,
"probabilities": probs,
}
LDA (Classical Approach)
from sklearn.decomposition import LatentDirichletAllocation
from sklearn.feature_extraction.text import CountVectorizer
def lda_topics(documents: list[str], n_topics: int = 10) -> dict:
"""Classical LDA topic modeling."""
vectorizer = CountVectorizer(max_df=0.95, min_df=2, max_features=5000, stop_words="english")
doc_term_matrix = vectorizer.fit_transform(documents)
lda = LatentDirichletAllocation(
n_components=n_topics,
random_state=42,
top_words = [feature_names[i] for i in topic.argsort()[:-11:-1]]
topics[topic_idx] = top_words
return topics
Language Detection
from langdetect import detect, detect_langs
def detect_language(text: str) -> dict:
"""Detect the language of input text."""
language = detect(text)
all_langs = detect_langs(text)
return {
"primary": language,
"all": [{"lang": str(l).split(":")[0], "prob": l.prob} for l in all_langs],
}
from transformers import pipeline
lang_detector = pipeline("text-classification", model="papluca/xlm-roberta-base-language-detection")
result = lang_detector("Bonjour le monde")
Transformer Architecture Overview
Core Components
Input Text
|
[Tokenization]
|
[Token Embeddings + Position Embeddings]
|
+-- Transformer Block (x N layers) --+
| |
| [Multi-Head Self-Attention] |
| [Add & Layer Norm] |
| [Feed-Forward Network] |
# ... (condensed) ...
|
[Task-Specific Head]
|
Output
Architecture Families
| Architecture | Type | Examples | Best For |
|---|
| Encoder-only | BERT-style | BERT, RoBERTa, DeBERTa | Classification, NER, extraction |
| Decoder-only | GPT-style | GPT-4, LLaMA, Mistral | Text generation, chat |
| Encoder-Decoder | Seq2Seq | T5, BART, mBART | Translation, summarization |
Hugging Face Pipeline Quick Reference
from transformers import pipeline
sentiment = pipeline("sentiment-analysis")
sentiment("I love this movie!")
ner = pipeline("ner", aggregation_strategy="simple")
ner("John works at Google in New York.")
extractor = pipeline("feature-extraction")
embeddings = extractor("Hello world")
Checklist
When to Use
Use this skill when:
- Designing or implementing nlp engineer solutions
- Reviewing or improving existing nlp engineer approaches
- Making architectural or implementation decisions about nlp engineer
- Learning nlp engineer patterns and best practices
- Troubleshooting nlp engineer-related issues
Do NOT use this skill when:
- The question is about a fundamentally different technology domain
- A more specific sibling skill covers the exact topic needed
- The user needs a complete hands-on tutorial rather than expert guidance
Output Format
# Nlp Engineer Analysis
## Context Assessment
[Situation summary and constraints]
## Recommended Approach
[Primary recommendation with rationale]
## Implementation Steps
1. [Step with specific details]
2. [Step with specific details]
3. [Step with specific details]
## Trade-offs and Considerations
- [Key trade-off 1]
- [Key trade-off 2]
## Next Steps
- [Immediate action item]
- [Follow-up action item]
Example
Input: "Help me implement nlp engineer for a medium-scale production application"
Output: A structured analysis covering current state assessment, recommended nlp engineer approach with specific patterns, implementation roadmap with milestones, and risk mitigation strategies tailored to the application scale and constraints.
Edge Cases
- Legacy system integration: When nlp engineer must coexist with legacy approaches, provide a gradual migration path rather than a complete rewrite
- Scale mismatch: When the solution complexity exceeds the project scale, recommend a simpler approach and note when to revisit
- Team skill gaps: When the team lacks experience with the recommended approach, include learning resources and simpler alternatives
- Conflicting requirements: When constraints conflict (e.g., performance vs. maintainability), explicitly state the trade-off and recommend based on stated priorities