文章目录
一.小白零基础30分钟速通
1.报名赛事
2.运行baseline:数据处理
3.模型微调
这部分主要包括四步:数据上传,等待处理,模型训练,模型发布。
4.模型测试
5.提交文件,拿下第一个分数
(1)学习率:0.00008 训练次数:16
(2)学习率:0.00008 训练次数:15

二.baseline1精读
1.数据处理思路介绍
1.1赛题讲解



通过上面的描述我们能看到在图1数据说明及图2提交界面中需要我们进行数据处理,然后进行微调。我们要做的是通过大语言模型,输入阅读材料,阅读材料是高考的语文和英语阅读材料,大模型输出选择题及对应的答案,选择题根据阅读材料进行出题。
好的。我们从微调需要的输入输出两方面来看。也就是图4中的input与traget部分。

1.2 微调数据
1.3 数据处理方案
1.3.1 python正则表达式
正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。
Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。
re 模块使 Python 语言拥有全部的正则表达式功能。
compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。
re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。
本章节主要介绍Python中常用的正则表达式处理函数。
1.3.2 Pandas库
Pandas 是 Python 语言的一个扩展程序库,用于数据分析。
Pandas 名字衍生自术语 “panel data”(面板数据)和 “Python data analysis”(Python 数据分析)。
Pandas 是一个开放源码、BSD 许可的库,提供高性能、易于使用的数据结构和数据分析工具。
Pandas 一个强大的分析结构化数据的工具集,基础是 Numpy(提供高性能的矩阵运算)。
Pandas 可以从各种文件格式比如 CSV、JSON、SQL、Microsoft Excel 导入数据。
Pandas 可以对各种数据进行运算操作,比如归并、再成形、选择,还有数据清洗和数据加工特征。
Pandas 广泛应用在学术、金融、统计学等各个数据分析领域。
1.3.3 处理目标
我们需要将文件中的数据读取出来,将语文数据与英语数据整理好后存储成可以微调的数据格式。可以微调的数据格式我们可以选择csv与jsonl类型。
1.4 处理流程
将语文、英语训练集按照下图结构,选项与答案组成output模块,prompt+阅读文本组成input模块。这样就是我们的处理流程结构啦。

