讲解mindnlp模型微调20250329

先给大家说自己是三维视觉领域

首先讲解mindnlp的组成,训练方法

然后讲解模型任务,模型分为四种

然后讲解微调数据集的选择,微调的两种方法

然后讲解微调数据集的格式

然后讲解PEFT

然后讲解Ascend 910B

看效果

MindNLP

MindNLP是基于MindSpore的一个自然语言处理(NLP)开源库,其中包含了许多自然语言处理的常用方法,提供了一个易用的NLP平台,旨在帮助研究人员和开发者更高效地构建和训练模型。

  • 丰富完备的数据预处理模块
    • 提供丰富的NLP数据处理模块,可灵活高效地完成数据预处理,包括Multi30k、SQuAD、CoNLL等经典数据集。
  • 用户友好的NLP模型工具集
    • 提供多种可配置神经网络组件,易于用户自定义模型,可大幅提升NLP任务建模的效率。
  • 灵活易用的训练与推理引擎
    • 简化了MindSpore中复杂的训练过程,提供了灵活易用的 TrainerEvaluator ,可以轻松地训练和评估模型

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等工具无缝集成

模型

https://mindnlp-ai.readthedocs.io/en/latest/zh/api/transformers/models/blenderbot_small/#mindnlp.transformers.models.blenderbot_small.modeling_blenderbot_small.BlenderbotSmallModel

模型名称 架构类型 输入输出模式 主要用途 适用场景
BlenderbotSmallModel Encoder-Decoder 接受输入,返回未经语言模型头(LM Head)处理的原始隐藏状态 提取文本特征或自定义任务头 研究、特征提取
BlenderbotSmallForConditionalGeneration Encoder-Decoder + LM Head 接受输入,直接生成文本序列(通过 LM Head 解码) 对话生成(如微调 Synthetic-Persona-Chat)。 文本摘要、翻译等需要双向上下文理解的任务。 对话生成、翻译、摘要
BlenderbotSmallForCausalLM Decoder-only 从左到右生成文本(类似 GPT) 开放式文本生成(如故事续写)。 单轮问答、文本补全。 故事续写、文本补全

  1. BlenderbotSmallModel
  • 定位: 基础模型,仅包含编码器(Encoder)和解码器(Decoder)骨架。
  • 输出: 返回未经语言模型头(LM Head)处理的原始隐藏状态。
  • 用途:
    • 研究模型内部机制。
    • 自定义任务头(如分类、检索)。
  1. BlenderbotSmallForConditionalGeneration:
    • 适用场景: 对话生成任务,尤其是需要根据上下文生成连贯回复的场景。
    • 特点: 这是一个条件生成模型,适合处理输入输出对的任务,如对话生成、文本摘要等。
    • 推荐: 如果你的目标是生成对话回复,BlenderbotSmallForConditionalGeneration 是更好的选择。
  2. BlenderbotSmallForCausalLM:
    • 适用场景: 自回归文本生成任务,如故事生成或文本补全。
    • 特点: 这是一个因果语言模型,适合从左到右生成文本,不依赖特定输入条件。
    • 推荐: 如果你的任务是生成连续文本而非对话回复,可以选择 BlenderbotSmallForCausalLM

模型微调方法

微调的一般策略。通常有两种方法:一种是全参数微调,另一种是部分冻结,只训练某些层。

ConditionalGeneration,所以接下来应该是具体的微调步骤。冻结层通常是为了防止过拟合,特别是在数据量较小的情况下,或者保留预训练模型的一些通用特征。Synthetic-Persona-Chat数据集可能是一个对话生成数据集,有足够的数据量。

接下来要考虑BlenderbotSmall的结构。BlenderbotSmall是基于Transformer的模型,包含编码器和解码器。对于生成任务,通常解码器部分更关键,尤其是在生成响应时。用户是否需要冻结前面的权重,可能指的是编码器部分,或者是底层的嵌入层?

一般来说,在微调时,如果数据量不大,冻结部分底层参数可以防止过拟合,同时让模型保留更多的通用语言理解能力。反之,如果数据足够,解冻所有层进行微调可能效果更好。需要询问用户的数据量吗?但用户没有提到,可能需要给出一般性的建议。

