随着,ChatGPT 敏捷爆火,引发了大模型的时代革新。但是关于一般群众来说,进行大模型的预练习或者全量微调遥不可及。由此,催生了各种参数高效微调技能,让科研人员或者一般开发者有时机测验微调大模型。

因此,该技能值得咱们进行深入分析其背面的机理,之前共享了大模型参数高效微调技能原理总述的文章。下面给大家共享大模型参数高效微调技能实战系列文章,该系列共六篇文章,相关代码均放置在GitHub:llm-action。

  • 大模型参数高效微调技能实战(一)-PEFT概述及环境搭建
  • 大模型参数高效微调技能实战(二)-Prompt Tuning
  • 大模型参数高效微调技能实战(三)-P-Tuning
  • 大模型参数高效微调技能实战(四)-Prefix Tuning / P-Tuning v2
  • 大模型参数高效微调技能实战(五)-LoRA
  • 大模型参数高效微调技能实战(六)-IA3

本文为大模型参数高效微调技能实战的第六篇。下面将对(IA)3(IA)^3的进行解说,为了便于书写,后边统一运用IA3来表示(IA)3(IA)^3

IA3 简述

IA3(论文:Few-Shot Parameter-Efficient Fine-Tuning is Better and Cheaper than In-Context Learning),经过学习向量来对激活层加权进行缩放,从而取得更强的功能,一起仅引入相对少数的新参数,如下图左边所示,它的诞生背景是为了改进 LoRA。

大模型参数高效微调技术实战(六)-IA3

为了使微调更有用,IA3(经过抑制和扩大内部激活注入适配器)运用学习向量重新调整内部激活。 这些学习到的向量被注入到典型的基于transformer的架构中的attention和feedforward模块中。 原始权重坚持冻住,这些学习到的向量是微调期间唯一可练习的参数。 与学习 LoRA 更新低秩权重矩阵不同,处理学习向量能够使可练习参数的数量少得多。

与 LoRA 相似,IA3 具有许多相同的长处:

  • IA3 经过大幅削减可练习参数的数量,使微调愈加高效。关于 T0 模型,运用 IA3 只要大约 0.01% 的可练习参数,而运用 LoRA 有 > 0.1% 的可练习参数。
  • 原始的预练习权重坚持冻住状况,这意味着您能够具有多个轻量级、便携式 IA3 模型,用于在其之上构建的各种下流使命。
  • 运用 IA3 微调的模型的功能与完全微调的模型的功能相当。
  • IA3 不会增加任何推理推迟,因为适配器(adapter)权重能够与根底模型合并。

原则上,IA3 能够应用于神经网络中权重矩阵的任何子集,以削减可练习参数的数量。 依据作者的实现,IA3 权重被添加到 Transformer 模型的 key, value 和 feedforward 层。 给定注入 IA3 参数的目标层,可练习参数的数量能够依据权重矩阵的巨细确定。

IA3 微调实战

与 PEFT 支撑的其他办法相同,要运用 IA3 微调模型,您只需要以下几步:

  • 实例化根本模型。
  • 创建一个配置 (IA3Config),在其间界说 IA3 特定的参数。
  • 运用 get_peft_model() 包装根底模型以取得可练习的 PeftModel。
  • 像往常练习根底模型相同练习 PeftModel。

为了不影响阅读体会,详细的代码放置在GitHub:llm-action 项目中 peft_ia3_clm.ipynb文件,这里仅列出关键步骤。

第一步,引入必要的库,如:IA3 配置类 IA3Config

from peft import get_peft_config, get_peft_model, get_peft_model_state_dict, IA3Config, TaskType

第二步,创建 IA3 微调办法对应的配置。

peft_config = IA3Config(task_type=TaskType.CAUSAL_LM,
                        target_modules=["query_key_value", "mlp.dense_4h_to_h"],
                        inference_mode=False, 
                        feedforward_modules=["mlp.dense_4h_to_h"])

参数说明:

  • task_type:指定使命类型。如:条件生成使命(SEQ_2_SEQ_LM),因果言语建模(CAUSAL_LM)等。
  • inference_mode:是否在推理形式下运用Peft模型。
  • target_modules:要替换为 IA3 的模块称号列表或模块称号的正则表达式,例如,留意力块。在 PEFT 中支撑的模型中默许的模块名如下所示:
TRANSFORMERS_MODELS_TO_IA3_TARGET_MODULES_MAPPING = {
    "t5": ["k", "v", "wo"],
    "mt5": ["k", "v", "wi_1"],
    "gpt2": ["c_attn", "mlp.c_proj"],
    "bloom": ["query_key_value", "mlp.dense_4h_to_h"],
    "roberta": ["key", "value", "output.dense"],
    "opt": ["q_proj", "k_proj", "fc2"],
    "gptj": ["q_proj", "v_proj", "fc_out"],
    "gpt_neox": ["query_key_value", "dense_4h_to_h"],
    "gpt_neo": ["q_proj", "v_proj", "c_proj"],
    "bart": ["q_proj", "v_proj", "fc2"],
    "gpt_bigcode": ["c_attn", "mlp.c_proj"],
    "llama": ["k_proj", "v_proj", "down_proj"],
    "bert": ["key", "value", "output.dense"],
    "deberta-v2": ["key_proj", "value_proj", "output.dense"],
    "deberta": ["in_proj", "output.dense"],
}
  • feedforward_modules:target_modules 中被视为前馈(feedforward)层的模块称号列表或模块称号的正则表达式。虽然学习向量与留意力块的输出激活相乘,但向量与经典前馈层的输入相乘。在 PEFT 中支撑的模型中默许的前馈层模块名如下所示:
