12 对话模型微调2

1 P-Tuning

P-Tuning 是在 Prompt-Tuning的基础上,通过新增 LSTM 或 MLP 编码模块来加速模型的收敛;

之前的实验也看到了使用prompt训练速度很慢,那么P-Tuning呢

参数占比:

trainable params: 5,267,456 || all params: 1,308,379,136 || trainable%: 0.4026

1.1 代码部分

PromptEncoderConfig:

PromptEncoderConfig 类通常包含了以下配置项:

  1. Prompt Length:提示向量的长度,即提示向量中包含的token数量。
  2. Embedding Dimension:提示向量的嵌入维度,通常与预训练模型的隐藏层维度相同。
  3. Initialization Method:提示向量的初始化方法,可以是随机初始化或其他预定义的方式。
  4. Trainable Parameters:哪些参数是可训练的,例如提示向量本身是否可训练。
  5. Additional Layers:是否添加额外的层来进一步处理提示向量,例如线性层、LSTM层等。

示例代码

from datasets import Dataset
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, DataCollatorForSeq2Seq, TrainingArguments, Trainer

ds = Dataset.load_from_disk("../data/")
tokenizer = AutoTokenizer.from_pretrained("../bloom-model/")
def process_func(example):
    MAX_LENGTH = 256
    input_ids, attention_mask, labels = [], [], []
    instruction = tokenizer("\n".join(["Human: " + example["instruction"], example["input"]]).strip() + "\n\nAssistant: ")
    response = tokenizer(example["output"] + tokenizer.eos_token)
    input_ids = instruction["input_ids"] + response["input_ids"]
    attention_mask = instruction["attention_mask"] + response["attention_mask"]
    labels = [-100] * len(instruction["input_ids"]) + response["input_ids"]
    if len(input_ids) > MAX_LENGTH:
        input_ids = input_ids[:MAX_LENGTH]
        attention_mask = attention_mask[:MAX_LENGTH]
        labels = labels[:MAX_LENGTH]
    return {
        "input_ids": input_ids,
        "attention_mask": attention_mask,
        "labels": labels
    }

tokenized_ds = ds.map(process_func, remove_columns=ds.column_names)

from transformers import DataCollatorWithPadding
from transformers.trainer_callback import TrainerCallback
import matplotlib.pyplot as plt

from peft import PromptEncoderConfig, TaskType, get_peft_model, PromptEncoderReparameterizationType

config = PromptEncoderConfig(task_type=TaskType.CAUSAL_LM, num_virtual_tokens=10,
                             encoder_reparameterization_type=PromptEncoderReparameterizationType.MLP,
                             encoder_dropout=0.1, encoder_num_layers=5, encoder_hidden_size=1024)
config

# 自定义回调类,用于在训练过程中打印损失
model = AutoModelForCausalLM.from_pretrained("../bloom-model/")
model = get_peft_model(model, config)
print(model.print_trainable_parameters())


class PrintLossCallback(TrainerCallback):
    
    def __init__(self):
        self.losses = []
        self.steps = []

    def on_log(self, args, state, control, logs=None, **kwargs):
        # 打印训练过程中的日志信息
        try:
            if logs is not None:
                print(f"Step {state.global_step}: Loss={logs['loss']:.4f}, Learning Rate={logs['learning_rate']:.6f}")
                self.losses.append(logs['loss'])
                self.steps.append(state.global_step)

        except Exception as e :
            print(f'on_log error {e}')
    
    def plot_losses(self):
        plt.figure(figsize=(10, 5))
        plt.plot(self.steps, self.losses, label='Training Loss')
        plt.xlabel('Steps')
        plt.ylabel('Loss')
        plt.title('Training Loss Over Time')
        plt.legend()
        plt.show()
        

args = TrainingArguments(
    output_dir="./chatbot_ptune",
    per_device_train_batch_size=8,
    gradient_accumulation_steps=8,
    logging_steps=10,
    num_train_epochs=1,
    save_steps=100,
)
plot_losses_callback = PrintLossCallback()
trainer = Trainer(
    model=model,
    args=args,
    tokenizer=tokenizer,
    train_dataset=tokenized_ds,
    data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
    callbacks=[plot_losses_callback]  # 注册自定义回调
)



if torch.cuda.is_available():
    trainer.model = trainer.model.to("cuda")
# 训练模型
trainer.train()

|----------------------------------------------------------------------------|----------------------------------------------------------------------------|
| | |

推理:

from peft import PeftModel
# 在一个jupyter文件中,如果前面已经加载了模型,并对模型做了一定修改,则需要重新加载原始模型
model = AutoModelForCausalLM.from_pretrained("../bloom-model/")
peft_model = PeftModel.from_pretrained(model=model, model_id="./chatbot_ptune/")

