7 – 数据集预处理

当大语言模型的基础架构搭建后,如何高效释放其理论潜能成为新的攻坚方向。前几章我们系统剖析了从零构建大语言模型的核心技术路径——这类以Transformer为骨架的深度神经网络,最初专攻自然语言理解与生成,如今已加速向多模态形态演进。然而,当模型规模突破百亿参数量级时,工程层面的挑战已跃升为制约模型效能释放的关键瓶颈。从本章开始,我们将深入大模型工业化落地的工程实践,工程能力是将学术论文中的SOTA指标转化为产业生产力的关键密钥, 这些内容涉及数据收集与处理、并行策略、计算优化、内存管理、稳定训练技术、容错机制等内容。

本篇从数据预处理讲起。

数据是构建大预言模型的根基,没有数据,一切无从谈起。收集大量不同种类和来源的自然语言语料对于创建高效的LLM至关重要。当前的LLM主要使用多个公共文本数据集极其组合作为其预训练语料库。

所使用的预训练数据可以分为两大类:通用数据专业数据。大多数LLM使用网页、书籍和对话等通用数据作为其预训练语料库,因为这类数据丰富、多样且易于获取,这有助于提高LLM的语言建模和泛化能力。同时,一些LLM使用诸如多语言数据、科学数据等特定领域的数据集,以赋予LLM解决垂直领域问题的能力。除此之外,还有大语言模型自合成数据集。

通用数据源(覆盖广泛领域的基础语料)

  1. Common Crawl• 最大的开源网页抓取数据集,原始数据达45TB,经严格过滤后保留约15%高质量内容(如C4数据集)。
  2. 维基百科• 高质量百科全书文本,覆盖多语言和学科领域,常作为模型的起点数据。
  3. 书籍与期刊• 虚构与非虚构书籍(如Project Gutenberg、Books3)提升模型叙事连贯性。
  4. 社交媒体与论坛• Reddit、Stack Exchange等问答平台提供真实对话数据,优化模型的指令遵循能力。

垂直领域数据源(专业场景增强)

  1. 开源代码库• GitHub、GitLab代码数据提升模型逻辑推理能力。
  2. 科学文献与行业数据• 科学领域:arXiv数学论文、PubMed医学文献,帮助模型处理复杂符号和公式。• 行业数据:法律判决文书、金融报告、医疗记录(需脱敏)提升特定领域适应性。
  3. 多语言数据• 中文数据如WanJuan、SkyPile-150B(含166万个中文网页),解决非英语语料稀缺问题。• 多语言混合训练(如BLOOM模型)需平衡语言比例,避免方言干扰。

大语言模型自合成数据集(补充性数据源)

由于大型语言模型规模变得越来越大,训练LLM有可能会耗尽我们所拥有的所有数据。目前已有企业选择使用通过LLM的自合成数据进行训练。Cosmopedia 是一个由Mixtral-8x7B-Instruct-v0.1生成,包含教科书、博文、故事、帖子和WikiHow文章的数据集。该数据集包含超过3000万个文件和250亿个tokens,据考证是由HuggingFac用了10k张H100生成的迄今为止最大的开放合成数据集。

上文曾提到,像LLaMa、GPT等模型,会对收集到的预训练数据进行去重、过滤等操作,这是因为原始训练数据集就像开采出来的原油,需要精炼和提纯。

数据和特征决定了机器学习算法的上限,而模型和算法只是不断逼近这个上限”,这一论断在大语言模型时代依旧成立。当收集了丰富的文本数据之后,为了确保数据的质量和效用,还需要对数据进行清洗,从而消除低质量、冗余、无关甚可能有害的数据,因为”garbage in garbage out“。

数据清洗主要用于过滤低质量或者提取特定任务需要(中文-日文翻译)的数据,而对于数据的质量,不同的文本类型有不同的评判标准。对于网页数据,我们希望网页内容完整,剔除嵌入广告以及多余的HTML元素标签;对于对话数据,我们希望词语连贯,剔除多余的表情(emjoi)符号; 对于代码数据,我们希望剔除多余的非代码、非注释类格式信息等等。

常用的数据清洗包括语种过滤、格式修正、低质量过滤、敏感信息过滤、毒害信息过滤等。

语种过滤

fastText

  Facebook开源的深度学习工具,支持176种语言,压缩模型仅917KB

import fasttext
model = fasttext.load_model('lid.176.ftz')  #   需要提前下载该模型
model.predict("Das ist ein Test")  # 输出('__label__de', 0.98)

