【Datawhale AI夏令营】Task2: baseline1精讲

一、介绍及数据处理思路

1.1 介绍

        Task2的任务包含了对数据处理策略的说明、微调步骤的详细介绍、baseline代码的深入解析以及相关附加知识的讲解。

1.2 数据处理思路

1.2.1 微调数据

        数据集包含了近年来语文和英语阅读材料的数据,依据讯飞大模型定制训练平台的要求进行处理。数据集分为input和target两部分。Input部分由用于训练的阅读材料及其相关要求组成,提供了大模型生成阅读题目的基础内容;target部分则是训练目标,包含选项和参考答案。总之,输入到讯飞大模型的数据集由两部分组成:一部分是阅读原文(这是模型训练的核心基础),另一部分是范例题目(用于训练大模型以生成后续的题目)。

1.2.2 数据处理方案

        本文使用了正则表达式模块re来进行字符串处理,并使用pandas库来处理xlsx文件。

        自Python 1.5版本起,引入的re模块提供了类似于Perl的正则表达式功能。通过re.compile函数,可以将模式字符串编译为正则表达式对象,该对象具备匹配和替换的能力。re模块还提供了直接使用模式字符串的函数,其功能与正则表达式对象的方法一致。

        Pandas是一个基于Numpy的开源数据分析工具库,其名称来源于“panel data”和“Python data analysis”。该库提供了高效的工具,用于从CSV、JSON、SQL、Excel等格式的数据中进行导入、归并、重塑、选择和清洗,广泛应用于学术研究、金融和统计领域。

        基于上述方法,将文件中的数据读取后,使用re.compile整理数据,并将其保存为适合微调的数据格式。

二、微调流程

2.1 大模型模型介绍

        大语言模型(LLM)是一种旨在理解和生成自然语言的人工智能模型,通常拥有数十亿甚至更多的参数,并在大量文本数据上进行了训练,如GPT-3、GPT-4、PaLM等。

        LLM与传统模型的主要差异在于其涌现能力,包括上下文学习、指令执行和逐步推理,这使得LLM能够更灵活地应对复杂任务,并提供更加精准的回答和推理能力。

        LLM拥有庞大的参数规模,支持预训练与微调,具备强大的上下文感知、多语言与多模态处理能力,广泛应用于文本生成、自动翻译等领域。

        然而,LLM也面临着伦理与风险挑战,如生成有害内容、侵犯隐私和存在认知偏差等问题。

2.2 微调介绍

       微调步骤如图 1所示。

1 微调步骤

2.2.1 使用微调的情况(条件)和原因

       使用微调的条件为使用的数据集和预训练模型的数据集类似(即相似的特征提取)、自己搭建模型的正确率太低、数据集数量太少和计算资源太少。

       使用微调的原因在于:

  1. 需要有限数据量即可,节约时间和计算资源。
  2. 收敛存在模型,优化参数,提高准确率,解决模型泛化能力低、过拟合等问题。

2.2.2 不同数据集的微调方法

       不同的数据集以数据量和相似度作为特点来区分,不同特点的数据集有不同的微调解决方法,根据精讲,可以将微调方法总结如所示。

表 1 不同数据集的微调方法

数据集编号

特点

解决方法

1

数据量少且相似度高

修改模型的最后几层或softmax图层的输出类别

2

数据量少且相似度低

冻结预训练模型的初始层并重新训练较高层

3

大量但相似度低的数据

从头训练神经网络

4

数据量大且相似度高

保留预训练模型的架构和初始权重进行再训练

2.2.3 微调注意事项

       通常情况下,会截断预训练网络的最后一层并替换为与我们任务相关的新softmax层,如从1000个类别改为10个类别。在训练时使用较小的学习率,以避免过快扭曲预训练的权重。对于小数据集,仅训练最后一层;对于中等数据集,冻结前几层权重以保留通用特征,让网络专注于学习深层特定特征。

2.2.4 高效微调方法-Lora

       LoRA (Low-rank Adaptation) 是一种高效微调大语言模型的方法,旨在解决全量参数 Fine-tune 的资源消耗问题。传统的 Fine-tune 需要调整模型所有参数,随着预训练模型规模的扩大,资源压力倍增。

        LoRA 改进了传统的 Adapt Tuning 方法,通过优化密集层的秩分解矩阵来实现微调,避免了增加额外参数带来的推理延迟问题。它可以有效构建小型 LoRA 模块,针对不同任务切换,并使用自适应优化器,减少硬件要求。

        LoRA 主要在 Transformer 结构中的注意力模块应用,通过低秩分解更新部分权重矩阵,冻结其他部分,进而高效完成微调。

        通过 peft 库,LoRA 的实现变得便捷,可以轻松应用于大模型的微调。具体步骤包括确定需要使用 LoRA 的层,替换为 LoRA 层并冻结原参数,然后使用 Trainer 进行训练。

        LoRA微调方法在不显著增加计算量的情况下,提高了模型在不同任务上的适应性。