2.微调流程介绍
2.1 大语言模型介绍
大语言模型的概念
大语言模型(英文:Large Language Model,缩写LLM),也称大型语言模型,是一种人工智能模型,旨在理解和生成人类语言。
通常,大语言模型 (LLM) 指包含数十亿(Billion或更多)参数的语言模型,这些模型在大量的文本数据上进行训练,例如国外的有GPT-3 、GPT-4、PaLM 、Galactica 和 LLaMA 等,国内的有ChatGLM、文心一言、通义千问、讯飞星火等。
大模型的能力和特点
- 大模型的能力
大语言模型(LLM)与以前的预训练语言模型(PLM)的主要区别在于其涌现能力。这种能力在小型模型中不明显,但在大型模型中显著。例如:
- 上下文学习:首次由GPT-3引入,允许模型在提供自然语言指令或多个任务示例的情况下,通过理解上下文并生成相应输出来执行任务。
- 指令遵循:通过指令微调,LLM可以根据任务指令执行未见过的任务,展示出强大的泛化能力。
- 逐步推理:通过"思维链(Chain of Thought, CoT)"策略,LLM能够解决多步推理任务,例如数学问题。
- 大模型的特点
-
- 巨大的规模:参数规模达数十亿甚至数千亿,使其能捕捉更多语言知识和复杂语法结构。
- 预训练和微调:在大规模无标签文本数据上预训练,然后通过有标签数据微调,适应特定任务。
- 上下文感知:具备强大的上下文感知能力,能够理解和生成依赖前文的文本内容。
- 多语言支持:支持多种语言,促进跨文化和跨语言的应用。
- 多模态支持:一些LLM支持文本、图像和语音的多模态数据。
- 涌现能力:在大规模模型中表现出明显的性能提升,能处理更复杂的任务。
- 多领域应用:广泛应用于文本生成、自动翻译、信息检索、摘要生成、聊天机器人等多个领域。
- 伦理和风险问题:需要谨慎处理生成有害内容、隐私问题和认知偏差等伦理和风险问题。
2.2 微调介绍
什么是模型微调?
相当于给你一个预训练模型(Pre-trained model),基于这个模型微调(Fine Tune)。
预训练模型就是已经用数据集训练好了的模型。
两种 Finetune 范式
- 增量预训练微调 (Continue PreTraining)
使用场景:让基座模型学习到一些新知识,如某个垂类领域的常识
训练数据:文章、书籍、代码等 - 指令跟随微调 (Supervised Finetuning)
使用场景:让模型学会对话模板,根据人类指令进行对话
训练数据:高质量的对话、问答数据
为什么要微调?
相对于从头开始训练(Training a model from scatch),微调可以省去大量计算资源和计算时间,提高了计算效率,甚至提高准确率。
普通预训练模型的特点是:用了大型数据集做训练,已经具备了提取浅层基础特征和深层抽象特征的能力。
不做微调:
(1)从头开始训练,需要大量的数据,计算时间和计算资源。
(2)存在模型不收敛,参数不够优化,准确率低,模型泛化能力低,容易过拟合等风险。
使用微调:避免了上述可能存在的问题。
什么情况下使用微调?
(1) 你要使用的数据集和预训练模型的数据集相似
如果不太相似,效果可能就没有那么好了,特征提取是不同的,所以相应的参数训练后也是不同的。
(2) 自己搭建或者使用的模型正确率太低。
(3)数据集相似,但数据集数量太少。
(4)计算资源太少。
不同数据集下使用微调
- 数据集1 - 数据量少,但数据相似度非常高在这种情况下,我们所做的只是修改最后几层或最终的softmax图层的输出类别。
- 数据集2 - 数据量少,数据相似度低在这种情况下,我们可以冻结预训练模型的初始层(比如k层),并再次训练剩余的(n-k)层。由于新数据集的相似度较低,因此根据新数据集对较高层进行重新训练具有重要意义。
- 数据集3 - 数据量大,数据相似度低在这种情况下,由于我们有一个大的数据集,我们的神经网络训练将会很有效。但是,由于我们的数据与用于训练我们的预训练模型的数据相比有很大不同。使用预训练模型进行的预测不会有效。因此,最好根据你的数据从头开始训练神经网络(Training from scatch)。
- 数据集4 - 数据量大,数据相似度高这是理想情况。在这种情况下,预训练模型应该是最有效的。使用模型的最好方法是保留模型的体系结构和模型的初始权重。然后,我们可以使用在预先训练的模型中的权重来重新训练该模型。
微调指导事项
1.通常的做法是截断预先训练好的网络的最后一层(softmax层),并用与我们自己的问题相关的新的softmax层替换它。例如,ImageNet上预先训练好的网络带有1000个类别的softmax图层。如果我们的任务是对10个类别的分类,则网络的新softmax层将由10个类别组成,而不是1000个类别。然后,我们在网络上运行预先训练的权重。确保执行交叉验证,以便网络能够很好地推广。
2.使用较小的学习率来训练网络。由于我们预计预先训练的权重相对于随机初始化的权重已经相当不错,我们不想过快地扭曲它们太多。通常的做法是使初始学习率比用于从头开始训练(Training from scratch)的初始学习率小10倍。
- 如果数据集数量过少,我们进来只训练最后一层,如果数据集数量中等,冻结预训练网络的前几层的权重也是一种常见做法。
这是因为前几个图层捕捉了与我们的新问题相关的通用特征,如曲线和边。我们希望保持这些权重不变。相反,我们会让网络专注于学习后续深层中特定于数据集的特征。
LoRA
LoRA是一种高效微调方法,深入了解其原理可参见博客:[知乎|深入浅出Lora]
LoRA的优势
- 可以针对不同的下游任务构建小型 LoRA 模块,从而在共享预训练模型参数基础上有效地切换下游任务。
- LoRA 使用自适应优化器(Adaptive Optimizer),不需要计算梯度或维护大多数参数的优化器状态,训练更有效、硬件门槛更低。
- LoRA 使用简单的线性设计,在部署时将可训练矩阵与冻结权重合并,不存在推理延迟。
- LoRA 与其他方法正交,可以组合。
LoRA的原理
- https://github.com/microsoft/LoRA?tab=readme-ov-file
- https://arxiv.org/pdf/2106.09685
- https://huggingface.co/docs/peft/quicktour
微调处理流程
3.baseline1精讲
3.1 环境准备
相关库的下载与安装
!pip install pandas openpyxl
3.2 语文数据处理
3.2.1 数据加载
这里我们使用pandas加载xlsx中的数据,这里面我们使用全局匹配,将训练集中的中文点与左侧括号匹配为英文类型。
# 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)
3.2.2 抽取问题
这里主要是为了抽取题目及答案,并且过滤简答题。大家可以阅读详细的注释理解问题抽取的函数如何工作。
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
3.2.3 抽取问题的结果
这里我们抽取刚才我们拿到的选择题的答案部分。
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 = {