重要提示

您正在查看 NeMo 2.0 文档。此版本引入了 API 的重大更改和一个新的库,NeMo Run。我们目前正在将 NeMo 1.0 中的所有功能移植到 2.0。有关先前版本或 2.0 中尚不可用的功能的文档,请参阅 NeMo 24.07 文档

语义去重#

背景#

语义去重是一种先进的技术,通过识别和消除语义相似的数据点,从大型数据集中删除冗余数据。与侧重于文本相似性的精确或模糊去重不同,语义去重利用内容的语义含义来识别重复项。

正如 Abbas 等人在论文 SemDeDup:通过语义去重实现网络规模的数据高效学习 中概述的那样,这种方法可以显著减小数据集大小,同时保持甚至提高模型性能。

语义去重对于大型、未经整理的网络规模数据集尤其有效,它可以删除高达 50% 的数据,而性能损失极小。

NeMo Curator 中的语义去重模块使用嵌入来识别和删除“语义重复项”——语义相似但不完全相同的数据对。虽然本文档主要侧重于基于文本的去重,但基本原理可以扩展到具有适当嵌入模型的其他模态。

工作原理#

SemDeDup 算法包括以下主要步骤

  1. 嵌入生成:每个数据点都使用预训练模型进行嵌入。

  2. 聚类:使用 k-means 聚类将嵌入聚类为 k 个簇。

  3. 相似度计算:在每个簇内,计算成对余弦相似度。

  4. 重复项识别:余弦相似度高于阈值的数据对被视为语义重复项。

  5. 重复项删除:从簇内每组语义重复项中,保留一个代表性数据点(通常是与簇质心余弦相似度最低的数据点),其余数据点将被删除。

配置语义去重#

NeMo Curator 中的语义去重可以使用 YAML 文件进行配置。这是一个示例 sem_dedup_config.yaml

# Configuration file for semantic dedup
cache_dir: "semdedup_cache"
num_files: -1

# Embeddings configuration
embeddings_save_loc: "embeddings"
embedding_model_name_or_path: "sentence-transformers/all-MiniLM-L6-v2"
embedding_batch_size: 128
write_embeddings_to_disk: true

# Clustering configuration
clustering_save_loc: "clustering_results"
n_clusters: 1000
seed: 1234
max_iter: 100
kmeans_with_cos_dist: false

# Semdedup configuration
which_to_keep: "hard"
largest_cluster_size_to_process: 100000
sim_metric: "cosine"

# Extract dedup configuration
eps_thresholds:
  - 0.01
  - 0.001

# Which threshold to use for extracting deduped data
eps_to_extract: 0.01

您可以自定义此配置文件以满足您的特定需求和数据集特征。

更改嵌入模型#

语义去重模块的关键优势之一是其在使用不同预训练模型进行嵌入生成方面的灵活性。您可以通过修改配置文件中的 embedding_model_name_or_path 参数轻松更改嵌入模型。

例如,要使用不同的句子转换器模型,您可以更改

embedding_model_name_or_path: "sentence-transformers/all-MiniLM-L6-v2"

embedding_model_name_or_path: "facebook/opt-125m"

该模块支持多种类型的模型,包括

  1. 句子转换器:非常适合基于文本的语义相似性任务。

  2. 自定义模型:您可以通过指定模型的路径来使用您自己的预训练模型。

更改模型时,请确保

  1. 该模型与您正在处理的数据类型(此模块主要为文本)兼容。

  2. 根据需要调整 embedding_batch_size 参数,因为不同的模型可能有不同的内存要求。

  3. 所选模型适合您数据集的语言或领域。

通过选择合适的嵌入模型,您可以优化语义去重过程以满足您的特定用例,并可能提高去重数据集的质量。

去重阈值#

语义去重过程由两个关键阈值参数控制

eps_thresholds:
  - 0.01
  - 0.001

eps_to_extract: 0.01
  1. eps_thresholds:用于计算语义匹配的相似度阈值列表。每个阈值代表确定重复项时的不同严格程度。

    值越低越严格,要求文档具有更高的相似度才被视为重复项。

  2. eps_to_extract:用于最终提取去重数据的特定阈值。

    此值必须是 eps_thresholds 中列出的阈值之一。

这种两步方法具有以下几个优点

  • 可以在多个阈值下计算匹配项的灵活性,而无需重新运行整个过程。

  • 能够分析不同阈值对数据集的影响。

  • 可以根据特定需求微调最终阈值,而无需重新计算所有匹配项。