三、baseline1精讲 %源于Datawhale

  1. 环境准备(相关库的下载与安装)
!pip install pandas openpyxl
  1. 语文数据处理
2.1 数据加载
# coding~
 
import pandas as pd
import re
 
# 读取Excel文件
df = pd.read_excel('训练集-语文.xlsx')
df = df.replace('.', '.', regex=True)
df = df.replace('(', '(', regex=True)
 
# 读取第二行(即第三行)“选项”列的内容
# 可以使用loc获取某行的数据
second_row_option_content = df.loc[2, '选项']
 
# 显示第二行“选项”列的内容
print(second_row_option_content)
    1. 抽取问题
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)
    # 这一行作用是匹配一个以字母[A到D]开头、后面跟着一个点字符的字符串,
    #直到遇到下一个[A到D]或字符串结束。
    
    
    # 找到所有问题
    questions = question_pattern.findall(text)
 
    # 初始化选择题和简答题列表
    multiple_choice_questions = []
    short_answer_questions = []
 
        # 处理每个问题
    for id,question in enumerate(questions):
        # 这里取到的question,如果是选择题会带着选择题的选项。
        # 检查是否是选择题 因为选择题内有ABCD这样的选项
        if re.search(r'[A-D]', question):
            # 如果有选项,提取出选项的内容
            choices = choice_pattern.findall(question)
            # 这里提取了题目的内容,因为每个题目都会有一个打分的(X分)这样的标记
            # 以左括号为目标,截取选择题选项中的内容
            question_text = re.split(r'\n', question.split('(')[0])[0]
            
            
            pattern_question = re.compile(r'(\d+)\.(.*)')
            # 这里清洗了选择题的编号,重新用循环中的id进行编号。
            # 如果不做这一步可以发现给定的数据中编号是乱序的。
            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
    1. 抽取问题的结果
def chinese_multiple_choice_answers(questions_with_answers):
   # 首先清洗输入字段,因为答案字段中的格式不统一,清洗后便于统一处理。
   # 这里删除了所有的换行和空格
    questions_with_answers = questions_with_answers.replace(" ", "").replace("\n", "")
    
    # print(questions_with_answers)
    # 使用正则表达式匹配答案
    # 这里我们主要使用第一个匹配 一个数字+点+字母ABCD之间一个
    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
    1. prompt设计
def get_prompt_cn(text):
    prompt = f'''
    你是⼀个⾼考选择题出题专家,你出的题有⼀定深度,你将根据阅读文本,出4道单项选择题,包含题目选项,以及对应的答案,注意:不⽤给出原文,每道题由1个问题和4个选项组成,仅存在1个正确答案,请严格按照要求执行。 阅读文本主要是中文,你出的题目需要满足以下要点,紧扣文章内容且题干和答案为中文:
    
    ### 回答要求
    (1)理解文中重要概念的含义
    (2)理解文中重要句子的含意
    (3)分析论点、论据和论证方法
    
    
    ### 阅读文本
    {text}
    '''
    
    return prompt   
    1. 中文处理主函数
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)
        # 抽取阅读材料组合成input内容
        data_prompt = get_prompt_cn(data_prompt)
        # print(data_options)
        # print(data_answers)
        # 做数据验证,因为训练数据格式不能确定每组数据都能被正常处理(会有一部分处理失败)
        # 我们验证一下两个列表的长度 如果相同代表数据处理正确
        if(len(data_answers)==len(data_options)):
            # 定义output的数据字符串
            res = ''
            # 处理选择题目中的每个数据,逐个拼入到output字符串
            for id_,question in enumerate(data_options):
            # 首先放入题目
                res += f'''
{question['question']}?
                '''+'\n'
                # 然后找到选择题的每个选项,进行choices列表循环
                for choise in question['choices']:
                # 逐个将选项拼接到字符串
                    res = res+ choise[0] + choise[1]+ '\n'
                #  最后将答案拼接到每个选择题的最后
                # 以 答案:题号.选项的格式
                res = res + '答案:' + str(data_answers[id_].split('.')[-1])  + '\n'
            # 最后将处理得到的input、output数据存入到列表
            res_output.append(res)
            res_input.append(data_prompt)
        # break
    return res_input,res_output
 
  1. 英文数据处理

3.1 数据加载

# coding~
 
import pandas as pd
 
# 读取Excel文件
df = pd.read_excel('训练集-英语.xlsx')
# 英文数据处理中有一部分ocr识别的题目,这种题目中看上去是字母A,但是实际为俄文的字母,,
# 所以开始使用全局匹配做了清洗……
df = df.replace('.', '.', regex=True).replace('А.', 'A.', regex=True).replace('В.', 'B.', regex=True).replace('С.', 'C.', regex=True).replace('D.', 'D.', regex=True)
# df = df.replace('(', '(', regex=True)
 
# 读取第二行(即第三行)“选项”列的内容
second_row_option_content = df.loc[0, '选项']
 