Hugging Face Transformers

  • 集成了BERT、XLM-R等预训练模型,支持零样本跨语言检测
 from transformers import pipeline
 classifier = pipeline("text-classification", model="papluca/xlm-roberta-base-language-detection")
 classifier("我爱你中国") 
 输出 [{'label': 'zh', 'score': 0.9751690626144409}]

格式过滤

  • 移除 HTML/XML 标签、特殊符号、乱码;
  • 统一编码格式(如 针对中文同一使用UTF-8);
  • 修复断行、空格等排版问题;
  • 保留表格、数学公式等内容形式;

内容过滤

   内容过滤用于剔除无效,或信息量低的文本。

  • 删除过短文本(如 <100 字符)或长文本中的低信息密度段落。低信息密度段落指文本中有效语义信息占比低的片段,表现为:
    • 重复冗余:相同语义的多次重复(如”快来买!立即抢购!现在下单!”)
    • 通用模板:适用于任何场景的套话(如”根据相关法律法规…”)
    • 情绪填充:大量感叹词/表情符号(如”天啊!!!太棒了😍😍😍”)
    • 空洞描述:缺乏具体细节的叙述(如”这个产品非常好用,效果显著”),

   可以使信息熵来计算文本的信息度量,Shannon熵公式:

\(H(X)=−∑p(x_i)log2p(x_i)\)

import math
from collections import Counter

def calculate_entropy(text):
    # 中英文混合处理
    chars = [c for c in text if c.strip()]
    freq = Counter(chars)
    total = len(chars)
    return -sum( (count/total)*math.log2(count/total) for count in freq.values() )
   
阈值参考:中文:正常文本熵值 3.5-4.8,低于3.0可能为低信息英文:正常文本熵值 4.0-5.0,低于3.5需警惕
  • 过滤广告文本(通过重复关键词检测)
  • 屏蔽含大量乱码、无意义符号( 比如表情符号)的内容
from langdetect import detect
import re

def clean_short_text(text, min_length=100):
    # 基础清洗
    text = re.sub(r'\s+', ' ', text).strip()
    
    # 多语言兼容的短文本过滤
    if len(text) < min_length:
        try:
            # 排除有效短文本类型(如诗歌/指令)
            if detect(text) in ['zh-cn','ja'] and contains_meaningful_chinese(text):
                return text
            return None
        except: return None
    
    # 长文本低信息密度检测
    sentences = [s for s in re.split(r'[.!?。!?]', text) if s]
    low_info_count = sum(1 for s in sentences if is_low_info(s))
    
    # 保留高信息密度部分(可调阈值)
    if low_info_count / len(sentences) > 0.7:
        return " ".join([s for s in sentences if not is_low_info(s)])
    
    return text

def is_low_info(sentence):
    """基于信息熵与停用词比例的混合检测"""
    stopword_ratio = sum(1 for w in sentence.split() if w in stopwords) / len(sentence.split())
    entropy = calculate_shannon_entropy(sentence)
    return stopword_ratio > 0.6 or entropy < 2.5

敏感信息过滤

  • 基于预定义黑名单(涉政、暴力、色情等关键词)过滤数据;
  • 电话号码,邮箱地址,以及 IP 地址等隐私信息;

  内容去重

  • 文档级去重(MinHash/LSH 算法检测相似文档)
from datasketch import MinHashLSH

# 初始化LSH索引(相似度阈值0.7)
lsh = MinHashLSH(threshold=0.7, num_perm=128)

def doc_to_minhash(text, num_perm=128):
    m = MinHash(num_perm=num_perm)
    for word in text.split():
        m.update(word.encode('utf-8'))
    return m

# 添加文档到索引
documents = ["doc1 text...", "doc2 text..."] 
for idx, doc in enumerate(documents):
    mh = doc_to_minhash(doc)
    lsh.insert(f"doc_{idx}", mh)

# 查询相似文档
query_doc = "query text..."
query_hash = doc_to_minhash(query_doc)
result = lsh.query(query_hash)  # 返回相似文档ID列表
  • 段落级去重(13-gram 重复字符 >50% 时剔除,与论文方法类似);
  • 句子级别去重,删除包含重复单词和短语的低质量句子;
  • 模糊去重,语义相似度检测(如 SimHash)避免近义重复;

毒性模型检测

  • 使用类似 FastText 的分类器评估文本毒性;
from transformers import pipeline
# 加载模型
classifier = pipeline("text-classification", model="unitary/toxic-bert")
# 检测结果
print(classifier("This is an explicit threat."))

以上,数据清洗的基本流程。下面我们继续讨论,在实际生产场景,如何高效的处理大规模/超大规模数据集。