在选择合适的阈值时

  • 较低的阈值(例如,0.001):更严格,导致更少的去重,但对识别出的重复项有更高的置信度。

  • 较高的阈值(例如,0.1):不太严格,导致更激进的去重,但可能会删除仅在某种程度上相似的文档。

我们建议您尝试不同的阈值,以找到数据缩减与保持数据集多样性和质量之间的最佳平衡。这些阈值的影响可能因数据集的性质和大小而异。

请记住,如果您想使用 eps_thresholds 中未包含的阈值提取数据,则需要重新计算语义匹配,并将新阈值包含在列表中。

用法#

在运行语义去重之前,请确保数据集中的每个文档/数据点都有唯一的标识符。如果需要,您可以使用 NeMo Curator 中的 add_id 模块

from nemo_curator import AddId
from nemo_curator.datasets import DocumentDataset

add_id = AddId(id_field="doc_id")
dataset = DocumentDataset.read_json("input_file_path", add_filename=True)
id_dataset = add_id(dataset)
id_dataset.to_json("output_file_path", write_to_filename=True)

要执行语义去重,您可以使用单个组件或带有配置文件的 SemDedup 类。

使用单个组件#

  1. 嵌入创建

from nemo_curator import EmbeddingCreator

# Step 1: Embedding Creation
embedding_creator = EmbeddingCreator(
    embedding_model_name_or_path="path/to/pretrained/model",
    embedding_batch_size=128,
    embedding_output_dir="path/to/output/embeddings",
    input_column="text",
    logger="path/to/log/dir",
)
embeddings_dataset = embedding_creator(dataset)
  1. 聚类

from nemo_curator import ClusteringModel

# Step 2: Clustering
clustering_model = ClusteringModel(
    id_column="doc_id",
    max_iter=100,
    n_clusters=50000,
    clustering_output_dir="path/to/output/clusters",
    logger="path/to/log/dir"
)
clustered_dataset = clustering_model(embeddings_dataset)
  1. 语义去重

from nemo_curator import SemanticClusterLevelDedup

# Step 3: Semantic Deduplication
semantic_dedup = SemanticClusterLevelDedup(
    n_clusters=50000,
    emb_by_clust_dir="path/to/embeddings/by/cluster",
    sorted_clusters_dir="path/to/sorted/clusters",
    id_column="doc_id",
    id_column_type="str",
    which_to_keep="hard",
    output_dir="path/to/output/deduped",
    logger="path/to/log/dir"
)
semantic_dedup.compute_semantic_match_dfs()
deduplicated_dataset_ids = semantic_dedup.extract_dedup_data(eps_to_extract=0.07)

使用 SemDedup 类#

或者,您可以使用 SemDedup 类执行所有步骤

from nemo_curator import SemDedup, SemDedupConfig
import yaml

# Load configuration from YAML file
with open("sem_dedup_config.yaml", "r") as config_file:
    config_dict = yaml.safe_load(config_file)

# Create SemDedupConfig object
config = SemDedupConfig(**config_dict)

# Initialize SemDedup with the configuration
sem_dedup = SemDedup(
    config=config,
    input_column="text",
    id_column="doc_id",
    id_column_type="str",
    logger="path/to/log/dir",
)

# Perform semantic deduplication
deduplicated_dataset_ids = sem_dedup(dataset)

这种方法允许轻松尝试不同的配置和模型,而无需更改核心代码。

参数#

配置文件中的关键参数包括

  • embedding_model_name_or_path:用于嵌入生成的预训练模型的路径或标识符。

  • embedding_batch_size:每个嵌入批次中要处理的样本数。

  • n_clusters:k-means 聚类的簇数。

  • eps_to_extract:去重阈值。值越高,去重越激进。

  • which_to_keep:用于选择要保留哪个重复项的策略(“hard”或“soft”)。

输出#

语义去重过程生成去重数据集,通常将数据集大小减少 20-50%,同时保持或提高模型性能。输出包括

  1. 每个数据点的嵌入。

  2. 每个数据点的簇分配。

  3. 语义重复项列表。

  4. 最终去重数据集。

性能注意事项#

语义去重是计算密集型的,尤其是对于大型数据集。但是,在减少训练时间和提高模型性能方面的优势通常超过了前期成本。请考虑以下事项

  • 使用 GPU 加速以加快嵌入生成和聚类。

  • 根据数据集大小和可用的计算资源调整簇数 (n_clusters)。

  • eps_to_extract 参数允许您控制数据集大小缩减与潜在信息丢失之间的权衡。

有关该算法及其性能影响的更多详细信息,请参阅原始论文:Abbas 等人的 SemDeDup:通过语义去重实现网络规模的数据高效学习