peft_model = peft_model.cuda()
ipt = tokenizer("Human: {}\n{}".format("考试有哪些技巧?", "").strip() + "\n\nAssistant: ", return_tensors="pt").to(peft_model.device)
print(tokenizer.decode(peft_model.generate(**ipt, max_length=128,
                                           do_sample=True)[0], 
                       skip_special_tokens=True))

可能没有有关作弊的语料。

整体上效果也不咋滴!

2 Lora

2.1 算法思想

LoRA 的思想很简单:

  • 在原始 PLM (Pre-trained Language Model) 旁边增加一个旁路,做一个降维再升维的操作,来模拟所谓的intrinsic rank
  • 训练的时候固定 PLM 的参数,只训练降维矩阵 A 与升维矩阵 B 。而模型的输入输出维度不变,输出时将 BA 与 PLM 的参数叠加。
  • 用随机高斯分布初始化 A ,用 0 矩阵初始化 B ,保证训练的开始此旁路矩阵依然是 0 矩阵。

在LoRA中,降维矩阵A和升维矩阵B的初始化方式是有特定原因的。降维矩阵A使用随机高斯分布初始化,是为了保持模型的表达能力。高斯分布的随机初始化可以帮助模型在训练初期快速学习到有效的特征表示,从而提高模型的性能。而升维矩阵B使用0矩阵初始化,是为了减少对原始模型参数的影响。 将B初始化为0矩阵,使得在训练初期,模型仍然保持原始预训练参数的输出,从而保证了模型在微调初期的稳定性。**如果将A和B都用0矩阵初始化,那么在训练初期,模型将无法学习到有效的特征表示,导致微调效果不佳。如果A用0矩阵初始化,B用随机高斯分布初始化,那么在训练初期,模型可能会受到B矩阵的干扰,导致训练过程不稳定,甚至可能损害模型的性能。总之,LoRA中降维矩阵A和升维矩阵B的初始化方式是为了保持模型的表达能力,同时减少对原始模型参数的影响,**从而提高微调的效率和稳定性。在实际应用中,可以根据具体任务和模型需求,对初始化方式进行适当调整。

2.2 参数

peft_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM, 
    inference_mode=False, 
    r=8, 
    lora_alpha=32, 
    lora_dropout=0.1
)

参数说明:

  • task_type:指定任务类型。如:条件生成任务(SEQ_2_SEQ_LM),因果语言建模(CAUSAL_LM)等。
  • inference_mode:是否在推理模式下使用Peft模型。
  • r: LoRA低秩矩阵的维数。关于秩的选择,通常,使用4,8,16即可。
  • lora_alpha: LoRA低秩矩阵的缩放系数,为一个常数超参,调整alpha与调整学习率类似。缩放系数(通常标记为α,alpha)就是用来控制LoRA层输出的缩放程度,从而影响最终叠加到原有模型权重上的更新量。++可以把 α 值设置成 rank 值的两倍;++
  • lora_dropout:LoRA 层的丢弃(dropout)率,取值范围为[0, 1)
  • target_modules:要替换为 LoRA 的模块名称列表或模块名称的正则表达式。针对不同类型的模型,模块名称不一样,因此,我们需要根据具体的模型进行设置,比如,LLaMa的默认模块名为[q_proj, v_proj],我们也可以自行指定为:[q_proj,k_proj,v_proj,o_proj]。 在 PEFT 中支持的模型默认的模块名如下所示:
  TRANSFORMERS_MODELS_TO_LORA_TARGET_MODULES_MAPPING = {
      "t5": ["q", "v"],
      "mt5": ["q", "v"],
      "bart": ["q_proj", "v_proj"],
      "gpt2": ["c_attn"],
      "bloom": ["query_key_value"],
      "blip-2": ["q", "v", "q_proj", "v_proj"],
      "opt": ["q_proj", "v_proj"],
      "gptj": ["q_proj", "v_proj"],
      "gpt_neox": ["query_key_value"],
      "gpt_neo": ["q_proj", "v_proj"],
      "bert": ["query", "value"],
      "roberta": ["query", "value"],
      "xlm-roberta": ["query", "value"],
      "electra": ["query", "value"],
      "deberta-v2": ["query_proj", "value_proj"],
      "deberta": ["in_proj"],
      "layoutlm": ["query", "value"],
      "llama": ["q_proj", "v_proj"],
      "chatglm": ["query_key_value"],
      "gpt_bigcode": ["c_attn"],
      "mpt": ["Wqkv"],
  }

