1. 引言
通过前面两篇文章欺诈文本分类微调(二):生成正向数据集和欺诈文本分类微调(三):生成反向数据集我们已经生成了正向和反向的基础数据集,不过这些数据集还是比较原始的长篇对话,并不适合直接用于特定任务的指令微调训练,大概还需要进行以下几方面处理:
- 不同长度的对话文本构造
- 正、反向数据集的均衡分布
- 训练、测试集的构造
2. 构造不同长度对话集
2.1 加载数据文件
复用前面一篇文章的工具函数。
import pandas as pd
import os
import json
def filename(path):
filename_with_ext = os.path.basename(path)
filename, extention = os.path.splitext(filename_with_ext)
return filename
def get_files(directory, extension='.csv'):
files = [f for f in os.listdir(directory) if f.endswith(extension)]
return files
def print_json(obj):
print(json.dumps(obj, indent=4, ensure_ascii=False))
input_dir = "../dataset/fraud/csv_dialogs"
files = get_files(input_dir)
files
['虚假购物诈骗(200).csv',
'虚拟货币诈骗(200).csv',
'“杀猪盘” 诈骗(200).csv',
'冒充客服诈骗(200).csv',
'网络赌博诈骗(200).csv',
'传销诈骗(140).csv',
'短信诈骗(200).csv',
'微商代理诈骗(200).csv',
'网络贷款诈骗(162).csv',
'二手交易诈骗(200).csv',
'兼职刷单诈骗(140).csv',
'meeting_label_false.csv',
'投资诈骗(200).csv']
2.2 对话集分割
定义数据集中的列名,以及任务中的提示词指令。
group_column = 'case'
speaker_column = 'speaker'
content_column = 'content'
is_fraud_column = 'is_fraud'
instruction = "下面是一段对话文本, 请分析对话内容是否有诈骗风险,只以json格式输出你的判断结果(is_fraud: true/false)。"
关于数据集中是否应该提供instruction指令,主要看所使用的模型和训练场景,对于大语言模型下的特定任务微调,提供明确的指令能够帮助模型更好地理解任务,并帮助模型区分不同的任务,从而提高模型在多任务场景下的表现。
定义几个工具函数用于辅助对话集分割,
- find_fraud_speaker:用于找出案例中属于诈骗角色的发言人,对于正向(欺诈)数据集,里面必定有一个发言人属于诈骗者。
- total_chars: 用于统计一组对话集的长度,用于实时判断分割后对话集的长度是否超限。
- to_train_data: 用于将一组对话集转换为一条训练数据。
def find_fraud_speaker(df: pd.DataFrame):
# 按照speaker列进行分组,并统计每个分组下is_fraud=True的数量
fraud_counts = df.groupby(speaker_column)[is_fraud_column].sum()
# 特殊情况处理:对于没有is_fraud=True的对话集,则没有诈骗者
if fraud_counts.max() == 0:
return ''
# 统计欺诈最多的speaker即认为是诈骗者
return fraud_counts.idxmax()
def total_chars(strs: list):
return sum(len(s) for s in strs)
def to_train_data(dialog:list, label, instruction, fraud_speaker=''):
content = "\n".join(dialog)
return {
"input": content, "label": label, "fraud_speaker": fraud_speaker, "instruction": instruction}
定义一个函数split_dialog用于处理单个案例的分割,按照指定的长度将一个案例分割成多段对话,每段对话作为一条训练数据。具体步骤为:
- 遍历并逐句叠加对话内容,达到max_length指定的长度就构造一组small_dialog,作为一条训练数据。
- 遍历完后可能会剩余最后一段,在for循环后加补充逻辑来将剩余数据添加到small_dialogs。
注:之所以要对一个完整的案例进行分割,是为了尽量贴合实际场景,一方面是一场会议比较长,我们不大可能把整个会议的ASR文本一次给到大模型做欺诈检测&