TRANSFORMERS_MODELS_TO_IA3_FEEDFORWARD_MODULES_MAPPING = {
    "t5": ["wo"],
    "mt5": [],
    "gpt2": ["mlp.c_proj"],
    "bloom": ["mlp.dense_4h_to_h"],
    "roberta": ["output.dense"],
    "opt": ["fc2"],
    "gptj": ["fc_out"],
    "gpt_neox": ["dense_4h_to_h"],
    "gpt_neo": ["c_proj"],
    "bart": ["fc2"],
    "gpt_bigcode": ["mlp.c_proj"],
    "llama": ["down_proj"],
    "bert": ["output.dense"],
    "deberta-v2": ["output.dense"],
    "deberta": ["output.dense"],
}
  • module_to_save:除了 IA3 层之外要设置为可练习并保存在终究查看点中的模块列表。这些一般包括模型的自界说头(head),该头是为微调使命随机初始化的。例如,在序列分类或Token分类使命中,最终一层classifier/score是随机初始化的,因此需要可练习和保存。

第三步,经过调用get_peft_model办法包装根底的 Transformer 模型。

model = AutoModelForCausalLM.from_pretrained(model_name_or_path)
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()

经过 print_trainable_parameters 办法能够查看到 IA3 可练习参数的数量(仅为172,032)以及占比(仅为0.0307%)。

trainable params: 172,032 || all params: 559,386,624 || trainable%: 0.0307536849504646

IA3 模型类结构如下所示:

PeftModelForCausalLM(
  (base_model): IA3Model(
    (model): BloomForCausalLM(
      (transformer): BloomModel(
        (word_embeddings): Embedding(250880, 1024)
        (word_embeddings_layernorm): LayerNorm((1024,), eps=1e-05, elementwise_affine=True)
        (h): ModuleList(
          (0): BloomBlock(
            (input_layernorm): LayerNorm((1024,), eps=1e-05, elementwise_affine=True)
            (self_attention): BloomAttention(
              (query_key_value): Linear(
                in_features=1024, out_features=3072, bias=True
                (ia3_l): ParameterDict(  (default): Parameter containing: [torch.FloatTensor of size 3072x1])
              )
              (dense): Linear(in_features=1024, out_features=1024, bias=True)
              (attention_dropout): Dropout(p=0.0, inplace=False)
            )
            (post_attention_layernorm): LayerNorm((1024,), eps=1e-05, elementwise_affine=True)
            (mlp): BloomMLP(
              (dense_h_to_4h): Linear(in_features=1024, out_features=4096, bias=True)
              (gelu_impl): BloomGelu()
              (dense_4h_to_h): Linear(
                in_features=4096, out_features=1024, bias=True
                (ia3_l): ParameterDict(  (default): Parameter containing: [torch.FloatTensor of size 1x4096])
              )
            )
          )
          ...
          (23): BloomBlock(
            ...
          )
        )
        (ln_f): LayerNorm((1024,), eps=1e-05, elementwise_affine=True)
      )
      (lm_head): Linear(in_features=1024, out_features=250880, bias=False)
    )
  )
)

第四步,模型练习的其余部分均无需更改,当模型练习完成之后,保存高效微调部分的模型权重以供模型推理即可。

peft_model_id = f"{model_name_or_path}_{peft_config.peft_type}_{peft_config.task_type}"
model.save_pretrained(peft_model_id)

输出的模型权重文件如下所示:

/data/nfs/llm/model/bloomz-560m_IA3_CAUSAL_LM
├── [ 398]  adapter_config.json
├── [689K]  adapter_model.bin
└── [ 129]  README.md
0 directories, 3 files

留意:这里只会保存经过练习的增量 PEFT 权重。其间,adapter_config.json 为 IA3 配置文件;adapter_model.bin 为 IA3 权重文件。

第五步,加载微调后的权重文件进行推理。

from peft import PeftModel, PeftConfig
peft_model_id = f"{model_name_or_path}_{peft_config.peft_type}_{peft_config.task_type}"
config = PeftConfig.from_pretrained(peft_model_id)
# 加载根底模型
model = AutoModelForCausalLM.from_pretrained(config.base_model_name_or_path)
# 加载PEFT模型
model = PeftModel.from_pretrained(model, peft_model_id)
# 编码
inputs = tokenizer(f'{text_column} : {dataset["test"][i]["Tweet text"]} Label : ', return_tensors="pt")
# 模型推理
outputs = model.generate(
        input_ids=inputs["input_ids"], 
        attention_mask=inputs["attention_mask"], 
        max_new_tokens=10, 
        eos_token_id=3
    )
# 解码
print(tokenizer.batch_decode(outputs.detach().cpu().numpy(), skip_special_tokens=True))

至此,咱们完成了 IA3 的练习及推理。

结语

本文对 IA3 根本原理进行了简述;一起,解说了 IA3 进行模型练习及推理。

假如觉得我的文章能够能够给您带来协助,期待您的点赞保藏加重视~~