from datasets import Dataset
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, DataCollatorForSeq2Seq, TrainingArguments, Trainer

ds = Dataset.load_from_disk("../data/")
tokenizer = AutoTokenizer.from_pretrained("../bloom-model/")
def process_func(example):
    MAX_LENGTH = 256
    input_ids, attention_mask, labels = [], [], []
    instruction = tokenizer("\n".join(["Human: " + example["instruction"], example["input"]]).strip() + "\n\nAssistant: ")
    response = tokenizer(example["output"] + tokenizer.eos_token)
    input_ids = instruction["input_ids"] + response["input_ids"]
    attention_mask = instruction["attention_mask"] + response["attention_mask"]
    labels = [-100] * len(instruction["input_ids"]) + response["input_ids"]
    if len(input_ids) > MAX_LENGTH:
        input_ids = input_ids[:MAX_LENGTH]
        attention_mask = attention_mask[:MAX_LENGTH]
        labels = labels[:MAX_LENGTH]
    return {
        "input_ids": input_ids,
        "attention_mask": attention_mask,
        "labels": labels
    }

tokenized_ds = ds.map(process_func, remove_columns=ds.column_names)


from transformers import DataCollatorWithPadding
from transformers.trainer_callback import TrainerCallback
import matplotlib.pyplot as plt

from peft import LoraConfig, TaskType, get_peft_model

config = LoraConfig(task_type=TaskType.CAUSAL_LM, 
                    target_modules=".*\.1.*query_key_value", 
                    modules_to_save=["word_embeddings"])
config

# 自定义回调类,用于在训练过程中打印损失
model = AutoModelForCausalLM.from_pretrained("../bloom-model/")
model = get_peft_model(model, config)
print(model.print_trainable_parameters())


class PrintLossCallback(TrainerCallback):
    
    def __init__(self):
        self.losses = []
        self.steps = []

    def on_log(self, args, state, control, logs=None, **kwargs):
        # 打印训练过程中的日志信息
        try:
            if logs is not None:
                print(f"Step {state.global_step}: Loss={logs['loss']:.4f}, Learning Rate={logs['learning_rate']:.6f}")
                self.losses.append(logs['loss'])
                self.steps.append(state.global_step)

        except Exception as e :
            print(f'on_log error {e}')
    
    def plot_losses(self):
        plt.figure(figsize=(10, 5))
        plt.plot(self.steps, self.losses, label='Training Loss')
        plt.xlabel('Steps')
        plt.ylabel('Loss')
        plt.title('Training Loss Over Time')
        plt.legend()
        plt.show()
        

args = TrainingArguments(
    output_dir="./chatbot_ptune",
    per_device_train_batch_size=8,
    gradient_accumulation_steps=8,
    logging_steps=10,
    num_train_epochs=1,
    save_steps=1000,
)
plot_losses_callback = PrintLossCallback()
trainer = Trainer(
    model=model,
    args=args,
    tokenizer=tokenizer,
    train_dataset=tokenized_ds,
    data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
    callbacks=[plot_losses_callback]  # 注册自定义回调
)



if torch.cuda.is_available():
    trainer.model = trainer.model.to("cuda")
# 训练模型
trainer.train()

效果还一般般!但是从损失曲线图来看要稳定一些。

相关推荐
baiduopenmap6 分钟前
百度世界2024精选公开课:基于地图智能体的导航出行AI应用创新实践
前端·人工智能·百度地图
小任同学Alex9 分钟前
浦语提示词工程实践(LangGPT版,服务器上部署internlm2-chat-1_8b,踩坑很多才完成的详细教程,)
人工智能·自然语言处理·大模型
新加坡内哥谈技术15 分钟前
微软 Ignite 2024 大会
人工智能
江瀚视野42 分钟前
Q3净利增长超预期,文心大模型调用量大增,百度未来如何分析?
人工智能
陪学1 小时前
百度遭初创企业指控抄袭,维权还是碰瓷?
人工智能·百度·面试·职场和发展·产品运营
QCN_1 小时前
湘潭大学人工智能考试复习1(软件工程)
人工智能
Landy_Jay1 小时前
深度学习:GPT-1的MindSpore实践
人工智能·gpt·深度学习
白光白光1 小时前
量子神经网络
人工智能·深度学习·神经网络
全域观察1 小时前
如何复制只读模式下的腾讯文档
人工智能·新媒体运营·媒体·内容运营·程序员创富
panpantt3211 小时前
【参会邀请】第二届大数据与数据挖掘国际会议(BDDM 2024)邀您相聚江城!
大数据·人工智能·数据挖掘