文章目录
概要
-
文章说明:本文基于《星火大模型驱动阅读理解题库构建挑战赛》的数据编写学习笔记,旨在介绍微调的流程,和微调过程中的数据流动。
-
赛事链接 :https://challenge.xfyun.cn/h5/detail?type=question-bank-construction&option=phb&ch=dw24_E7x9gl
整体架构流程
1. 数据处理,生成微调数据
1.1 赛题数据介绍
1.1.1 原始数据格式
python
import pandas as pd
import re
# 读取Excel文件
df = pd.read_excel('训练集-语文.xlsx')
python
df.head(2)
训练集-语文.xlsx包含三列,数据细节如下:
1.1.2 期望用来微调数据格式
微调的数据的提示词格式为:
问题及答案数据格式为:
即把原始数据的选项和答案一一对应。
1.2 数据清洗
python
df = df.replace('.', '.', regex=True)
df = df.replace('(', '(', regex=True)
上述代码段使用了pandas库中的DataFrame
对象的replace()
方法,来在DataFrame中替换特定的字符或字符串。这里,代码执行了两个替换操作,每个操作都使用了正则表达式(通过设置regex=True
)来匹配并替换特定的字符或字符序列。下面是这两个操作的详细解释:
- 第一个替换操作
python
df = df.replace('.', '.', regex=True)
-
目的 :将DataFrame中所有的全角句号(
.
)替换为半角句号(.
)。 -
第二个替换操作
python
df = df.replace('(', '(', regex=True)
- 目的 :将DataFrame中所有的全角左括号(
(
)替换为半角左括号((
)。
1.3 生成微调数据
python
def chinese_multiple_choice_questions(questions_with_answers):
# 输入的题目文本
text = questions_with_answers
# 正则表达式模式
question_pattern = re.compile(r'\d+\..*?(?=\d+\.|$)', re.DOTALL)
choice_pattern = re.compile(r'([A-D])\s*(.*?)(?=[A-D]|$|\n)', re.DOTALL)
# 找到所有问题
questions = question_pattern.findall(text)
# 初始化选择题和简答题列表
multiple_choice_questions = []
short_answer_questions = []
# 处理每个问题
for id,question in enumerate(questions):
# 检查是否是选择题
if re.search(r'[A-D]', question):
choices = choice_pattern.findall(question)
question_text = re.split(r'\n', question.split('(')[0])[0]
pattern_question = re.compile(r'(\d+)\.(.*)')
matches_question = str(id+1)+'.'+ pattern_question.findall(question_text)[0][1] # 取出问题后重排序
# print(str(id+1)+'.'+matches_question)
multiple_choice_questions.append({
'question': matches_question,
'choices': choices
})
else:
short_answer_questions.append(question.strip())
return multiple_choice_questions
def chinese_multiple_choice_answers(questions_with_answers):
questions_with_answers = questions_with_answers.replace(" ", "").replace("\n", "")
# print(questions_with_answers)
# 使用正则表达式匹配答案
choice_pattern = re.compile(r'(\d+)\.([A-Z]+)')
short_pattern = re.compile(r'(\d+)\.([^A-Z]+)')
# 找到所有匹配的答案
choice_matches = choice_pattern.findall(questions_with_answers)
short_matches = short_pattern.findall(questions_with_answers)
# 将匹配结果转换为字典
choice_answers = {int(index): answer for index, answer in choice_matches}
short_answers = {int(index): answer for index, answer in short_matches}
# 按序号重新排序
sorted_choice_answers = sorted(choice_answers.items())
sorted_short_answers = sorted(short_answers.items())
answers = []
# 输出结果
# print("选择题答案:")
for id in range(len(sorted_choice_answers)):
answers.append(f"{id+1}. {sorted_choice_answers[id][1]}")
return answers
以下是两个函数 chinese_multiple_choice_questions
和 chinese_multiple_choice_answers
的详细解释:
- chinese_multiple_choice_questions函数
目的:从包含问题和答案的文本中提取出选择题及其选项,并将它们以字典形式组织起来。
步骤:
-
初始化变量 :将输入的
questions_with_answers
文本赋值给text
变量。 -
编译正则表达式:
question_pattern
:用于匹配问题文本,从数字点开始到下一个数字点或文本末尾。choice_pattern
:用于匹配选择题中的选项,从选项字母(A-D)开始到下一个选项字母、文本末尾或换行符。
-
查找所有问题 :使用
question_pattern
查找text
中所有匹配的问题,并将它们存储在questions
列表中。 -
初始化列表 :创建两个空列表
multiple_choice_questions
和short_answer_questions
,分别用于存储选择题和简答题。 -
遍历问题 :对于
questions
列表中的每个问题,使用enumerate
获取其索引(id
)和内容(question
)。 -
检查问题类型:
- 如果问题中包含选项字母(A-D),则认为它是选择题。
- 使用
choice_pattern
查找问题中的选项,并存储在choices
列表中。 - 尝试从问题文本中提取问题编号和文本。这里使用了
split
和re.split
的组合。 - 使用
re.compile
和findall
提取问题编号和文本。 - 将格式化后的问题和选项作为字典添加到
multiple_choice_questions
列表中。
-
处理简答题 :如果问题不包含选项字母,则将其视为简答题,并添加到
short_answer_questions
列表中。 -
返回结果 :函数只返回
multiple_choice_questions
列表,忽略了short_answer_questions
列表。
- chinese_multiple_choice_answers函数
目的:从包含问题和答案的文本中提取出选择题和简答题的答案,并将它们以列表形式返回。
步骤:
-
预处理文本:去除输入文本中的所有空格和换行符。
-
编译正则表达式:
choice_pattern
:用于匹配选择题的答案,格式为数字点后跟大写字母。short_pattern
:用于匹配简答题的答案,格式为数字点后跟非大写字母的文本。
-
查找答案 :使用两个正则表达式分别查找选择题和简答题的答案,并将它们存储在
choice_matches
和short_matches
列表中。 -
将匹配结果转换为字典:将匹配结果转换为字典,其中键是问题编号(转换为整数),值是答案。
-
排序 :将字典的项按编号排序,得到
sorted_choice_answers
和sorted_short_answers
。 -
构建答案列表 :遍历
sorted_choice_answers
,将选择题答案格式化为字符串,并添加到answers
列表中。注意,这里没有包含简答题的答案。 -
返回结果 :返回包含选择题答案的
answers
列表。
注意:函数只返回了选择题的答案,忽略了简答题的答案。此外,去除文本中的空格和换行符可能会导致意外的匹配结果,特别是如果答案文本中原本包含这些字符时。在实际应用中,可能需要更精细的文本处理逻辑来确保准确性。
python
df['答案_processed'] = df['答案'].map(chinese_multiple_choice_answers)
df增加一列答案_processed
,如下:
1.3.1 生成提示词和回答
python
def get_prompt_cn(text):
prompt = f'''
你是⼀个⾼考选择题出题专家,你出的题有⼀定深度,你将根据阅读文本,出4道单项选择题,包含题目选项,以及对应的答案,注意:不⽤给出原文,每道题由1个问题和4个选项组成,仅存在1个正确答案,请严格按照要求执行。 阅读文本主要是中文,你出的题目需要满足以下要点,紧扣文章内容且题干和答案为中文:
### 回答要求
(1)理解文中重要概念的含义
(2)理解文中重要句子的含意
(3)分析论点、论据和论证方法
### 阅读文本
{text}
'''
return prompt
python
def process_cn(df):
res_input = []
res_output = []
for id in range(len(df)):
data_options = df.loc[id, '选项']
data_answers = df.loc[id,'答案']
data_prompt = df.loc[id,'阅读文本']
data_options = chinese_multiple_choice_questions(data_options)
data_answers = chinese_multiple_choice_answers(data_answers)
data_prompt = get_prompt_cn(data_prompt)
# print(data_options)
# print(data_answers)
if(len(data_answers)==len(data_options)):
res = ''
for id_,question in enumerate(data_options):
res += f'''
{question['question']}?
'''+'\n'
for choise in question['choices']:
res = res+ choise[0] + choise[1]+ '\n'
res = res + '答案:' + str(data_answers[id_].split('.')[-1]) + '\n'
res_output.append(res)
res_input.append(data_prompt)
# break
return res_input,res_output
这段代码定义了一个名为 process_cn
的函数,它接收一个 DataFrame(df
)作为输入,这个 DataFrame 预期包含三列:'选项'
、'答案'
和 '阅读文本'
。该函数的主要目的是处理这些列中的数据,将每个选项格式化为更易读的格式,并生成两个列表:res_input
和 res_output
。res_input
包含处理后的"阅读文本",而 res_output
包含格式化后的选项和答案。
下面是对代码主要部分的详细解释:
-
初始化结果列表 :函数开始时,初始化了两个空列表
res_input
和res_output
,用于存储处理后的"阅读文本"和格式化后的选项及答案。 -
遍历 DataFrame :通过
for id in range(len(df))
循环遍历 DataFrame 的每一行。这里使用id
作为索引,但更常见的做法是直接遍历df.iterrows()
或使用for index, row in df.iterrows():
,这样可以更直接地访问行数据。 -
提取数据 :对于每一行,从 DataFrame 中提取
'选项'
、'答案'
和'阅读文本'
列的值。 -
处理数据:
data_options = chinese_multiple_choice_questions(data_options)
:调用chinese_multiple_choice_questions
函数来处理'选项'
列的数据。data_answers = chinese_multiple_choice_answers(data_answers)
:调用chinese_multiple_choice_answers
函数处理'答案'
列的数据。data_prompt = get_prompt_cn(data_prompt)
:调用get_prompt_cn
函数来处理'阅读文本'
列的数据。
-
条件检查:检查处理后的答案数量是否与选项数量相等。这是为了确保每个选项都有一个对应的答案。
-
格式化输出:
- 使用嵌套循环遍历每个选项及其选择项,将它们格式化为问题后跟选项的字符串,并在每个问题后添加对应的答案。
- 格式化后的字符串被添加到
res_output
列表中。 - 对应的"阅读文本"被添加到
res_input
列表中。
-
返回值 :函数返回两个列表:
res_input
和res_output
。
python
cn_input,cn_output = process_cn(df)
最终,处理训练集-语文.xlsx
生成的提示词和回答如下:
2.模型微调
将1.3生成的数据送入如下链接微调:
https://training.xfyun.cn/dataset/datasetIndex
微调步骤见学习教程:https://linklearner.com/activity/14/12/26
3.模型推理
利用微调后的模型推理测试数据,将测试数据送入微调模型
4.模型评估
技术名词解释
提示:这里可以添加技术名词解释
例如:
- Bert
- GPT 初代
- GPT-2
- GPT-3
- ChatGPT
技术细节
1.提示词编写规范
提示:这里可以添加技术细节
例如:
- API
- 支持模型类型
小结
提示:这里可以添加总结
例如:
提供先进的推理,复杂的指令,更多的创造力。