Hugging Face Datasets文本质量分析,识别低质量内容、垃圾数据、偏见内容、识别毒性内容、检测重复文档、识别测试集污染数据、识别过短的内容

发布时间:2024年01月09日

Hugging Face Datasets文本质量分析,识别低质量内容、垃圾数据、偏见内容、识别毒性内容、检测重复文档、识别测试集污染数据、识别过短的内容。

在这里插入图片描述

在这里插入图片描述

在机器学习和自然语言处理的世界中,数据的质量至关重要。Hugging Face提供了大量的文本数据集,但是如何评估这些数据集的质量呢?这篇文章将介绍如何使用Xorbits DataFrame和Streamlit对Hugging Face上的文本数据集进行质量分析。

数据集质量的重要性
数据集的质量直接影响到模型的性能,尤其对于最近很火的大模型的预训练来讲,如果数据集中存在大量的垃圾数据、重复数据、污染数据或者偏见内容,将会影响模型的性能。

因为预训练LLM的数据集很大比例来自于互联网,通过收集并清理来自互联网上的海量文本,可以增加训练数据集的大小。但直接使用互联网上爬到的数据会带来很多新的挑战,因为其中很多文本是低质量机器生成的spam或色情内容。而且这些从Web上抓取到的文本,会出现大量重复的内容。比如,在C4数据集中,有一个50个词的句子重复出现了6万次。因此,当我们想要使用Hugging Face上的数据集来预训练LLM时,有必要对数据集的质量进行一定程度的分析。

HuggingFace-Datasets-Text-Quality-Analysis这个项目的目标就是让人们评估Hugging Face上文本类型数据集的质量。这个工具可以从Hugging Face获取parquet文件,然后识别出数据集中的垃圾数据、重复数据、污染数据、偏见内容等质量问题。

在这里插入图片描述

如何使用?
首先,你可以通过以下命令创建一个新的conda环境,并激活它:

$ conda create -n datasets-quality python=3.9 
$ conda activate datasets-quality

接下来,进入HuggingFace-Datasets-Text-Quality-Analysis目录,安装依赖:

$ cd HuggingFace-Datasets-Text-Quality-Analysis 
$ pip install -r requirements.txt 

最后,运行Streamlit应用:

python -m streamlit run app.py 

注意事项
如果你从Hugging Face下载的数据集太大,运行应用可能会超出你的机器的内存,导致一些错误。你可以对数据进行了一些采样,并且使用 Xorbits 有效利用你电脑上的多个CPU核心:

https://github.com/xorbitsai/xorbits
?
Xorbits是一个开源数据处理和AI加速框架,它能够加速机器学习的各个环节,从数据预处理,到模型训练和推理。Xorbits 利用多核和 GPU 来加速计算,支持单机加速,也可以轻松扩展到成千台机器。

识别低质量内容
很多网页包含的都是自动生成的内容,或者是为了搜索引擎优化而写的关键字,没有太多的实质性内容。网上也有很多社交媒体的内容,可能缺乏上下文、连贯性或实质性。

所以在这一步中,需要过滤那些低质量的文档,然后从训练集中去除它们,通常有两种方法来过滤这些低质量的内容:一种是基于规则的方法,另一种是基于分类器的方法。使用规则来过滤低质量内容的好处是,它不会引入偏见。如果维基百科或Reddit数据来训练分类器来,从而过滤低质量的文档,可能会无意中偏向某类人群,或忽略掉某些方言或社会语言形式的表达。

例如下面这段Python代码使用正则表达式匹配那些出现“可疑”字符超过一定比例的文本:

import re
RE_SUSPICIOUS = re.compile(r'[\u0026# \u003e{}\\[\\]\\\\]')
def impurity(text, min_len=10):
    """returns the share of suspicious characters in a text"""
    if text == None or len(text) < min_len:
        return 0
    else:
        return len(RE_SUSPICIOUS.findall(text))/len(text)
df['impurity'] = df['text'].apply(impurity, min_len=10)
total_num_docs = len(df)
impurity_num_docs = len(df[df['impurity'] > 0.01])
impurity_ratio = impurity_num_docs / total_num_docs

识别毒性内容
络信息内容多样,但其中也混有不少有毒和偏见的内容。Toxicity一般指网络环境中存在的有害或恶意行为,比如网络欺凌、恶意攻击、仇恨言论等。RealToxicityPrompts通过一个叫做Perspective AI的工具对内容的毒性进行评测,根据他们的报告,OpenWebText的内容中有2.1%,WebText的内容中有4.3%,这些内容的毒性评分达到或超过50%。

The Pile使用了一个叫Spam Scanner的工具对有害内容进行分类。Spam Scanner是一款用于限制垃圾邮件,防止网络钓鱼和对用户的攻击的API工具,它内置了一个毒性检测的分类器;在tfjs-models中,也包含了一个检测毒性内容的分类器。

还有一种简单的方法,就是通过"坏词"来对文本进行滤,比如,C4的作者就过滤掉了这个列表中的文本。可以参考下面这段Python代码:

with open('./List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words', 'r') as f:
    lines = f.readlines()
    banned_words = [line.rstrip('\n') for line in lines]
    df['banned_words_in_text'] = df['text'].apply(lambda text: [word for word in banned_words if word in text.lower().split()]) 
    total_num_docs = len(df)
    df['matches'] = df['banned_words_in_text'].apply(lambda words: len(words) > 0)
    biased_num_docs = df['matches'].sum()
    biased_content_ratio = biased_num_docs / total_num_docs 

检测重复文档
当通过从互联网抓取原始文本来创建数据集时,这通常会导致同样的序列被重复多次。这篇论文提到,在C4数据集中,有一个50个词的序列被重复了60,000次。去重有助于防止模型在存在许多重复时输出逐字的训练数据,并使模型对隐私攻击的抵抗力更强。去重还可以提高模型训练的效率,防止基准测试的污染。