然后,关于如何用transformers库冻结参数。通常是通过设置参数的requires_grad为False。例如,遍历模型的参数,对某些层进行冻结。例如,冻结嵌入层、编码器的前几层等。

  • 不冻结(默认推荐):
    • 适用场景: 数据集足够大(与预训练数据分布相似),或需要模型充分适应对话任务。
    • 优点: 模型的所有参数均可更新,能更好地学习对话任务的特性。
    • 缺点: 训练时间较长,显存占用高,可能在小数据集上过拟合。
  • 冻结部分权重:
    • 适用场景: 数据集较小,或希望快速微调、节省资源。
    • 优点: 减少显存占用、加速训练,防止过拟合。
    • 缺点: 可能限制模型对新任务的适应能力。
      1. 轻量级微调:
        • 冻结编码器,仅训练解码器。
        • 适合资源有限或数据集较小的情况。
      2. 平衡策略:
        • 冻结前几层(如编码器的前 3 层),训练深层网络。
        • 保留浅层通用特征,调整深层任务相关特征。
      3. 全参数微调:
        • 不冻结任何参数,直接微调。
        • 适合数据集较大且与预训练任务差异较大的场景。

数据集选择

针对 Synthetic-Persona-Chat 的微调选择推荐模型:BlenderbotSmallForConditionalGeneration

原因:

  1. 任务匹配: 该数据集是 多轮对话,需要模型根据上下文(用户输入 + 角色设定)生成回复,完美契合 Seq2Seq 架构。
  2. 双向上下文: 编码器可捕捉输入对话的全局信息,解码器生成时结合编码器状态和已生成部分。
  3. 性能优势: 在对话任务中,条件生成模型的流畅度和相关性显著优于纯解码器模型。

为什么不选其他模型?

  • BlenderbotSmallModel:
    • 缺少生成头(LM Head),需自行添加生成逻辑,不适合直接微调生成任务。
  • BlenderbotSmallForCausalLM:
    • 仅解码器架构无法有效利用双向上下文,对话生成效果受限。
    • 更适合单轮文本续写,而非多轮交互式对话。

如何调用

如何处理数据集

一个dataset库获得的数据集要用在mindnlp训练中,要经过以下三个步骤:

  1. 将数据集转化为模型需要的格式,如序列生成模型需要对话对格式,序类分类模型需要序列+标签格式
  2. 进行tokenizer
  3. 转化为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分钟)

  1. 环境配置

    • MindNLP安装指南(结合昇腾NPU/GPU版本)
    • 依赖库:mindspore, mindnlp, datasets, peft
  2. 数据准备

    • 数据集示例:DailyDialog(日常对话)、Custom JSON格式数据

    • 数据预处理:

      python

      复制

      1
      2
      def format_dialogue(example):  
      return {"text": f"User: {example['input']}\nBot: {example['output']}"}
    • 数据划分:8:1:1(训练/验证/测试)


三、模型加载与PEFT配置(15分钟)

  1. 加载BlenderBot-Small预训练模型

    • MindNLP代码示例:

      python

      复制

      1
      2
      from mindnlp.models import BlenderbotSmall  
      model = BlenderbotSmall.from_pretrained("blenderbot_small-90M")
  2. 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
      7
      from 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)
  3. 冻结原模型参数

    • 验证参数冻结状态:print_trainable_parameters(model)

四、训练流程与优化技巧(20分钟)

  1. 训练配置

    • 优化器选择:AdamWeightDecay(MindSpore兼容)
    • 学习率设置:5e-4(PEFT通常需更大学习率)
    • Batch Size与梯度累积:根据显存动态调整
  2. 训练代码核心片段

    python

    复制

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from 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()
  3. 性能监控与调试

    • 使用MindInsight可视化训练曲线(Loss/Perplexity)
    • 常见问题:
      • 显存不足:启用梯度检查点(gradient_checkpointing=True
      • 收敛慢:检查学习率与参数是否解冻