FastChat数据预处理:文本清洗与格式标准化

FastChat数据预处理:文本清洗与格式标准化

【免费下载链接】FastChat An open platform for training, serving, and evaluating large language models. Release repo for Vicuna and Chatbot Arena. 【免费下载链接】FastChat 项目地址: https://gitcode.com/GitHub_Trending/fa/FastChat

在大语言模型训练过程中,数据质量直接决定了模型性能的上限。FastChat作为业界领先的开源对话模型训练平台,提供了一套完整的数据预处理流水线,本文将深入解析其文本清洗与格式标准化技术细节。

数据预处理的核心挑战

mermaid

大语言模型训练数据面临的主要挑战包括:

挑战类型具体问题FastChat解决方案
格式不一致HTML标签残留、代码块格式错误HTML转Markdown标准化
内容质量问题低质量对话、重复内容多级过滤机制
语言混杂多语言混合影响训练效果语言检测与过滤
长度不匹配对话过长超出模型上下文智能分割算法
隐私与合规敏感信息泄露风险关键词过滤机制

HTML到Markdown的精准转换

FastChat使用clean_sharegpt.py模块处理HTML格式的原始数据,其转换流程包含多个关键步骤:

正则表达式模式匹配

# 核心正则表达式模式
div_pattern = re.compile("<div.*?>")
span_pattern = re.compile("<span.*?>")
code_lang_pattern = re.compile(
    "```\s*" + "(.*?)" + "(?:Copy code)+" + "(.+?)" + "\s*?```", re.DOTALL
)
code_lang_format = "```\g<1>\n\g<2>\n```"

代码块格式化处理

原始HTML中的代码块通常包含冗余信息,FastChat通过以下步骤进行清理:

def reformat_code(val: str) -> str:
    # 输入格式示例:
    # ```
    # $<language>Copy code$<exact_code_here>
    # ```
    # 转换为标准Markdown格式
    return re.sub(code_lang_pattern, code_lang_format, val)

def html_to_markdown(val: str) -> str:
    val = re.sub(div_pattern, "", val)  # 移除所有<div>标签
    val = re.sub(span_pattern, "", val)  # 移除所有<span>标签
    val = markdownify.markdownify(val).strip()  # 转换为Markdown
    val = reformat_code(val)  # 重新格式化代码块
    
    # 移除噪声内容
    val = re.sub(regenerate_pattern, "", val)
    val = re.sub(copy_chars_pattern, "", val)
    val = re.sub(copy_code_pattern, "", val)
    
    return val.replace("\n\n\n", "\n").strip()

多级数据过滤机制

1. 格式验证过滤

def clean_html_one_sample(sample):
    roles = ["human", "gpt"]
    
    # 对话轮次验证
    if len(sample["conversations"]) <= 1:
        return (sample, 1)  # 跳过过短对话
    
    # 起始角色验证(必须从human开始)
    if sample["conversations"][0]["from"] != "human":
        sample["conversations"] = sample["conversations"][1:]
    
    # 终止角色验证(必须以gpt结束)
    if sample["conversations"][-1]["from"] == "human":
        sample["conversations"] = sample["conversations"][:-1]

2. 关键词黑名单过滤

def contain_blocked_words(val: str) -> bool:
    blocked_words = ["openai", "chatgpt"]
    for w in blocked_words:
        if w in val.lower():
            return True
    return False

def contain_blocked_responses(role: str, val: str) -> bool:
    if role == "gpt":
        blocked_responses = [
            "Too many requests in 1 hour. Try again later.",
            "!Too many requests in 1 hour. Try again later.",
        ]
        for w in blocked_responses:
            if val.startswith(w):
                return True
    return False

3. 语言检测与过滤

def skip(conv, args):
    # 多语言检测与过滤
    if args.keep_lang != "all" or args.skip_lang is not None:
        text = "\n".join([x["value"] for x in conv["conversations"]])
        try:
            lang_code = Detector(text).language.code
        except (pycld2.error, polyglot.detect.base.UnknownLanguage):
            lang_code = "unknown"

        # 保留指定语言或跳过指定语言
        if args.keep_lang != "all" and lang_code != args.keep_lang:
            return True
        if lang_code == args.skip_lang:
            return True
    
    # 重复数字模式过滤
    if args.reduce_rep:
        for sentence in conv["conversations"]:
            val = sentence["value"]
            sub = re.search(r"(\d)\1{8}", val)  # 检测连续9个相同数字
            if sub is not None:
                return True
    return False

长对话智能分割算法

mermaid

