This page is for version 26.09 · v1.4.0.
For other versions, use one of these documentation indexes:
- Latest · v1.4.0 (26.09) (default): https://docs.nvidia.com/nemo/curator/latest/llms.txt
- Main · preview: https://docs.nvidia.com/nemo/curator/main/llms.txt
- 26.09 · v1.4.0: https://docs.nvidia.com/nemo/curator/v26.09/llms.txt
- 26.07 · v1.3.0: https://docs.nvidia.com/nemo/curator/v26.07/llms.txt
- 26.04 · v1.2.0: https://docs.nvidia.com/nemo/curator/v26.04/llms.txt
- 26.02 · v1.1.0: https://docs.nvidia.com/nemo/curator/v26.02/llms.txt
- 25.09 · v1.0.0: https://docs.nvidia.com/nemo/curator/v25.09/llms.txt
Create custom data loading pipelines using Curator. This guide shows how to build modular stages that run on Curator’s distributed processing.
How It Works
Curator uses the same 3-step pipeline pattern described in Data Acquisition Concepts for custom data loading. Each step maps to one or more abstract base classes with corresponding processing stages that compose into pipelines.
Architecture Overview
For detailed information about the core components and data flow, see Data Acquisition Concepts and Data Loading Concepts.
Implementation Guide
1. Create Directory Structure
your_data_source/├── __init__.py├── stage.py # Main composite stage├── url_generation.py # URL generation logic├── download.py # Download implementation├── iterator.py # File iteration logic└── extract.py # Data extraction logic (optional)
2. Build Core Components
URL Generator (url_generation.py)
from dataclasses import dataclassfrom nemo_curator.stages.text.download import URLGenerator@dataclassclass CustomURLGenerator(URLGenerator):def generate_urls(self) -> list[str]:"""Generate list of URLs to download."""# Your URL generation logic herereturn ["https://example.com/dataset1.zip","https://example.com/dataset2.zip",]
Document Downloader (download.py)
from nemo_curator.stages.text.download import DocumentDownloaderclass CustomDownloader(DocumentDownloader):def __init__(self, download_dir: str):super().__init__(download_dir=download_dir)def _get_output_filename(self, url: str) -> str:"""Extract filename from URL."""return url.split("/")[-1]def _download_to_path(self, url: str, path: str) -> tuple[bool, str | None]:"""Download file from URL to local path."""# Custom download logic# Return (success_bool, error_message)try:# ... download implementation ...return True, Noneexcept Exception as e:return False, str(e)
Document Iterator (iterator.py)
import jsonfrom collections.abc import Iteratorfrom typing import Anyfrom nemo_curator.stages.text.download import DocumentIteratorclass CustomIterator(DocumentIterator):def __init__(self, log_frequency: int = 1000):super().__init__()self._log_frequency = log_frequencydef iterate(self, file_path: str) -> Iterator[dict[str, Any]]:"""Iterate over records in a file."""# Custom iteration logic to load local file and return documentsfor record in load_local_file_fn(file_path):yield {"content": record_content, "metadata": record_metadata, "id": record_id}def output_columns(self) -> list[str]:"""Define output columns."""return ["content", "metadata", "id"]
Document Extractor (extract.py)
from typing import Anyfrom nemo_curator.stages.text.download import DocumentExtractorclass CustomExtractor(DocumentExtractor):def __init__(self):super().__init__()def extract(self, record: dict[str, str]) -> dict[str, Any] | None:"""Transform raw record to final format."""# Skip invalid recordsif not record.get("content"):return None# Extract and clean textcleaned_text = self._clean_text(record["content"])# Generate unique ID if not presentdoc_id = record.get("id", self._generate_id(cleaned_text))return {"text": cleaned_text,"id": doc_id,"source": record.get("metadata", {}).get("source", "unknown")}def input_columns(self) -> list[str]:return ["content", "metadata", "id"]def output_columns(self) -> list[str]:return ["text", "id", "source"]def _clean_text(self, text: str) -> str:"""Clean and normalize text."""# Your text cleaning logic herereturn text.strip()def _generate_id(self, text: str) -> str:"""Generate unique ID for text."""import hashlibreturn hashlib.md5(text.encode()).hexdigest()[:16]
3. Create Composite Stage (stage.py)
from nemo_curator.stages.text.download import DocumentDownloadExtractStagefrom nemo_curator.stages.base import ProcessingStagefrom .url_generation import CustomURLGeneratorfrom .download import CustomDownloaderfrom .iterator import CustomIteratorfrom .extract import CustomExtractorclass CustomDataStage(DocumentDownloadExtractStage):"""Custom data loading stage combining all components."""def __init__(self,download_dir: str = "./custom_downloads",url_limit: int | None = None,record_limit: int | None = None,add_filename_column: bool | str = True,):self.url_generator = CustomURLGenerator()self.downloader = CustomDownloader(download_dir=download_dir)self.iterator = CustomIterator()self.extractor = CustomExtractor()# Initialize the parent composite stagesuper().__init__(url_generator=self.url_generator,downloader=self.downloader,iterator=self.iterator,extractor=self.extractor, # Optional - remove if not neededurl_limit=url_limit,record_limit=record_limit,add_filename_column=add_filename_column,)self.name = "custom_data"def decompose(self) -> list[ProcessingStage]:"""Decompose this composite stage into its constituent stages."""return self.stagesdef get_description(self) -> str:"""Get a description of this composite stage."""return "Custom data"
Usage Examples
Basic Pipeline
from nemo_curator.core.client import RayClientfrom nemo_curator.pipeline import Pipelinefrom your_data_source.stage import CustomDataStagefrom nemo_curator.stages.text.io.writer.jsonl import JsonlWriterdef main():# Initialize Ray clientray_client = RayClient()ray_client.start()# Create pipelinepipeline = Pipeline(name="custom_data_pipeline",description="Load and process custom dataset")# Create custom data loading stagedata_stage = CustomDataStage(...)pipeline.add_stage(data_stage)# Save the results to JSONLpipeline.add_stage(JsonlWriter(...))# Run pipelineprint("Starting pipeline...")results = pipeline.run()# Stop Ray clientray_client.stop()if __name__ == "__main__":main()
For executor options and configuration, refer to Execution Backends.
Parameters Reference
| Parameter | Type | Description | Default |
|---|---|---|---|
url_generator | URLGenerator | Custom URL generation implementation | Required |
downloader | DocumentDownloader | Custom download implementation | Required |
iterator | DocumentIterator | Custom file iteration implementation | Required |
extractor | DocumentExtractor | None | Optional extraction/transformation step | None |
url_limit | int | None | Maximum number of URLs to process | None |
record_limit | int | None | Maximum records per file | None |
add_filename_column | bool | str | Add filename column to output; if str, uses it as the column name (default name: “file_name”) | True |
Output Format
Processed data flows through the pipeline as DocumentBatch tasks containing Pandas DataFrames or PyArrow Tables:
Example Output Schema
{"text": "This is the processed document text","id": "unique-document-id","source": "example.com","file_name": "dataset1.jsonl" # If add_filename_column=True (default column name)}