节前,我们组织了一场算法岗技术&面试讨论会,邀请了一些互联网大厂朋友、参加社招和校招面试的同学,针对大模型技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何备战、面试常考点分享等热门话题进行了深入的讨论。
合集在这里:《大模型面试宝典》(2024版) 正式发布!
大语言模型的相关研究表明,数据质量对于模型的影响非常大。因此在收集到各类型数据之后,需要对数据进行处理,去除低质量数据、重复数据、有害信息、个人隐私等内容。
典型的数据处理过程如下图所示,主要包含质量过滤、冗余去除、隐私消除、词元切分这四个步骤。喜欢本文记得收藏、点赞、关注。
技术交流群
前沿技术资讯、算法交流、求职内推、算法竞赛、面试交流(校招、社招、实习)等、与 10000+来自港科大、北大、清华、中科院、CMU、腾讯、百度等名校名企开发者互动交流~
我们建了算法岗技术与面试交流群, 想要进交流群、需要源码&资料、提升技术的同学,可以直接加微信号:mlc2040。加的时候备注一下:研究方向 +学校/公司+CSDN,即可。然后就可以拉你进群了。
方式①、微信搜索公众号:机器学习社区,后台回复:加群
方式②、添加微信号:mlc2040,备注:技术交流
用通俗易懂方式讲解系列
- 《大模型面试宝典》(2024版) 正式发布!
- 《大模型实战宝典》(2024版)正式发布!
- 大模型面试准备(一):LLM主流结构和训练目标、构建流程
- 大模型面试准备(二):LLM容易被忽略的Tokenizer与Embedding
- 大模型面试准备(三):聊一聊大模型的幻觉问题
- 大模型面试准备(四):大模型面试必会的位置编码
- 大模型面试准备(五):图解 Transformer 最关键模块 MHA
- 大模型面试准备(六):一文讲透生成式预训练模型 GPT、GPT2、GPT3
- 大模型面试准备(七):ChatGPT 的内核 InstructGPT 详细解读
- 大模型面试准备(八):一文详解国产大模型导师 LLaMA v1和v2
- 大模型面试准备(九):简单透彻理解MoE
下面按算法难易和重要程度(词元切分 > 冗余去除 > 质量过滤 > 隐私消除)分别为大家讲解。
词元切分
传统的自然语言处理通常以单词为基本处理单元,模型都依赖预先确定的词表 V,在编码输入词序列时,这些词表示模型只能处理词表中存在的词。因此,在使用中,如果遇到不在词表中的未登录词,模型无法为其生成对应的表示,只能给予这些未登录词(Out-of-vocabulary,OOV) 一个默认的通用表示。
在深度学习模型中,词表示模型会预先在词表中加入一个默认的“[UNK]”(unknown)标识,表示未知词,并在训练的过程中将 [UNK] 的向量作为词表示矩阵的一部分一起训练,通过 引入某些相应机制来更新 [UNK] 向量的参数。
在使用时,对于全部的未登录词,都使用 [UNK] 的向量作为这些词的表示向量。
此外,基于固定词表的词表示模型对词表大小的选择比较敏感。当词表大小过小时,未登录词的比例较高,影响模型性能。而当词表大小过大时,大量低频词出现在词表中,而这些词的词向量很难得到充分学习。
理想模式下,词表示模型应能覆盖绝大部分的输入词,并避免词表过大所造成的数据稀疏问题。
为了缓解未登录词问题,一些工作通过利用亚词级别的信息构造词表示向量。一种直接的解决思路是为输入建立字符级别表示,并通过字符向量的组合来获得每个单词的表示,以解决数据稀疏问题。然而,单词中的词根、词缀等构词模式往往跨越多个字符,基于字符表示的方法很难学习跨度较大的模式。为了充分学习这些构词模式,研究人员们提出了子词词元化(Subword Tokenization)方法,试图缓解上文介绍的未登录词问题。
词元表示模型会维护一个词元词表,其中既存在完整的单词,也存在形如“c”, “re”, “ing”等单词部分信息,称为子词。
词元表示模型对词表中的每个词元计算一个定长向量表示,供下游模型使用。对于输入的词序列,词元表示模型将每个词拆分为词表内的词元。例如,将单词“reborn”拆分为“re”和“born”。
模型随后查询每个词元的表示,将输入重新组成为词元表示序列。当下游模型需要计算一个单词或词组的表示时,可以将对应范围内的词元表示合成为需要的表示。因此,词元表示模型能够较好地解决自然语言处理系统中未登录词的问题。词元分析(Tokenization)目标是将原始文本分割成由词元(Token)序列的过程。词元切分也是数据预处理中至关重要的一步。
BPE 分词
字节对编码(Byte Pair Encoding,BPE)[7]模型是一种常见的子词词元模型。该模型所采用的词表包含最常见的单词以及高频出现的子词。在使用中,常见词通常本身位于 BPE 词表中,而罕见词通常能被分解为若干个包含在 BPE 词表中的词元,从而大幅度降低未登录词的比例。BPE 算法包括两个部分:(1)词元词表的确定;(2)全词切分为词元;(3)获得词元表示序列。计算过程下图所示。
词元词表的确定
首先,确定语料库中全词的词表和词频,然后将每个单词切分为单个字符的序列,并在序列最后添加符号“”作为单词结尾的标识。比如单词“low”被切分为序列“l␣o␣w␣”。
所切分出的序列元素称为字节,即每个单词都切分为字节的序列。之后,按照每个字节序列的相邻字节对和单词的词频,统计每个相邻字节对的出现频率,合并出现频率最高的字节对,将其作为新的词元加入词表,并将全部单词中的该字节对合并为新的单一字节。
如上图所示,在第一次迭代时,出现频率最高的字节对是 (e,s),故将“es”作为词元加入词表,并将全部序列中相邻的 (e,s)字节对合并为 es 字节。重复这一步骤,直至 BPE 词元词表的大小达到指定的预设值,或没有可合并的字节对为止。
全词切分为词元
在词元词表确定之后,对于输入词序列中未在词表中的全词进行切分,BPE 算法对词表中的词元按从长到短的顺序进行遍历,用每一个词元和当前序列中的全词或未完全切分为词元的部分进行匹配,将其切分为该词元和剩余部分的序列。
例如,对于单词“lowest”,首先通过匹配词元“est”将其切分为“low”, “est”的序列,再通过匹配词元“low”,确定其最终切分结果为“low”, “est”的序列。通过这样的过程,BPE 尽量将词序列中的词切分成已知的词元。
获得词元表示序列
在遍历词元词表后,对于切分得到的词元序列,为每个词元查询词元表示,构成词元表示序列。若出现未登录词元,即未出现在 BPE 词表中的词元,则采取和未登录词类似的方式,为其赋予相同的表示,最终获得输入的词元表示序列。
字节级(Byte-level)BPE
此外,字节级(Byte-level)BPE 通过将字节视为合并的基本符号,用来改善多语言语料库(例如包含非 ASCII 字符的文本)的分词质量。GPT-2、BART 和 LLaMA 等大语言模型都采用了这种分词方法。
原始 LLaMA 的词表大小是 32K,并且主要根据英文进行训练,因此,很多汉字都没有直接出现在词表中,需要字节来支持所有的中文字符,由 2 个或者 3 个 Byte Token 才能拼成一个完整的汉字。
BPE 输出
对于使用了字节对编码的大语言模型,其输出序列也是词元序列。对于原始输出,根据终结符 的位置确定每个单词的范围,合并范围内的词元,将输出重新组合为词序列,作为最终的结果。
WordPiece 分词
WordPiece[8] 也是一种常见的词元分析算法,最初应用于语音搜索系统。此后,该算法做为 BERT 的分词器。
WordPiece 与 BPE 有非常相似的思想,都是通过迭代地合并连续的词元,但在合并的选择标准上略有不同。
为了进行合并,WordPiece 需要首先训练一个语言模型,并用该语言模型对所有可能的词元对进行评分。在每次合并时,选择使得训练数据似然概率增加最多的词元对。
由于 Google 并没有发布其 WordPiece 算法的官方实现,HuggingFace 在其在线 NLP 课程中提供了一种更直观的选择度量方法:一个词元对的评分是根据训练语料库中两个词元的共现计数除以它们各自的出现计数的乘积。计算公式如下所示:
Unigram 分词
Unigram 词元分析[9] 是另外一种应用于大语言模型的词元分析方法,T5 和 mBART 采用该方法构建词元分析器。不同于 BPE 和 WordPiece,Unigram 词元分析从一个足够大的可能词元集合开始,然后迭代地从当前列表中删除词元,直到达到预期的词汇表大小为止。
基于训练好的 Unigram 语言模型,使用从当前词汇表中删除某个字词后,训练语料库似然性的增加量作为选择标准。
为了估计一元语言(Unigram)模型,采用了**期望最大化(Expectation–Maximization,EM)**算法:每次迭代中,首先根据旧的语言模型找到当前最佳的单词切分方式,然后重新估计一元语言单元概率以更新语言模型。
在这个过程中,使用**动态规划算法(如维特比算法)**来高效地找到给定语言模型时单词的最佳分解方式。
冗余去除
文献 [3] 指出大语言模型训练语料库中的重复数据,会降低语言模型的多样性,并可能导致训练过程不稳定,从而影响模型性能。因此,需要对预训练语料库中的重复进行处理,去除其中的冗余部分,这对于改善语言模型的训练具有重要的作用。
文本冗余发现(Text Duplicate Detection)也称为文本重复检测,是自然语言处理和信息检索中的基础任务之一,其目标是发现不同粒度上的文本重复,包括句子、段落以及文档等不同级别。
冗余去除就是在不同的粒度上进行去除重复内容,包括句子、文档和数据集等粒度的重复。
句子级别
在句子级别上,文献 [4] 指出,包含重复单词或短语的句子很可能造成语言建模中引入重复的模式。这对语言模型来说会产生非常严重的影响,使得模型在预测时容易陷入重复循环(Repetition Loops)。
例如,使用 GPT-2 模型,对于给定的上下文:
In a shocking finding, scientist discovered a herd of unicorns living in a remote, previously unexplored valley, in the Andes Mountains. Even more surprising to the researchers was the fact that the unicorns spoke perfect English.
如果使用束搜索(Beam Search),在设置 b = 32 时,模型就会产生如下输出,进入了重复循环模式:
The study, published in the Proceedings of the National Academy of Sciences of the United States of America (PNAS), was conducted by researchers from the Universidad Nacional Autónoma de México (UNAM) and the Universidad Nacional Autónoma de México (UNAM/Universidad Nacional Autónoma de México/Universidad Nacional Autónoma de México/Universidad Nacional Autónoma de México/Universidad Nacional Autónoma de …
由于重复循环对于语言模型生成的文本质量有非常大的影响,因此在预训练语料中需要删除这些包含大量重复单词或者短语的句子。
RefinedWeb 构造过程中也进行了句子级别的过滤。使用了文献 [5] 所提出的过滤方法,提取并过滤文档间超过一定长度的相同字符串。
给定两个文档 和 ,其中存在长度为 的公共子串 。当 ⩾ 50 时,就将其中一个子串过滤。
公共子串匹配的关键是如何高效完成字符串匹配,文献 [64] 将整个文档 转换为一个超长的字符串序列 ,之后构造序列 的后缀数组(Suffix Array)。该数组包含在该序列中的所有后缀的按字典顺序排列的列表。
具体而言,后缀数组 是一个整数数组,其中每个元素表示 中的一个后缀的起始位置。按照字典顺序, 中的元素按照后缀的字典顺序排列。
例如,序列“banana”的后缀包括“banana”,“anana”,“nana”,“ana”,“na”和“a”,对应的后缀数组 为 [6, 4, 2, 1, 5, 3]。根据数组 ,可以很容易的找出相同的子串。如果,那么 和 在数组 中一定在紧邻的位置上。
文献 [5] 中设计了并行的后缀数组构造方法,针对 Wiki-40B 训练语料(约包含 4GB 文本内容),使用拥有 96 核 CPU 以及 768GB 内存的服务器,可以在 2.3 分钟内完成计算。对于包含 350GB 文本的 C4 数据集合,仅需要 12 小时可以完成后缀数组构造。
文档级别
在文档级别上,大部分大语言模型都是依靠文档之间的表面特征相似度(例如 重叠比例)进行检测并删除重复文档。
LLaMA 采用 CCNet 的处理模式,首先将文档拆分为段落,并把所有字符转换为小写字符、将数字替换为占位符,以及删除所有 Unicode 标点符号和重音符号来对每个段落进行规范化处理。然后,使用 SHA-1 方法为每个段落计算一个哈希码(Hash Code),并使用前 64 位数字作为键。最后,利用每个段落的键进行重复判断。
RefinedWeb 首先去除掉页面中菜单、标题、页脚、广告等内容,仅抽取页面中的主要内容。在此基础上,在文档级别进行过滤,采用与文献 [6] 类似的方法,使用 重叠程度来衡量句子、段落以及文档的相似度。如果重复程度超过预先设定的阈值,则会过滤掉重复段落或文档。
数据集层面
数据集层面也可能存在一定数量的重复情况,比如很多大语言模型预训练集合都会包含 GitHub、Wikipedia、C4 等数据集。还需要特别注意的是,预训练语料中混入测试语料,从而造成数据集污染的情况。
低质过滤
互联网上的数据质量参差不齐,无论是 OpenAI 联合创始人 Andrej Karpathy 在微软 Build 2023 的报告,还是当前的一些研究都表明,训练数据的质量对于大语言模型效果具有非常重要的影响。因此,如何**从收集到的数据中删除低质量数据成为大语言模型训练中的重要步骤。**大语言模型训练中所使用的低质量数据过滤方法可以大致分为两类:基于分类器的方法和基于启发式的方法。
基于分类器的方法
基于分类器的方法目标是训练文本质量判断模型,并利用该模型识别并过滤低质量数据。
GPT3、PALM 以及 GLam 模型在训练数据构造时都使用了基于分类器的方法。
文献 [1] 采用了基于特征哈希的线性分类器(Feature Hash Based Linear Classifier),可以非常高效地完成文本质量判断。该分类器使用一组精选文本(维基百科、书籍和一些选定的网站)进行训练,目标是将与训练数据类似的网页给定较高分数。利用这个分类器可以评估网页的内容质量。
在实际应用中,还可以通过使用 Pareto 分布对网页进行采样,根据其得分选择合适的阈值,从而选定合适的数据集合。
但是,一些研究也发现,基于分类器的方法可能会删除包含方言或者口语的高质量文本,从而损失一定的多样性。
基于启发式的方法
基于启发式的方法则**通过一组精心设计的规则来消除低质量文本,**BLOOM 和 Gopher 采用了基于启发式的方法。
这些启发式规则主要包括:
-
语言过滤: 如果一个大语言模型仅关注一种或者几种语言,那么就可以大幅度的过滤掉数据中其他语言的文本。
-
指标过滤: 利用评测指标也可以过滤低质量文本。例如,可以使用语言模型对于给定文本的困惑度(Perplexity)进行计算,利用该值可以过滤掉非自然的句子。
-
统计特征过滤: 针对文本内容可以计算包括标点符号分布、符号字比(Symbol-to-Word Ratio)、句子长度等等在内的统计特征,利用这些特征过滤低质量数据。
-
关键词过滤: 根据特定的关键词集,可以识别和删除文本中的噪声或无用元素,例如,HTML 标签、超链接以及冒犯性词语等。
在大语言模型出现之前,在自然语言处理领域已经开展了很多文章质量判断(Text Quality Evaluation)相关研究,主要应用于搜索引擎、社会媒体、推荐系统、广告排序以及作文评分等任务中。
在搜索和推荐系统中,结果的内容质量是影响用户体验的的重要因素之一,因此,此前很多工作都是针对**用户生成内容(User-Generated Content,UGC)**质量进行判断。
自动作文评分也是文章质量判断领域的一个重要子任务,自 1998 年文献 [2] 提出了使用贝叶斯分类器进行作文评分预测以来,基于 SVM、CNN-RNN、BERT 等方法的作文评分算法也相继提出,并取得了较大的进展。
这些方法也都可以应用于大语言模型预训练数据过滤中。但是由于预训练数据量非常大,并且对于质量判断的准确率并不要求非常高,因此一些基于深度学习以及基于预训练的方法还没有应用于低质过滤过滤中。
隐私消除
由于绝大多数预训练数据源于互联网,因此不可避免地会包含涉及敏感或个人信息(Personally Identifiable Information,PII)的用户生成内容,这可能会增加隐私泄露的风险。如下图所示,输入前缀词“East Stroudsburg Stroudsburg”,语言模型在此基础上补全了姓名、电子邮件地址、电话 号码、传真号码以及实际地址。这些信息都是模型从预训练语料中学习得到的。因此,有非常必要从预训练语料库中删除包含个人身份信息的内容。
删除隐私数据最直接的方法是采用基于规则的算法,BigScience ROOTS Corpus 构建过程中就是采用了基于命名实体识别的方法,利用命名实体识别算法检测姓名、地址和电话号码等个人信息内容并进行删除或者替换。该方法使用了基于 Transformer 的模型,并结合机器翻译技术,可以处理超过 100 种语言的文本,消除其中的隐私信息。该算法被集成在 muliwai 类库中。
BPE 作为 NLP 和 LLM 领域最重要的必会的分词方法,下面以 HuggingFace NLP 课程中介绍的 Byte Pair Encoding 代码为例,介绍 BPE 方法的构建和使用,代码实现如下所示,大家可以读一读、跑一跑感觉一下,相信会更有体会:
from transformers import AutoTokenizer
from collections import defaultdict
corpus = [
"This is the Hugging Face Course.",
"This chapter is about tokenization.",
"This section shows several tokenizer algorithms.",
"Hopefully, you will be able to understand how they are trained and generate tokens.",
]
# 使用 GPT-2 tokenizer 将输入分解为单词:
tokenizer = AutoTokenizer.from_pretrained("gpt2")
word_freqs = defaultdict(int)
for text in corpus:
words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text)
new_words = [word for word, offset in words_with_offsets]
for word in new_words:
word_freqs[word] += 1
# 计算基础词典, 这里使用语料库中的所有字符:
alphabet = []
for word in word_freqs.keys():
for letter in word:
if letter not in alphabet:
alphabet.append(letter)
alphabet.sort()
# 增加特殊 Token 在字典的开头,GPT-2 中仅有一个特殊 Token``<|endoftext|>''表示文本结束
vocab = ["<|endoftext|>"] + alphabet.copy()
# 将单词切分为字符
splits = {word: [c for c in word] for word in word_freqs.keys()}
#compute_pair_freqs 函数用于计算字典中所有词元对的频率
def compute_pair_freqs(splits):
pair_freqs = defaultdict(int)
for word, freq in word_freqs.items():
split = splits[word]
if len(split) == 1:
continue
for i in range(len(split) - 1):
pair = (split[i], split[i + 1])
pair_freqs[pair] += freq
return pair_freqs
#merge_pair 函数用于合并词元对
def merge_pair(a, b, splits):
for word in word_freqs:
split = splits[word]
if len(split) == 1:
continue
i = 0
while i < len(split) - 1:
if split[i] == a and split[i + 1] == b:
split = split[:i] + [a + b] + split[i + 2 :]
else:
i += 1
splits[word] = split
return splits
# 迭代训练,每次选取得分最高词元对进行合并,直到字典大小达到设置目标为止:
vocab_size = 50
while len(vocab) < vocab_size:
pair_freqs = compute_pair_freqs(splits)
best_pair = ""
max_freq = None
for pair, freq in pair_freqs.items():
if max_freq is None or max_freq < freq:
best_pair = pair
max_freq = freq
splits = merge_pair(*best_pair, splits)
merges[best_pair] = best_pair[0] + best_pair[1]
vocab.append(best_pair[0] + best_pair[1])
# 训练完成后,tokenize 函数用于给定文本进行词元切分
def tokenize(text):
pre_tokenize_result = tokenizer._tokenizer.pre_tokenizer.pre_tokenize_str(text)
pre_tokenized_text = [word for word, offset in pre_tokenize_result]
splits = [[l for l in word] for word in pre_tokenized_text]
for pair, merge in merges.items():
for idx, split in enumerate(splits):
i = 0
while i < len(split) - 1:
if split[i] == pair[0] and split[i + 1] == pair[1]:
split = split[:i] + [merge] + split[i + 2 :]
else:
i += 1
splits[idx] = split
return sum(splits, [])
tokenize("This is not a token.")
Huggingface 的 transformer 类中已经集成了很多分词器,可以直接使用。例如,利用 BERT 分词器获得输入“I have a new GPU!”的词元代码如下所示:
>>> from transformers import BertTokenizer
>>> tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
>>> tokenizer.tokenize("I have a new GPU!")
["i", "have", "a", "new", "gp", "##u", "!"]
相关文献:
[1] Du N, Huang Y, Dai A M, et al. Glam: Efficient scaling of language models with mixture-of-experts[C]//International Conference on Machine Learning. PMLR, 2022: 5547-5569.
[2] Larkey L S. Automatic essay grading using text categorization techniques[C]//Proceedings of the 21st annual international ACM SIGIR conference on Research and development in information retrieval. 1998: 90-95.
[3] Hernandez D, Brown T, Conerly T, et al. Scaling laws and interpretability of learning from repeated data[J]. arXiv preprint arXiv:2205.10487, 2022.
[4] Holtzman A, Buys J, Du L, et al. The curious case of neural text degeneration[C]//International Conference on Learning Representations. 2019.
[5] Lee K, Ippolito D, Nystrom A, et al. Deduplicating training data makes language models better[C]//Proceedings of the 60th Annual Meeting of the Association for Computational Linguistics (Volume 1: Long Papers). 2022: 8424-8445.
[6] Rae J W, Borgeaud S, Cai T, et al. Scaling language models: Methods, analysis & insights from training gopher[J]. arXiv preprint arXiv:2112.11446, 2021.
[7] Sennrich R, Haddow B, Birch A. Neural machine translation of rare words with subword units[C]//54th Annual Meeting of the Association for Computational Linguistics. Association for Computational Linguistics (ACL), 2016: 1715-1725.
[8] Schuster M, Nakajima K. Japanese and korean voice search[C]//2012 IEEE international conference on acoustics, speech and signal processing (ICASSP). IEEE, 2012: 5149-5152.
[9] Kudo T. Subword regularization: Improving neural network translation models with multiple subword candidates[C]//Proceedings of the 56th Annual Meeting of the Association for Computational Linguistics (Volume 1: Long Papers). 2018: 66-75.
随着基于统计机器学习的自然语言处理算法的发展,以及信息检索研究的需求,特别是近年来深度学习和预训练语言模型的研究,研究人员们构建了多种大规模开源数据集,涵盖了网页、图书、论文、百科等多个领域。在构建大语言模型时,数据的质量和多样性对于提高模型的性能至关重要。
同时,为了推动大语言模型的研究和应用,学术界和工业界也开放了多个针对大语言模型的开源数据集。
Pile
Pile 数据集[1] 是一个用于大语言模型训练的多样性大规模文本语料库,由 22 个不同的高质 量子集构成,包括现有的和新构建的,许多来自学术或专业来源。这些子集包括 Common Crawl、 Wikipedia、OpenWebText、ArXiv、PubMed 等。Pile 的特点是包含了大量多样化的文本,涵盖了不同领域和主题,从而提高了训练数据集的多样性和丰富性。Pile 数据集总计规模大小有 825GB 英文文本,其数据类型组成如下图所示,所占面积大小表示数据在整个数据集中所占的规模。
Pile 数据集合所包含的数据由如下 22 个不同子集:
学术领域
-
PubMed Central(PMC)是由美国国家生物技术信息中心(NCBI)运营的 PubMed 生物医学在线资源库的一个子集,提供对近 500 万份出版物的开放全文访问。
-
Free Law 项目是一个在美国注册的非营利组织,为法律领域的学术研究提供访问和分析工具。CourtListener 是 Free Law 项目的一部分,包含美国联邦和州法院的数百万法律意见,并提供批量下载服务。
-
ArXiv 是一个自 1991 年开始运营的研究论文预印版本发布服务,论文主要集中在数学、计算机科学和物理领域。ArXiv 上的论文是用 LaTeX 编写的,对于公式、符号、表格等内容的表示非常适合语言模型学习。
-
USPTO Backgrounds 是美国专利商标局授权的专利背景部分的数据集,来源于其公布的批量档案。典型的专利背景展示了发明的一般背景,给出了技术领域的概述,并建立了问题空间的框架。USPTO 背景,包含了大量关于应用主题的技术文章,面向非技术受众。
-
PubMed Abstracts 是由 PubMed 的 3000 万份出版物的摘要组成的数据集。PubMed 是由美国国家医学图书馆运营的生物医学文章在线存储库。PubMed 还包含了 MEDLINE,它包含了1946 年至今的生物医学摘要。
-
PhilPapers 数据集由 University of Western Ontario 数字哲学中心(Center for Digital Philosophy)维护的国际数据库中的哲学出版物组成。它涵盖了广泛的抽象、概念性的话语,其文本写作质量也非常高。
-
NIH Grant Abstracts: ExPORTER 数据集包含 1985 年至今,所有获得美国 NIH 资助的项目申请摘要,是非常高质量的科学写作实例。
互联网
-
Pile-CC 是基于 Common Crawl 的数据集,在 Web Archive 文件上使用 jusText[2] 的方法进行提取,这比直接使用 WET 文件,产生更高质量的输出。
-
OpenWebText2 (OWT2)是一个基于 WebText 和 OpenWebTextCorpus 的通用数据集。它包括从 Reddit 提交到 2020 年的最新内容、来自多种语言的内容、文档元数据、多个数据集版本和开源复制代码。
-
Stack Exchange 一个围绕用户提供问题和答案的网站集合。Stack Exchange Data Dump 包含了在 Stack Exchange 网站集合中所有用户贡献的内容的匿名数据集。它是截止到 2023 年 9月为止公开可用的最大的问题-答案对数据集合之一,涵盖了广泛的主题,从编程到园艺再到艺术等等。
-
Wikipedia (English) 是维基百科的英文部分。维基百科是一部由全球志愿者协作创建和维护的免费在线百科全书,旨在提供各种主题的知识。它是世界上最大的在线百科全书之一,可用于多种语言,包括英语、中文、西班牙语、法语、德语等等。
散文
-
Bibliotik 由小说和非小说类书籍组成,由 Shawn Presser 提供,几乎是图书数据集(BookCorpus2)数据量的十倍。Books3 就是来自 Bibliotik 的一个图书数据集。
-
PG-19 来自一个西方经典文学的数据集 Project Gutenberg,是由 1919 年以前的 Project Gutenberg 中的书籍组成,它们代表了与更现代的 Book3 和 BookCorpus 不同的风格。
-
BookCorpus2 数据集是原始 BookCorpus 的扩展版本,广泛应用于语言建模,甚至包括由“尚未发表”书籍。BookCorpus 与 Project Gutenbergu 以及 Books3 几乎没有重叠。
对话
-
OpenSubtitles 是由英文电影和电视的字幕组成的数据集。字幕是对话的重要来源,并且可以增强模型对虚构格式的理解。也可能会对创造性写作任务(如剧本写作、演讲写作、交互式故事讲述等)有一定作用。
-
Ubuntu IRC 数据集是从 Freenode IRC 聊天服务器上所有与 Ubuntu 相关的频道的公开聊天记录中提取的。聊天记录数据提供了语言模型建模人类交互的可能。
-
Hacker News 数据集是由初创企业孵化器和投资基金 Y Combinator 运营的链接聚合器。其目标是希望用户提交“任何满足一个人的知识好奇心的内容”,但文章往往聚焦于计算机科学和创业主题。其中包含了一些小众话题的高质量对话和辩论。
-
EuroParl 是一个多语言平行语料库,最初是为机器翻译任务构建。但也在自然语言处理的其他几个领域中得到了广泛应用。Pile 数据集中所使用的版本包括 1996 年至 2012年欧洲议会的 21 种欧洲语言的议事录。
-
YouTube Subtitles 数据集是从 YouTube 上人工生成的字幕中收集的文本平行语料库。该数据集除了提供了多语言数据之外,还是教育内容、流行文化和自然对话的来源。
其他
-
GitHub 是一个大型的开源代码库,对于语言模型完成代码生成、代码补全等任务具有非常重要的作用。
-
DeepMind Mathematics 数据集包含代数、算术、微积分、数论和概率等一系列数学问题组成,并且以自然语言提示的形式给出。大语言模型在数学任务上的表现较差,这可能部分是由于训练集中缺乏数学问题。因此,Pile 数据集中专门增加了数学问题数据集,期望增强通过 Pile 数据集训练的语言模型的数学能力。
Pile 中不同数据子集所占比例以及在训练时的采样权重有很大不同,对于高质量的数据会给于更高的采样权重。比如 Pile-CC 数据集包含 227.12GB 数据,整个训练周期中采样 1 轮,但是Wikipedia (en) 数据集虽然仅有 6.38G 数据,但是整个训练周期中采样 3 轮。具体的采样权重和采样轮数可以参考文献 [1]。
ROOTS
Responsible Open-science Open-collaboration Text Sources**(ROOTS)数据集合[3] 是 BigScience 项目在训练具有 1760 亿参数的 BLOOM 大语言模型所使用的数据集合**。该数据集合包含 46 种自然语言和 13 种编程语言,总计 59 种语言,整个数据集的大小约 1.6TB。ROOTS 数据集合中各语言所占比例如下图所示。图中左侧是以语言家族的字节数为单位表示的自然语言占比树状图。其中欧亚大陆语言占据了绝大部分(1321.89 GB)。橙色矩形对应是的印度尼西亚语(18GB),是巴布尼西亚大区唯一的代表。而绿色矩形对应于 0.4GB 的非洲语言。图中右侧是以文件数量为单位的编程语言分布的华夫饼图(Waffle Plot),一个正方形大约对应 3 万个文件。
ROOTS 数据主要来源于四个方面:公开语料、虚拟抓取、GitHub 代码、网页数据。
公开语料
在公开语料方面,BigScience Data Sourcing 工作组目标是收集尽可能多的收集各类型数据,包括自然语言处理数据集以及各类型文档数据集合。为此,还设计了 BigScience Catalogue[4] 用于管理和分享大型科学数据集,以及 Masader repository 用于收集阿拉伯语言和文化资源的开放数据存储库。在收集原始数据集的基础上,进一步从语言和统一表示方面对收集的文档进行规范化处理。识别数据集所属语言并分类存储,并将所有数据都按照统一的文本和元数据结构进行表示。由于数据种类繁多,ROOTS 数据集并没有公开其所包含数据集合情况,但是提供了 Corpus Map 以及 Corpus Description 工具,可以方便地查询各类数据集占比和数据情况。如下图所示,ROOTS 数据集中中文数据主要由 WuDao Corpora 和 OSCAR 组成。
虚拟抓取
在虚拟抓取方面,由于很多语言的现有公开数据集合较少,因此这些语言的网页信息是十分重要的资源补充。在 ROOTS 数据集中,采用 Common Crawl 网页镜像,选取了 614 个域名,从这些域名下的网页中提取文本内容补充到数据集中,以提升语言的多样性。
GitHub 代码
在 GitHub 代码方面,针对程序语言,ROOTS 数据集采用了与 AlphaCode 相同的方法从 BigQuery 公开数据集中选取文件长度在 100 到 20 万字符之间,字母符号占比在 15% 至 65%,最大行数在 20 至 1000 行之间代码。
网页数据
大语言模型训练中,网页数据对于数据的多样性和数据量支撑都起到了重要的作用,ROOTS 数据集合中包含了从 OSCAR 21.09 版本,对应的是 Common Crawl 2021 年 2 月的快照,占整体 ROOTS 数据集规模的 38%。
在数据准备完成后,还要进行清洗、过滤、去重以及隐私信息删除等工作,ROOTS 数据集处理流程如下图所示。整个处理工作并非完全依赖自动计算,而是人工与自动相结合的方法。针对数据中存在的一些非自然语言的文本,例如预处理错误、SEO 页面或垃圾邮件(包括色情垃圾邮件),ROOTS 数据集在构建时进行一定的处理。首先定义了一套质量指标,其中高质量的文本被定义为“由人类撰写,面向人类”(written by humans for humans),不区分内容(希望内容选择依据专业人员选择的来源)或语法正确性的先验判断。
所使用的**指标包括字母重复度、单词重复度、特殊字符、困惑度等。**完整的指标列表可以参考文献[3]。这些指标根据每个来源的不同,进行了两种主要的调整:针对每种语言单独选择参数,如阈值等;人工浏览每个数据来源,以确定哪些指标最可能识别出非自然语言。针对冗余信息,采用 SimHash 算法[5],计算文档的向量表示,并根据文档向量表示之间的海明距离(Hamming distance)是否超过阈值进行过滤。在此基础上又使用后缀数组(Suffix Array),将包含 6000 个以上字符重复的文档删除。通过上述方法共发现 21.67%的冗余信息。个人信息数据(包括:邮件、电话、地址等)则使用正则表示方法进行了过滤。
RefinedWeb
RefinedWeb[6] 是由位于阿布扎比的技术创新研究院 (Technology Innovation Institute, TII) 在开发 Falcon 大语言模型时同步开源的大语言模型预训练集合。其主要由从 CommonCrawl 数据集过滤的高质量数据组成。CommonCrawl 数据集包含自 2008 年以来爬取的数万亿个网页,由原始网页数据、提取的元数据和文本提取结果组成,总数据量超过 1PB。CommonCrawl 数据集以 WARC(Web ARChive)格式或者 WET 格式进行存储。WARC 是一种用于存档 Web 内容的国际标准格式,它包含了原始网页内容、HTTP 响应头、URL 信息和其他元数据。WET 文件只包含抽取出的纯文本内容。
文献[6]中给出了 RefinedWeb 中 CommonCrawl 数据集处理流程和数据过滤百分比,如下图所示。图中灰色部分是与前一个阶段相对应的移除率,阴影部分表示总体上的保留率。在文档准备阶段,**移除率以文档数量的百分比进行衡量,过滤阶段和重复去除阶段使用词元(Token)为单位进行衡量。**整个处理流程分为三个阶段:文档准备、过滤和去重。经过上述多个步骤之后,仅保留了大约 11.67% 的数据。RefinedWeb 一共包含 5 万亿个词元(5000G Token),开源公开部分6千亿个词元(600G Token)。
文档准备阶段
文档准备阶段主要是进行 URL 过滤、文本抽取和语言识别三个任务。
URL 过滤(URL Filtering)主要针对欺诈和成人网站(例如,主要包含色情、暴力、赌博等内容的网站)。使用基于规则的过滤方法:(1)包含 460 万黑名单域名(Blocklist);(2)根据严重程度加权的词汇列表对 URL 评分。
文本提取(Text Extraction)主要目标是仅提取页面的主要内容,同时去除菜单、标题、页脚、广告等内容。RefinedWeb 构建过程中使用 trafilatura 工具集[7],并通过正则表达式进行了部分后处理。
语言识别(Language Identification)阶段使用 CCNet 提出的 fastText 语言分类器[8]。该分类器使用字符 n-gram 做为特征,并在 Wikipedia 上进行训练,支持 176 种语言识别。如下图所示,CommonCrawl 数据集中非英语数据占比超过 50%,在经过语言识别后,过滤掉了所有非英语数据。
通过文档准备阶段得到的数据集合称为 RW-RAW。
过滤阶段
过滤阶段主要包含重复去除和文档过滤和逐行纠正三个任务。
重复去除(Repetition Removal)主要目标是删除具有过多行、段落或 n-gram 重复的文档。这些文档主要是由于爬取错误或者低质重复网页。这些内容会严重影响模型性能,使得模型产生病态行为(pathological behavior),因此需要尽可能在早期阶段去除。
文档过滤(Document-wise Filtering)目标是删除由机器生成的垃圾信息,这些页面主要由关键词列表、样板文本或特殊字符序列组成。采用了文献 [9] 中所提出的启发式质量过滤算法,通过整体长度、符号与单词比率以及其他标准来剔除离群值,以确保文档是实际的自然语言。
逐行纠正(Line-wise Corrections)目标是过滤文档中的不适合语言模型训练的行(例如,社交媒体计数器、导航按钮等)。使用基于规则的方法进行逐行纠正过滤,如果删除超过 5%,则完全删除该文档。
经过过滤阶段,仅有 23% 的原始数据得以保留,所得到的数据集合称为 RW-FILTERED。
冗余去除阶段
冗余去除阶段包含模糊冗余去除、严格冗余去除以及 URL 冗余去除三个任务。
模糊冗余去除(Fuzzy Deduplication)目标是删除内容相似的文档。使用了 MinHash 算法[10],快速估算两个文档间相似度。利用该算法可以有效过滤重叠度高的文档。RefinedWeb 数据集构建时,使用的是 5-gram 并分成 20 个桶,每个桶采用 450 个 Hash 函数。
严格冗余去除(Exact Deduplication)目标是删除连续相同的序列字符串。使用后缀数组(suffix array)进行严格逐个词元间的对比,并删除超过 50个以上的连续相同词元序列。
URL 冗余去除 (URL Deduplication)目标是删除具有相同 URL 的文档。CommonCrawl 数据中存在一定量的具有重复 URL 的文档,而且这些文档的内容绝大部分情况是完全相同的。RefinedWeb 数据集构建时,将 CommonCrawl 数据不同部分之间相同的 URL 进行了去除。
该阶段处理完成后的数据集称为 REFINEDWEB,仅有保留了原始数据的 11.67%。
以上三个阶段中所包含的各个任务的详细处理规则可以参考文献[6]附录部分。此外,文献[6] 还对三个阶段所产生的数据用于训练 10 亿和 30 亿模型的效果通过使用零样本泛化能力进行评测。发现 REFINEDWEB 的效果远好于 RW-RAW 和 RW-FILTERED。这也在一定程度上说明高质量数据集对于语言模型具有重要的影响。
SlimPajama
SlimPajama[11] 是由 CerebrasAI 公司针对 RedPajama 进行清洗和去重后得到的开源数据集合。原始 RedPajama 包含 1.21 万亿词元(1.21T Token),经过处理后的 SlimPajama 数据集包含 6270 亿词元(627B Token)。SlimPajama 还开源了用于对数据集进行端到端预处理的脚本。
RedPajama 是由 TOGETHER 联合多家公司发起的开源大语言模型项目,试图严格按照 LLaMA 模型论文中的方法构造大语言模型训练所需数据。虽然 RedPajama 数据质量较好,但是 CerebrasAI 的研究人员发现 RedPajama 数据集还是存在两个问题:1)一些语料中缺少数据文件;
2)数据集中包含大量重复数据。
为此,CerebrasAI 的研究人员开始针对 RedPajama 数据集开展进一步的处理。
SlimPajama 的整体处理过程如下图所示。整体处理包括多个阶段:NFC 正规化、清理、去重、文档交错、文档重排、训练集和保留集拆分,以及训练集与保留集中相似数据去重等步骤。所有步骤都假定整个数据集无法全部装载到内存中,并分布在多个进程中进行处理。使用 64 个 CPU,大约花费 60 多个小时就是完成 1.21 万亿词元处理。在整个处理过程中所需要内存峰值为 1.4TB。
SlimPajama 处理详细流程如下:
(1) NFC 正则化(NFC Normalization)
目标是去除非 Unicode 字符,SlimPajama 遵循 GPT-2 的规范,采用 NFC(Normalization Form C)正则化方法。NFC 正则化的命令示例如下:
python preprocessing/normalize_text.py \
--data_dir <prefix_path>/RedPajama/arxiv/ \
--target_dir <prefix_path>/RedPajama_norm/arxiv/
(2) 过滤短文档(Filter Short Documents)
RedPajama 的源文件中有 1.86% 包含了下载错误或长度较非常短的内容,这些内容对于模型训练没有作用。在去除标点、空格、换行和制表符后,过滤了长度少于 200 个字符的文档。查找需要过滤的文档的命令示例如下:
python preprocessing/filter.py \
<prefix_path>/RedPajama_norm/<dataset_name>/ \
<prefix_path>/RedPajama_filtered.pickle <n_docs> \
<dataset_name> <threshold>
(3) 去重(Deduplication)
为了对数据集进行全局去重(包括语料库内和语料库间的去重),SlimPajama 使用了 datasketch 库,并进行了一定的优化以减少内存消耗并增加并行性。采用了生产者-消费者模式,可以将运行时占主导地位的 I/O 操作进行有效的并行。整个去重过程包括多个阶段:(a)构建 MinHashLSH 索引、(b)在索引中进行查询以定位重复项、(c)构建图表示以确定重复连通域、(d)最后过滤每个成分中的重复项。
(a) MinHash 生成(MinHash Generation):
为了计算每个文档的 MinHash 对象,首先从每个文档中去除标点、连续空格、换行和制表符,并将其转换为小写。接下来,构建了13-gram 的列表,这些 n-gram 作为特征用于创建文档签名,并添加到 MinHashLSH 索引中。MinHash 生成的命令示例如下:
python dedup/to_hash.py <dataset_name> \
<prefix_path>/RedPajama_norm/<dataset_name>/\
<prefix_path>/RedPajama_minhash/<dataset_name>/ \
<n_docs> <iter> <index_start> <index_end> \
-w <ngram_size> -k <buffer_size>
(b) 重复对生成(Duplicate Pairs Generation)
使用 Jaccard 相似度计算文档之间相似度,设置阈值为 0.8 来确定一对文档是否应被视为重复。SlimPajama 的实现使用了 –range 和 –bands 参数,可在给定 Jaccard 阈值的情况下使用 datasketch/lsh.py 进行计算。重复对生成的命令示例如下:
python dedup/generate_duplicate_pairs.py \
--input_dir <prefix_path>/RedPajama_minhash/ \
--out_file <prefix_path>/redpj_duplicates/duplicate_pairs.txt \
--range <range> --bands <bands> --processes <n_processes>
© 重复图构建以及连通域查找(Duplicate Graph Construction & Search for Connected Components)
确定了重复的文档对之后,需要找到包含彼此重复文档的连通域。例如根据以下文档对:(A, B)、(A, C)、(A, E),可以形成一个 (A, B, C, E) 的组,并仅保留该组中的一个文档。可以使用如下命令构建重复图:
python dedup/generate_connected_components.py \
--input_dir <prefix_path>/redpj_duplicates \
--out_file <prefix_path>/redpj_duplicates/connected_components.pickle
(d) 生成最终重复列表(Generate Final List of Duplicates)
根据连通域构建创建一个查找表,以便稍后过滤出重复项。以下是生成重复项列表的命令示例:
python preprocessing/shuffle_holdout.py pass1 \
--input_dir <prefix_path>/RedPajama_norm/ \
--duplicates <prefix_path>/redpj_duplicates/duplicates.pickle \
--short_docs <prefix_path>/RedPajama_filtered.pickle\
--out_dir <prefix_path>/SlimPajama/pass1
(4) 交错和重排(Interleave & Shuffle)
大语言模型训练大都是在多源数据集上进行,需要使用指定的权重混合这些数据源。SlimPajama 数据集中默认从每个语料库中采样 1 轮,但是可以 通过 preprocessing/datasets.py 中更新采样权重。除了混合数据源外,还要执行随机重排操作以避免任何顺序偏差。交错和重排的命令示例如下:
python preprocessing/shuffle_holdout.py pass1 \
--input_dir <prefix_path>/RedPajama_norm/ \
--duplicates <prefix_path>/redpj_duplicates/duplicates.pickle \
--short_docs <prefix_path>/RedPajama_filtered.pickle \
--out_dir <prefix_path>/SlimPajama/pass1
(5) 训练和保留集合切分(Split Dataset into Train and Holdout)
这一步主要是完成第二次随机重拍并创建了保留集。为了加快处理速度,将源数据分成块并行处理。以下是命令示例:
for j in {1..20}
do
python preprocessing/shuffle_holdout.py pass2 "$((j-1))" "$j" "$j" \
--input_dir <prefix_path>/SlimPajama/pass1 \
--train_dir <prefix_path>/SlimPajama/train \
--holdout_dir <prefix_path>/SlimPajama/holdout > $j.log 2>&1 &
done
(6) 训练集与保留集中重复去除(Deduplicate Train against Holdout)
最后一步是确保训练集和保留集之间没有重叠。为了去除训练集的污染,应用了 SHA256 哈希算法来查找训练集和保留集之间的精确匹配项。然后,从训练集中过滤出这些精确匹配项。以下是命令示例:
python dedup/dedup_train.py 1 \
--src_dir <prefix_path>/SlimPajama/train \
--tgt_dir <prefix_path>/SlimPajama/holdout \
--out_dir <prefix_path>/SlimPajama/train_deduped
for j in {2..20}
do
python dedup/dedup_train.py "$j" \
--src_dir <prefix_path>/SlimPajama/train \
--tgt_dir <prefix_path>/SlimPajama/holdout \
--out_dir <prefix_path>/SlimPajama/train_deduped > $j.log 2>&1 &
done
相关文献:
[1] Gao L, Biderman S, Black S, et al. The pile: An 800gb dataset of diverse text for language modeling[J]. arXiv preprint arXiv:2101.00027, 2020.
[2] Endrédy I, Novák A. More effective boilerplate removal-the goldminer algorithm[J]. Polibits, 2013 (48):79-83. [3] Laurenccon H, Saulnier L, Wang T, et al. The bigscience roots corpus: A 1.6 tb composite multilingual dataset[J]. Advances in Neural Information Processing Systems, 2022, 35:31809-31826.
[4] McMillan-Major A, Alyafeai Z, Biderman S, et al. Documenting geographically and contextually diverse data sources: The bigscience catalogue of language data and resources[J]. arXiv preprint arXiv:2201.10066, 2022.
[5] Charikar M S. Similarity estimation techniques from rounding algorithms[C]//Proceedings of the thiry-fourth annual ACM symposium on Theory of computing. 2002: 380-388.
[6] Penedo G, Malartic Q, Hesslow D, et al. The refinedweb dataset for falcon llm: outperforming curated corpora with web data, and web data only[J]. arXiv preprint arXiv:2306.01116, 2023.
[7] Barbaresi A. Trafilatura: A web scraping library and command-line tool for text discovery and extraction[C]//Proceedings of the 59th Annual Meeting of the Association for Computational Linguistics and the 11th International Joint Conference on Natural Language Processing: System Demonstrations. 2021: 122-131.
[8] Wenzek G, Lachaux M A, Conneau A, et al. Ccnet: Extracting high quality monolingual datasets from web crawl data[C]//Proceedings of the Twelfth Language Resources and Evaluation Conference. 2020: 4003-4012.
[9] Rae J W, Borgeaud S, Cai T, et al. Scaling language models: Methods, analysis & insights from training gopher[J]. arXiv preprint arXiv:2112.11446, 2021.
[10] Broder A Z. On the resemblance and containment of documents[C]//Proceedings. Compression and Complexity of SEQUENCES 1997 (Cat. No. 97TB100171). IEEE, 1997: 21-29.
[11] Soboleva D, Al-Khateeb F, Myers R, et al. SlimPajama: A 627B token cleaned and deduplicated version of RedPajama[EB/OL]. 2023. https://huggingface.co/datasets/cerebras/SlimPajama-627B.
[12] 《大规模语言模型——从理论到实践》