FastChat采用基于token长度的智能分割算法:

def split_one_sample(sample):
    tokenized_lens = []
    conversations = sample["conversations"]
    conversations = conversations[: len(conversations) // 2 * 2]  # 确保偶数轮次
    
    # 计算每轮对话的token长度
    for c in conversations:
        length = len(tokenizer(c["value"]).input_ids) + 6  # 添加特殊token开销
        tokenized_lens.append(length)

    start_idx = 0
    cur_len = 0
    new_samples = []

    # 滑动窗口分割算法
    for i in range(0, len(conversations), 2):
        tmp_len = tokenized_lens[i] + tokenized_lens[i + 1]  # 一轮完整对话长度
        if cur_len + tmp_len > max_length:  # 超过最大长度限制
            new_samples.append(make_sample(sample, start_idx, i))
            start_idx = i
            cur_len = 0
        elif i == len(conversations) - 2:  # 最后一轮对话
            new_samples.append(make_sample(sample, start_idx, i + 2))
        cur_len += tmp_len

    return new_samples

数据质量统计与分析

FastChat提供详细的数据统计功能,帮助用户了解数据集特征:

def compute_stats(content):
    sample_lens = []      # 样本总长度
    sample_turns = []     # 对话轮次
    prompt_lens = []      # 提示词长度
    res_lens = []         # 回复长度

    for c in content:
        sample_len = 0
        sample_turns.append(len(c["conversations"]) // 2)
        for i in range(len(c["conversations"]) // 2):
            p = c["conversations"][i * 2]["value"]    # 用户提问
            r = c["conversations"][i * 2 + 1]["value"] # 模型回复
            turn_len = len(p) + len(r)
            sample_len += turn_len
            prompt_lens.append(len(p))
            res_lens.append(len(r))
        sample_lens.append(sample_len)

    return sample_lens, sample_turns, prompt_lens, res_lens

统计输出示例:

#sequence: 125.34 K
#tokens: 1.25 M
avg. turns: 2.45
avg. prompt length: 156.78
avg. response length: 245.32

完整数据处理流水线

# 步骤1: HTML转Markdown基础清洗
python3 -m fastchat.data.clean_sharegpt --in sharegpt_html.json --out sharegpt_clean.json

# 步骤2: 语言过滤(可选)
python3 -m fastchat.data.optional_clean --in sharegpt_clean.json --out sharegpt_clean_en.json --keep-lang en

# 步骤3: 格式错误过滤
python3 -m fastchat.data.filter_wrong_format --in sharegpt_clean_en.json --out sharegpt_clean_en_filtered.json

# 步骤4: 长对话分割
python3 -m fastchat.data.split_long_conversation \
    --in sharegpt_clean_en_filtered.json \
    --out sharegpt_final.json \
    --model-name-or-path meta-llama/Llama-2-7b-chat-hf

# 步骤5: 数据统计分析
python3 -m fastchat.data.get_stats --in sharegpt_final.json

最佳实践与性能优化

并行处理加速

FastChat利用多进程并行处理大幅提升清洗效率:

def clean_html_all(content, begin, end):
    processed = []
    with ProcessPoolExecutor() as executor:
        for result in tqdm(
            executor.map(clean_html_one_sample, content), total=len(content)
        ):
            processed.append(result)
    # ...后续处理逻辑

内存优化策略

对于超大规模数据集,建议采用分块处理:

def split_all(content, begin, end, tokenizer_, max_length_):
    # 将数据分块处理,每块1000个样本
    chunks = [content[i : i + 1000] for i in range(0, len(content), 1000)]
    with ProcessPoolExecutor() as executor:
        for result in tqdm(executor.map(worker, chunks), total=len(chunks)):
            new_content.extend(result)
    return new_content

总结

FastChat的数据预处理流水线体现了现代大语言模型训练数据处理的先进理念:

  1. 标准化优先:通过HTML到Markdown的转换确保格式统一
  2. 质量至上:多级过滤机制保障数据纯净度
  3. 智能分割:基于token长度的自适应分割算法
  4. 可扩展架构:并行处理支持大规模数据集
  5. 透明统计:详细的数据分析帮助优化训练策略

这套数据处理方案不仅适用于Vicuna模型训练,也可作为其他对话模型数据预处理的参考标准,为构建高质量对话数据集提供了完整的技术路径。

【免费下载链接】FastChat An open platform for training, serving, and evaluating large language models. Release repo for Vicuna and Chatbot Arena. 【免费下载链接】FastChat 项目地址: https://gitcode.com/GitHub_Trending/fa/FastChat

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值