最小哈希(MinHash)提供了一种相较于直接计算集合交并集更快、更易扩展的方式来估计两个集合的相似度。简单来说,我们对集合中的每个元素使用一系列哈希函数,并记录每个哈希函数的最小哈希值。之后,我们可以通过比较这些最小哈希值来估计两个集合的相似度。如果两个集合非常相似,那么他们的最小哈希值也将十分接近。相反,如果两个集合完全不同,那么他们的最小哈希值也会相差很远。考虑到概率算法可能存在误报的情况,我们在找到相似文档后,可以使用Jaccard相似度再次进行检验。但Falcon提到,如果数据集足够大,这个误伤完全可以接受,因此这个步骤可以省略。

由于比较每一对可能的文档之间的MinHash签名在计算上非常消耗资源,计算量和数据量的平方成正比。局部敏感哈希(LSH)就是一种在大型数据集中查找相似项的方法。如果你想象自己在一个大果园里寻找相似的苹果,每个苹果都有各自的特点,比如颜色、大小、形状等。你可以拿起一个苹果,然后和园里的每一个苹果进行一一比较,这样非常耗时。但如果像LSH那样,我们把果园分成多个小区,每个区里的苹果都有相似的特征。这样你就不需要和果园里的每个苹果比较,只需要看那个和你手中的苹果在同一区域的苹果,这就大大提高了搜索速度。

datasketch是一个提供了多种概率数据结构的Python包,其中包括MinHash和HyperLogLog等,它们能在一定程度的精度损失下,快速处理和查询大量数据。虽然LSH在算法层面优化了复杂度,但是考虑到网络数据集的庞大,对它们进行多个哈希函数的计算依然需要消耗大量的计算存储资源,因此大部分论文都推荐采用分布式计算的方案,例如GPT-3采用了Spark的MinHashLSH方法。

以下代码使用datasketch库和LSH(局部敏感哈希)对数据集进行去重。对于DataFrame中的每个文本,它创建一个查询MinHash对象,并在LSH索引上执行查询以找到相似的文档:

from datasketch import MinHashLSH, MinHash

df = train_dataset

lsh = MinHashLSH(threshold=0.85, num_perm=128)

for i, text in enumerate(df['text']):
    minhash = MinHash(num_perm=128)
    for word in text.split():
        minhash.update(word.encode('utf-8'))
    lsh.insert(str(i), minhash)

unique_documents = set()

for i, text in enumerate(df['text']):
    query_minhash = MinHash(num_perm=128)
    for word in text.split():
        query_minhash.update(word.encode('utf-8'))
    results = lsh.query(query_minhash)
    unique_documents.add(results[0])

total_unique_documents = len(unique_documents)
total_documents = len(df)
duplication_ratio = (total_documents - total_unique_documents) / total_documents
duplication_ratio

识别测试集污染数据
在机器学习中,确保训练数据和测试数据的隔离通常是相当直接的。然而,在大型语言模型的背景下,当训练和基准测试数据集都从互联网收集时,事情变得复杂了。

例如,如果基准测试数据(如问题-答案对)也在模型的训练集中,那么使用基准测试数据评估大型语言模型的性能可能会受到显著影响。从训练数据集中消除与现有基准测试数据集交叉的实例的过程被称为"去污染"(decontamination)。

OpenAI定义了一个测试文档,如果它与任何训练文档存在任何N-gram的重叠,那么它就被认为是被污染的。(他们根据数据集使用了在8到13之间的一系列N值。)在构建WebText数据集时,OpenAI的研究人员通过从训练集中消除所有的维基百科内容来去污染数据。这是必要的,因为维基百科的数据在他们的基准测试数据集中被大量使用。

下面的Python代码被用来量化数据集中的污染问题,即测试集中也出现在训练集中的文档的比例,使用N-gram和MinMashLSH进行计算。

from nltk import ngrams

from datasketch import MinHash, MinHashLSH

def process_data(df):
    minhashes = {}
    for idx, text in enumerate(df['text']):
        minhash = MinHash(num_perm=128)
        for d in ngrams(text, 13):
            s = "".join(d).encode('utf-8')
            minhash.update(s)
        minhashes[idx] = minhash
    return minhashes

train_minhashes = process_data(train_dataset)
test_minhashes = process_data(test_dataset)

lsh = MinHashLSH(threshold=0.8, num_perm=128)

for idx, minhash in train_minhashes.items():
    lsh.insert(idx, minhash)

duplicates_count = 0
for idx, minhash in test_minhashes.items():
    result = lsh.query(minhash)
    if len(result) > 0:
        duplicates_count += 1

contamination_ratio = duplicates_count / len(test_dataset)
contamination_ratio

识别过短的内容
语言建模的目标是根据前面的词元掌握生成文本的能力。在这种情况下,从语料库中识别并且删除极短的文档可能有助于减少噪声,通过生成连续的文本来模拟文本内的依赖关系。

我们使用Hugging Face Transformers库对文本进行tokenize,然后计算数据集中"过短"的文档的比例。这个例子将文本转换为BERT模型可以理解的token。

from transformers import BertTokenizer

tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')

df = train_dataset
# Create a new column with the number of tokens for each text
df['text_length'] = df['text'].apply(lambda text: len(tokenizer.tokenize(text)))
total_num_docs = len(df)
too_short_docs = len(df[df['text_length'] < 100])
too_short_doc_ratio = too_short_docs / total_num_docs
too_short_doc_ratio
文章来源:https://blog.csdn.net/u014374009/article/details/135473016
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。