從上圖可以直觀的看出,預訓練模型旁增加了右側的“旁支”,也就是先用一個Linear層A,將數據從 d維降到r,再用第二個Linear層B,將數據從r變回d維。最后再將左右兩部分的結果相加融合,得到輸出的hidden_state。

  1. 在訓練階段,預訓練參數W固定,只更新A和B參數,A和B模擬W的變化量。
  2. 在推理階段,用A、B參數與原預訓練參數相加替換原有預訓練模型的參數。推理過程沒有額外的參數量和計算量
  3. 相當于是用LoRA去模擬Full-finetune的過程,幾乎不會帶來效果損失

AdaLORA

AdaLoRA是自適應預算分配以實現參數有效的微調,由于在不太重要的權重矩陣添加更多的參數會產生很少的收益,甚至會損害模型性能。因此為了降低不重要的權重的計算,AdaLoRA通過調整增量矩陣的秩,以控制參數參與計算的量。

調整矩陣秩的方法

lora是根據 讓模型學習這兩個矩陣,用近似SVD分解的結果,同時將 的秩統一成為

AdaLora只直接利用SVD分解的結果,根據 學習型    這三個權重。

  1. 首先,初始化 為0矩陣, 為高斯隨機矩陣。這樣初始化的目的和lora一樣,能在訓練開始確保 是0矩陣,避免引入噪聲。
  2. 固定 ,更新。得到的 中對角線較小的值更新為0,相當于0對應的 進行mask,讓下一次計算不參與計算,這里就相當于變秩。只將重置為0,而不是將整個刪掉,是因為隨著模型的學習和更新,后面這樣的三元組可能會變的重要,顯然用mask更合理。
  3. 中較小的值更新為0后固定住,再更新 ,此時不重要的信息就不參與計算了。
  4. 重復2、3步

下面的內容解釋了這些參數的中文含義

QLora實戰

import?torch
from?transformers?import?AutoModelForCausalLM,?AutoTokenizer,?TrainingArguments,?BitsAndBytesConfig

#?modelpath="meta-llama/Llama-2-7b-hf"
modelpath="meta-llama/Meta-Llama-3-8B"

#?Load?4-bit?quantized?model
model?=?AutoModelForCausalLM.from_pretrained(
????modelpath,????
????device_map="auto",
????quantization_config=BitsAndBytesConfig(
????????load_in_4bit=True,
????????bnb_4bit_quant_type="nf4",
????????bnb_4bit_use_double_quant=True,
????????bnb_4bit_compute_dtype=torch.bfloat16,
????),
????torch_dtype=torch.bfloat16,
)
model.config.use_cache?=?False

tokenizer?=?AutoTokenizer.from_pretrained(modelpath)
tokenizer.pad_token?=?tokenizer.eos_token

配置lora

LoRAConfig()?用于配置,哪些位置添加lora層。在這里,將 LoRA 層添加到自注意力模塊的所有線性投影(attn_matrices=[“q”, “k”, “v”])以及中間和輸出線性層。

import?adapters
from?adapters?import?LoRAConfig

adapters.init(model)

config?=?LoRAConfig(
????selfattn_lora=True,?
????intermediate_lora=True,?
????output_lora=True,
????attn_matrices=["q",?"k",?"v"],
????alpha=16,?r=64,?dropout=0.1
)
model.add_adapter("assistant_adapter",?config=config)
model.train_adapter("assistant_adapter")

剛查需要更新的參數

print(model.adapter_summary())?#?觀察需要微調的參數量



for?param?in?model.parameters():
????if?param.ndim?==?1:
????????#?cast?the?small?parameters?(e.g.?layernorm)?to?fp32?for?stability
????????param.data?=?param.data.to(torch.float32)

#?Enable?gradient?checkpointing?to?reduce?required?memory?if?needed
#?model.gradient_checkpointing_enable()
#?model.enable_input_require_grads()

class?CastOutputToFloat(torch.nn.Sequential):
????def?forward(self,?x):?return?super().forward(x).to(torch.float32)
model.lm_head?=?CastOutputToFloat(model.lm_head)

model

數據準備

from?datasets?import?load_dataset

dataset?=?load_dataset("timdettmers/openassistant-guanaco")

def?tokenize(element):
????return?tokenizer(
????????element["text"],
????????truncation=True,
????????max_length=512,?#?can?set?to?longer?values?such?as?2048
????????add_special_tokens=False,
????)

dataset_tokenized?=?dataset.map(
????tokenize,?
????batched=True,?
????num_proc=os.cpu_count(),????#?multithreaded
????remove_columns=["text"]?????#?don't?need?this?anymore,?we?have?tokens?from?here?on
)

開始訓練

from?adapters?import?AdapterTrainer
from?transformers?import?DataCollatorForLanguageModeling

args?=?TrainingArguments(
????output_dir="output/llama_qlora",
????per_device_train_batch_size=1,
????per_device_eval_batch_size=1,
????evaluation_strategy="steps",
????logging_steps=10,
????save_steps=500,
????eval_steps=187,
????save_total_limit=3,
????gradient_accumulation_steps=16,
????max_steps=1875,
????lr_scheduler_type="constant",
????optim="paged_adamw_32bit",
????learning_rate=0.0002,
????group_by_length=True,
????bf16=True,
????warmup_ratio=0.03,
????max_grad_norm=0.3,
)


trainer?=?AdapterTrainer(
????model=model,
????tokenizer=tokenizer,
????data_collator=DataCollatorForLanguageModeling(tokenizer,?mlm=False),
????train_dataset=dataset_tokenized["train"],
????eval_dataset=dataset_tokenized["test"],
????args=args,
)

trainer.train()

推理

from?transformers?import?logging
logging.set_verbosity(logging.CRITICAL)

def?prompt_model(model,?text:?str):
????batch?=?tokenizer(f"###?Human:?{text}\n###?Assistant:",?return_tensors="pt")
????batch?=?batch.to(model.device)
????
????model.eval()
????with?torch.inference_mode(),?torch.cuda.amp.autocast():
????????output_tokens?=?model.generate(**batch,?max_new_tokens=50)

????return?tokenizer.decode(output_tokens[0],?skip_special_tokens=True)


print(prompt_model(model,?"Explain?Calculus?to?a?primary?school?student"))

權重融合

model.merge_adapter("assistant_adapter")

https://arxiv.org/pdf/2106.09685

https://github.com/microsoft/LoRA

https://arxiv.org/pdf/2303.10512

https://github.com/QingruZhang/AdaLoRA

文章轉自微信公眾號@CourseAI

上一篇:

LLM微調(三)| 大模型中RLHF + Reward Model + PPO技術解析

下一篇:

LLM推理部署(一):LLM七種推理服務框架總結
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費