20250329陕师大讲解mindnlp模型微调
讲解mindnlp模型微调20250329
先给大家说自己是三维视觉领域
首先讲解mindnlp的组成,训练方法
然后讲解模型任务,模型分为四种
然后讲解微调数据集的选择,微调的两种方法
然后讲解微调数据集的格式
然后讲解PEFT
然后讲解Ascend 910B
看效果
MindNLP
MindNLP是基于MindSpore的一个自然语言处理(NLP)开源库,其中包含了许多自然语言处理的常用方法,提供了一个易用的NLP平台,旨在帮助研究人员和开发者更高效地构建和训练模型。
- 丰富完备的数据预处理模块
- 提供丰富的NLP数据处理模块,可灵活高效地完成数据预处理,包括Multi30k、SQuAD、CoNLL等经典数据集。
- 用户友好的NLP模型工具集
- 提供多种可配置神经网络组件,易于用户自定义模型,可大幅提升NLP任务建模的效率。
- 灵活易用的训练与推理引擎
- 简化了MindSpore中复杂的训练过程,提供了灵活易用的
Trainer
和Evaluator
,可以轻松地训练和评估模型
- 简化了MindSpore中复杂的训练过程,提供了灵活易用的
MindNLP
- 华为昇思MindSpore生态下的开源NLP库
- 专为MindSpore框架优化设计
- 充分利用其自动并行、动静态图统一等特性
- 特别针对华为昇腾芯片优化
- 全面适配Hugging Face主要开发库(如Transformers、Peft、Trl),可直接使用datasets库,保持与Hugging Face生态的一致性
Transformers
-
由Hugging Face开发维护,已成为全球最流行的NLP开源库之一。
-
支持PyTorch、TensorFlow和JAX等多种深度学习框架
-
框架无关设计,原生支持PyTorch、TensorFlow,通过适配层也可支持其他框架如JAX
-
它提供了数万个预训练模型
-
作为Hugging Face生态核心,与Model Hub、Datasets、Evaluate、Gradio等工具无缝集成
模型
模型名称 | 架构类型 | 输入输出模式 | 主要用途 | 适用场景 |
---|---|---|---|---|
BlenderbotSmallModel |
Encoder-Decoder | 接受输入,返回未经语言模型头(LM Head)处理的原始隐藏状态 | 提取文本特征或自定义任务头 | 研究、特征提取 |
BlenderbotSmallForConditionalGeneration |
Encoder-Decoder + LM Head | 接受输入,直接生成文本序列(通过 LM Head 解码) |
对话生成(如微调 Synthetic-Persona-Chat )。 文本摘要、翻译等需要双向上下文理解的任务。 |
对话生成、翻译、摘要 |
BlenderbotSmallForCausalLM |
Decoder-only | 从左到右生成文本(类似 GPT) | 开放式文本生成(如故事续写)。 单轮问答、文本补全。 | 故事续写、文本补全 |
- BlenderbotSmallModel
- 定位: 基础模型,仅包含编码器(Encoder)和解码器(Decoder)骨架。
- 输出: 返回未经语言模型头(LM Head)处理的原始隐藏状态。
- 用途:
- 研究模型内部机制。
- 自定义任务头(如分类、检索)。
- BlenderbotSmallForConditionalGeneration:
- 适用场景: 对话生成任务,尤其是需要根据上下文生成连贯回复的场景。
- 特点: 这是一个条件生成模型,适合处理输入输出对的任务,如对话生成、文本摘要等。
- 推荐: 如果你的目标是生成对话回复,
BlenderbotSmallForConditionalGeneration
是更好的选择。
- BlenderbotSmallForCausalLM:
- 适用场景: 自回归文本生成任务,如故事生成或文本补全。
- 特点: 这是一个因果语言模型,适合从左到右生成文本,不依赖特定输入条件。
- 推荐: 如果你的任务是生成连续文本而非对话回复,可以选择
BlenderbotSmallForCausalLM
。
模型微调方法
微调的一般策略。通常有两种方法:一种是全参数微调,另一种是部分冻结,只训练某些层。
ConditionalGeneration,所以接下来应该是具体的微调步骤。冻结层通常是为了防止过拟合,特别是在数据量较小的情况下,或者保留预训练模型的一些通用特征。Synthetic-Persona-Chat数据集可能是一个对话生成数据集,有足够的数据量。
接下来要考虑BlenderbotSmall的结构。BlenderbotSmall是基于Transformer的模型,包含编码器和解码器。对于生成任务,通常解码器部分更关键,尤其是在生成响应时。用户是否需要冻结前面的权重,可能指的是编码器部分,或者是底层的嵌入层?
一般来说,在微调时,如果数据量不大,冻结部分底层参数可以防止过拟合,同时让模型保留更多的通用语言理解能力。反之,如果数据足够,解冻所有层进行微调可能效果更好。需要询问用户的数据量吗?但用户没有提到,可能需要给出一般性的建议。
然后,关于如何用transformers库冻结参数。通常是通过设置参数的requires_grad为False。例如,遍历模型的参数,对某些层进行冻结。例如,冻结嵌入层、编码器的前几层等。
- 不冻结(默认推荐):
- 适用场景: 数据集足够大(与预训练数据分布相似),或需要模型充分适应对话任务。
- 优点: 模型的所有参数均可更新,能更好地学习对话任务的特性。
- 缺点: 训练时间较长,显存占用高,可能在小数据集上过拟合。
- 冻结部分权重:
- 适用场景: 数据集较小,或希望快速微调、节省资源。
- 优点: 减少显存占用、加速训练,防止过拟合。
- 缺点: 可能限制模型对新任务的适应能力。
-
- 轻量级微调:
- 冻结编码器,仅训练解码器。
- 适合资源有限或数据集较小的情况。
- 平衡策略:
- 冻结前几层(如编码器的前 3 层),训练深层网络。
- 保留浅层通用特征,调整深层任务相关特征。
- 全参数微调:
- 不冻结任何参数,直接微调。
- 适合数据集较大且与预训练任务差异较大的场景。
- 轻量级微调:
数据集选择
针对 Synthetic-Persona-Chat
的微调选择推荐模型:BlenderbotSmallForConditionalGeneration
原因:
- 任务匹配: 该数据集是 多轮对话,需要模型根据上下文(用户输入 + 角色设定)生成回复,完美契合 Seq2Seq 架构。
- 双向上下文: 编码器可捕捉输入对话的全局信息,解码器生成时结合编码器状态和已生成部分。
- 性能优势: 在对话任务中,条件生成模型的流畅度和相关性显著优于纯解码器模型。
为什么不选其他模型?
BlenderbotSmallModel
:- 缺少生成头(LM Head),需自行添加生成逻辑,不适合直接微调生成任务。
BlenderbotSmallForCausalLM
:- 仅解码器架构无法有效利用双向上下文,对话生成效果受限。
- 更适合单轮文本续写,而非多轮交互式对话。
如何调用
如何处理数据集
一个dataset库获得的数据集要用在mindnlp训练中,要经过以下三个步骤:
- 将数据集转化为模型需要的格式,如序列生成模型需要对话对格式,序类分类模型需要序列+标签格式
- 进行tokenizer
- 转化为mindnlp可以直接使用的mindspore.dataset格式
给一个huggingface的图
数据集的目标结构:对话形式
BlenderbotSmall 是专为 多轮对话生成 设计的模型,因此数据集需要以 对话对(Context-Response Pairs) 为核心。具体来说,每条样本应包含:
-
输入(Context):对话历史(多轮上下文)。
-
目标输出(Target Response):模型需要生成的回复。
-
单轮对话(简单场景)
1
2
3
4# 输入(上下文)
"Hi, how are you?"
# 目标输出(回复)
"I'm good, thanks! How about you?"多轮对话(更常见)
1
2
3
4# 输入(上下文)
"User: Hi, what's your favorite movie? \nBot: I like science fiction. \nUser: Why?"
# 目标输出(回复)
"Because it explores futuristic ideas."带有角色设定(Persona)的对话
如果数据集包含角色信息(如
Synthetic-Persona-Chat
),需要在输入中显式添加角色描述:1
2
3
4# 输入(上下文)
"Persona: I am a robot. I love reading books. \nUser: What do you do for fun?"
# 目标输出(回复)
"I enjoy reading books, especially science fiction."
print(“dataset:”, dataset)
dataset: DatasetDict({
train: Dataset({
features: [‘user 1 personas’, ‘user 2 personas’, ‘Best Generated Conversation’],
num_rows: 8938
})
validation: Dataset({
features: [‘user 1 personas’, ‘user 2 personas’, ‘Best Generated Conversation’],
num_rows: 1000
})
test: Dataset({
features: [‘user 1 personas’, ‘user 2 personas’, ‘Best Generated Conversation’],
num_rows: 968
})
})
dataset_train = dataset[“train”]
print(“dataset_train:”, dataset_train)
dataset_train: Dataset({
features: [‘user 1 personas’, ‘user 2 personas’, ‘Best Generated Conversation’],
num_rows: 8938
})
print(“dataset_train[‘Best Generated Conversation’][0]:\n”, dataset_train[“Best Generated Conversation”][0])
dataset_train[‘Best Generated Conversation’][0]:
User 1: Hi! I’m [user 1’s name].
User 2: Hi [user 1’s name], I’m [user 2’s name].
User 1: What do you do for fun?
User 2: I like to play video games, go to the beach, and read.
User 1: I like to play video games too! I’m not much of a reader, though.
User 2: What video games do you like to play?
User 1: I like to play a lot of different games, but I’m really into competitive online games right now.
User 2: I’m not really into competitive games, I like to play more relaxing games.
User 1: That’s cool. What kind of relaxing games do you like to play?
User 2: I like to play puzzle games, simulation games, and story-based games.
User 1: I’ve never been much of a puzzle game person, but I do like simulation games and story-based games.
User 2: Nice! What’s your favorite simulation game?
User 1: I like Stardew Valley a lot. It’s a farming game, but it’s also really relaxing and fun.
User 2: I’ve heard good things about that game. I might have to check it out.
User 1: You should! It’s a lot of fun.
User 2: Well, I’m glad we met. Maybe we can play some games together sometime.
User 1: That would be fun!
User 2: Great! I’ll send you my Steam name.
User 1: Ok, sounds good.
print(“dataset_train[‘user 1 personas’][0]:”, dataset_train[“user 1 personas”][0])
dataset_train[‘user 1 personas’][0]: I am 32.
I do not want a job.
I play video games all day.
I still live at home with my parents.
print(“dataset_train[‘user 2 personas’][0]:”, dataset_train[“user 2 personas”][0])
dataset_train[‘user 2 personas’][0]: My favorite drink is iced coffee.
I have a black belt in karate.
I m in a jazz band and play the saxophone.
I vacation along lake michigan every summer.
tokenizer
def tokenize_function(examples):
model_inputs = tokenizer(
examples[“input”],
max_length=128,
truncation=True,
padding=“max_length”,
)
with tokenizer.as_target_tokenizer():
labels = tokenizer(
examples[“target”],
max_length=128,
truncation=True,
padding=“max_length”,
)
model_inputs[“labels”] = labels[“input_ids”]#获得"labels" “input_ids” “attention_mask”。通过查阅forward函数,label要改名labels
return model_inputs
dataset_train_tokenized = dataset_train_tokenized.map(tokenize_function, batched=True)
转化为mingnlp格式
import mindspore.dataset as ds
def data_generator(dataset):
for item in dataset:
yield item[“input_ids”], item[“attention_mask”], item[“labels”]
import mindspore.dataset as ds
# 将训练集和验证集转换为 MindSpore 数据集,注意forward函数中label要改成labels
def create_mindspore_dataset(dataset, shuffle=True):
return ds.GeneratorDataset(
source=lambda: data_generator(dataset), # 使用 lambda 包装生成器
column_names=[“input_ids”, “attention_mask”, “labels”],
shuffle=shuffle
)
dataset_train_tokenized = create_mindspore_dataset(dataset_train_tokenized, shuffle=True)
二、环境准备与数据说明(10分钟)
-
环境配置
- MindNLP安装指南(结合昇腾NPU/GPU版本)
- 依赖库:mindspore, mindnlp, datasets, peft
-
数据准备
-
数据集示例:DailyDialog(日常对话)、Custom JSON格式数据
-
数据预处理:
python
复制
1
2def format_dialogue(example):
return {"text": f"User: {example['input']}\nBot: {example['output']}"} -
数据划分:8:1:1(训练/验证/测试)
-
三、模型加载与PEFT配置(15分钟)
-
加载BlenderBot-Small预训练模型
-
MindNLP代码示例:
python
复制
1
2from mindnlp.models import BlenderbotSmall
model = BlenderbotSmall.from_pretrained("blenderbot_small-90M")
-
-
PEFT参数注入(以LoRA为例)
-
关键参数解析(衔接前序PEFT知识):
target_modules=["q_proj", "v_proj"]
(选择注意力层)r=8, lora_alpha=32
(平衡参数量与效果)lora_dropout=0.1
(防止小数据过拟合)
-
代码实现:
python
复制
1
2
3
4
5
6
7from peft import LoraConfig, get_peft_model
peft_config = LoraConfig(
r=8, lora_alpha=32,
target_modules=["q_proj", "v_proj"],
lora_dropout=0.1
)
model = get_peft_model(model, peft_config)
-
-
冻结原模型参数
- 验证参数冻结状态:
print_trainable_parameters(model)
- 验证参数冻结状态:
四、训练流程与优化技巧(20分钟)
-
训练配置
- 优化器选择:
AdamWeightDecay
(MindSpore兼容) - 学习率设置:
5e-4
(PEFT通常需更大学习率) - Batch Size与梯度累积:根据显存动态调整
- 优化器选择:
-
训练代码核心片段
python
复制
1
2
3
4
5
6
7
8
9
10
11
12
13
14from mindnlp.engine import Trainer, TrainingArguments
training_args = TrainingArguments(
output_dir="./results",
per_device_train_batch_size=4,
num_train_epochs=3,
learning_rate=5e-4,
logging_steps=50
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset
)
trainer.train() -
性能监控与调试
- 使用MindInsight可视化训练曲线(Loss/Perplexity)
- 常见问题:
- 显存不足:启用梯度检查点(
gradient_checkpointing=True
) - 收敛慢:检查学习率与参数是否解冻
- 显存不足:启用梯度检查点(