Semantic Deduplication
Detect and remove semantically redundant data from your large text datasets using NeMo Curator.
Unlike exact or fuzzy deduplication, which focus on textual similarity, semantic deduplication leverages the meaning of content to identify duplicates. This approach can significantly reduce dataset size while maintaining or even improving model performance.
The technique uses embeddings to identify “semantic duplicates” - content pairs that convey similar meaning despite using different words.
GPU Acceleration: Semantic deduplication requires GPU acceleration for both embedding generation and clustering operations. This method uses cuDF for GPU-accelerated dataframe operations and PyTorch models on GPU for optimal performance.
How It Works
Semantic deduplication identifies meaning-based duplicates using embeddings:
- Generates embeddings for each document using transformer models
- Clusters embeddings using K-means
- Computes pairwise cosine similarities within clusters
- Identifies semantic duplicates based on similarity threshold
- Removes duplicates, keeping one representative per group
Based on SemDeDup: Data-efficient learning at web-scale through semantic deduplication by Abbas et al.
Before You Start
Prerequisites:
- GPU acceleration (required for embedding generation and clustering)
- Stable document identifiers for removal (either existing IDs or IDs managed by the workflow and removal stages)
Running in Docker: When running semantic deduplication inside the NeMo Curator container, ensure the container is started with --gpus all so that CUDA GPUs are available. Without this flag, you will see RuntimeError: No CUDA GPUs are available. Also activate the virtual environment with source /opt/venv/env.sh after entering the container.
Quick Start
Get started with semantic deduplication using the following example of identifying duplicates, then remove them in one step:
Configuration
Configure semantic deduplication using these key parameters:
Step-by-Step Workflow
For fine-grained control, break semantic deduplication into separate stages:
This approach enables analysis of intermediate results and parameter tuning.
Comparison with Other Deduplication Methods
Compare semantic deduplication with other methods:
Key Parameters
| id_field | str | "_curator_dedup_id" | Name of the ID field in the data |
The same discovery rules apply to TextSemanticDeduplicationWorkflow, the pre-computed-embedding SemanticDeduplicationWorkflow, and TextDuplicatesRemovalWorkflow. The extension filter does not infer the reader format: keep input_filetype="parquet" when reading a custom Parquet suffix such as .pq. See Input File Discovery for examples and recursion details.
The lower-level SemanticDeduplicationWorkflow and KMeansStage use the parameter name fit_data_fraction for the same behavior.
Reduce K-means fitting memory
By default, fit_data_fraction=None uses the original single-pass path: each K-means actor loads all of its assigned groups, fits centroids on every row, predicts cluster assignments, and writes the results. This produces the highest-fidelity fit but requires the actor’s full assigned embedding data to fit in GPU memory.
Set a fraction strictly between 0 and 1 to enable a two-pass path:
- Fit pass: Each actor samples
round(fit_data_fraction * number_of_actor_files)files, with a minimum of one file. It reads only the embedding column from those files and cooperatively fits the centroids. - Predict and write pass: Each actor reads every original file group, one group at a time, assigns every row to a centroid, computes centroid distances, writes the partitioned result, and releases the group before reading the next one.
Because sampling is file-based rather than row-based, the realized row fraction can differ from the configured value when file sizes vary. Every actor contributes at least one file, so very small fractions can also sample more data than expected on highly parallel runs. Choose a fraction that leaves enough representative rows for at least n_clusters centroids, and use random_state or kmeans_random_state to make file selection repeatable.
The two-pass path lowers peak GPU memory from roughly all actor rows to the larger of the sampled fit data or one prediction group. The tradeoff is additional I/O: sampled files are read once for embeddings during fitting and again with their full requested columns during prediction. All input rows still receive cluster assignments; the fraction affects only centroid fitting.
Text workflow
Embeddings workflow
KMeansStage with saved centroids
KMeansStage.cache_path controls only centroid persistence. When it is set, actor 0 writes kmeans_centroids.npy after fitting; when it is None, centroids are not saved. This differs from SemanticDeduplicationWorkflow.cache_path, which stores the workflow’s K-means and pairwise intermediate results. The workflow intentionally does not forward its cache path to KMeansStage.cache_path, so use KMeansStage directly when you need the centroid array.
Similarity Threshold
Control deduplication aggressiveness with eps:
- Lower values (such as 0.001): More strict, less deduplication, higher confidence
- Higher values (such as 0.1): Less strict, more aggressive deduplication
Experiment with different values to balance data reduction and dataset diversity.
Embedding Models
Embedding generation uses vLLM as the inference backend. The default model is google/embeddinggemma-300m.
Default (vLLM):
Custom model with vLLM options:
vLLM Embedder (recommended for large models):
For large embedding models, you can generate embeddings separately using VLLMEmbeddingModelStage before running the deduplication workflow. This provides better GPU utilization and throughput for models with 500M+ parameters. See vLLM Embedder for details.
Generate embeddings with VLLMEmbeddingModelStage using the vLLM Embedder pipeline, then pass the output to SemanticDeduplicationWorkflow:
When choosing a model:
- Use models that support vLLM pooling (embedding) mode
- Choose models appropriate for your language or domain
- Prefer models trained for sentence embeddings (for example, EmbeddingGemma, E5, BGE, or SBERT)
- Use
embedding_pretokenize=Truefor models that benefit from explicit tokenization control - Pass additional vLLM configuration through
embedding_vllm_init_kwargs - For more control over the embedding process, consider using VLLMEmbeddingModelStage separately
Advanced Configuration
Output Format
The semantic deduplication process produces the following directory structure in your configured cache_path:
File Formats
The workflow produces these output files:
-
Document Embeddings (
embeddings/*.parquet):- Contains document IDs and their vector embeddings
- Format: Parquet files with columns:
[id_column, embedding_column]
-
Cluster Assignments (
semantic_dedup/kmeans_results/):embs_by_nearest_center/: Parquet files containing cluster members- Format: Parquet files with columns:
[id_column, embedding_column, cluster_id]
A direct
KMeansStage(cache_path="kmeans_cache/")additionally writes the fitted cluster centers tokmeans_cache/kmeans_centroids.npy. The workflow wrappers do not save this file. -
Duplicate IDs (
output_path/duplicates/*.parquet):-
IDs of documents identified as duplicates for removal
-
Format: Parquet file with columns:
["id"] -
Important: Contains only the IDs of documents to remove, not the full document content
-
When
perform_removal=True, clean dataset is saved tooutput_path/deduplicated/
-
Performance Considerations
Performance characteristics:
- Computationally intensive, especially for large datasets
- GPU acceleration required for embedding generation and clustering
- Benefits often outweigh upfront cost (reduced training time, improved model performance)
GPU requirements:
- NVIDIA GPU with CUDA support
- Sufficient GPU memory (recommended: >8GB for medium datasets)
- RAPIDS libraries (cuDF) for GPU-accelerated dataframe operations
- CPU-only processing not supported
Performance tuning:
- Adjust
n_clustersbased on dataset size and available resources - Use batched cosine similarity to reduce memory requirements
- Consider distributed processing for very large datasets
For more details, see the SemDeDup paper by Abbas et al.
Advanced Configuration
ID Generator for large-scale operations:
Critical requirements:
- Use the same input configuration (file paths, partitioning) across all stages
- ID consistency maintained by hashing filenames in each task
- Mismatched partitioning causes ID lookup failures
Ray backend configuration:
Provides distributed processing, memory management, and fault tolerance.