# 显示第二行“选项”列的内容
print(second_row_option_content)
    1. 抽取问题
import re
 
# 示例文本
text = second_row_option_content
 
def get_questions(text):
    # 数据清洗,将所有换行改为两个空格方便统一处理
    text = text.replace('\n', '  ')+'  '
    # print(text)
    # 正则表达式模式
    # 通过匹配以数字开头然后带一个点,为题干
    # 然后抽取选项A  以A开头 后面带一个点 最后以两个空格结尾
    # 为什么是两个空格?部分数据换行时为换行符,我们已经换成了两个空格,有些是以多个空格分割,我们默认为两个空格
    # 接着匹配B C D选项内容
    # 最后有一个
    pattern = re.compile(r'(\d+\..*?)(A\..*?\s{2})([B-D]\..*?\s{2})([B-D]\..*?\s{2})(D\..*?\s{2})', re.DOTALL)
 
    # 查找所有匹配项
    matches = pattern.findall(text)
 
    # 存储结果的字典列表
    questions_dict_list = []
 
    # 打印结果
    for match in matches:
        question, option1, option2, option3, option4 = match
        pattern_question = re.compile(r'(\d+)\.(.*)')
        # 第一个为选择题的题目 提前存到question_text 
        question_text = pattern_question.findall(question.strip())[0][1]
        
        # 提取选项字母和内容
        options = {option1[0]: option1, option2[0]: option2, option3[0]: option3, option4[0]: option4}
        
        question_dict = {
            'question': question_text,
            # 这一步就是防止ACBD这种乱序,我们进行重新匹配,将可能是ACBD的数据以首字母按位置排好号
            'options': {
                'A': options.get('A', '').strip(),
                'B': options.get('B', '').strip(),
                'C': options.get('C', '').strip(),
                'D': options.get('D', '').strip()
            }
        }
        
        questions_dict_list.append(question_dict)
    # 最后获得
    return questions_dict_list
 
# 调用函数并打印结果
questions = get_questions(text)
for q in questions:
    print(q)
    1. 抽取问题的结果
# 首先做数据清洗,将空格、换行符及点都删除
def remove_whitespace_and_newlines(input_string):
    # 使用str.replace()方法删除空格和换行符
    result = input_string.replace(" ", "").replace("\n", "").replace(".", "")
    return result
import re
 
# 示例文本
text = """
32. B. The underlying logic of the effect.                                                   33.D. estimates were not fully independent.
34.C. The discussion process.            35.D. Approving.
"""
def get_answers(text):
    text = remove_whitespace_and_newlines(text)
    # 正则表达式模式
    # 这里是一个数字加一个A-D的大写字母表示为答案区域,因为有些答案中有解释,这样的匹配规则可以尽可能匹配到答案
    pattern = re.compile(r'(\d)\s*([A-D])')
 
    # 查找所有匹配项
    matches = pattern.findall(text)
    res = []
    # 打印结果
    for match in matches:
        number_dot, first_letter = match
        res.append(first_letter)
    return res
    1. prompt设计
def get_prompt_en(text):
    prompt = f'''
    你是⼀个⾼考选择题出题专家,你出的题有⼀定深度,你将根据阅读文本,出4道单项选择题,包含题目选项,以及对应的答案,注意:不⽤给出原文,每道题由1个问题和4个选项组成,仅存在1个正确答案,请严格按照要求执行。
The reading text is mainly in English. The questions and answers you raised need to be completed in English for at least the following points:
    
    ### 回答要求
    (1)Understanding the main idea of the main idea.
    (2)Understand the specific information in the text.
    (3)infering the meaning of words and phrases from the context
    
    
    ### 阅读文本
    {text}
    '''
    
    return prompt   
    1. 英文数据处理主函数
def process_en(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 = get_questions(data_options)
        data_answers = get_answers(data_answers)
        data_prompt = get_prompt_en(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'''
                {id+1}.{question['question']}
                {question['options']['A']}
                {question['options']['B']}
                {question['options']['C']}
                {question['options']['D']}
                answer:{data_answers[id]}
                '''+'\n'
            res_output.append(res)
            res_input.append(data_prompt)
    return res_input,res_output
    # break
  1. 数据合并
# 将两个列表转换为DataFrame
 
df_new = pd.DataFrame({'input': cn_input+cn_input[:30]+en_input+en_input[:20], 'output': cn_output+cn_output[:30]+en_output+en_output[:20]})

四、相关学习资料

  1. Python:二次元的Datawhale的个人空间-二次元的Datawhale个人主页-哔哩哔哩视频 (bilibili.com)
  2. Pandas相关知识:https://github.com/datawhalechina/joyful-pandas
  3. 大语言模型知识:

https://github.com/datawhalechina/so-large-lm

https://github.com/datawhalechina/llms-from-scratch-cn

https://github.com/datawhalechina/llm-cookbook

  • 25
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值