
醫療機構如何防范API漏洞威脅
如上所述,ΔW的分解意味著我們用兩個較小的LoRA矩陣A和B來表示大矩陣ΔW。如果A的行數與ΔW相同,B的列數與ΔW相同,我們可以將這種分解表示為ΔW = AB(即矩陣A和B的乘積)。
這種分解能節省多少內存呢?這取決于超參數r的值。例如,如果ΔW有10,000行和20,000列,那么它需要存儲200,000,000個參數。如果我們選擇r = 8,那么A將有10,000行和8列,B將有8行和20,000列,這樣A和B總共需要存儲的參數數為10,000×8 + 8×20,000 = 240,000個參數,大約是原來參數數的1/830。
當然,A和B無法像ΔW那樣捕捉所有信息,但這是有意為之的設計。使用LoRA時,我們假設模型在預訓練階段需要W是一個全秩的大型矩陣,以包含預訓練數據集中的所有知識。然而,在微調LLM時,我們并不需要更新所有權重,也不需要用比ΔW更少的參數來捕捉適應的核心信息;因此,我們通過AB進行低秩更新。
在使用LoRA進行多次實驗后,我注意到盡管大型語言模型(LLM)的訓練本身具有隨機性,尤其是在GPU上進行模型訓練時,基準測試的結果在不同運行之間卻異常一致。這種一致性為其他比較研究提供了堅實的基礎。
請注意,這些結果是在默認設置下,使用較小的r=8得到的。具體的實驗細節可以在我另一篇文章中找到。
Dettmers等人提出的QLoRA,即量化LoRA,是一種在微調過程中進一步減少內存使用的技術。在反向傳播階段,QLoRA將預訓練的權重量化到4位精度,并利用分頁優化器來管理內存峰值。
實際上,我發現使用QLoRA可以節省33%的GPU內存。然而,由于QLoRA中預訓練模型權重的額外量化和去量化步驟,訓練運行時間增加了39%。
以下是使用16位浮點數的默認LoRA的對比數據:
而使用4位量化浮點數的QLoRA的數據如下:
此外,我觀察到模型性能幾乎沒有受到影響,這使得QLoRA成為常規LoRA訓練的一個可行替代方案,特別是在面臨常見的GPU內存瓶頸時。
學習率調度器在訓練過程中逐漸降低學習率,這有助于優化模型的收斂性能,并防止在最小化損失函數時超出最小值點。
余弦退火是一種流行的學習率調度器,它根據余弦曲線來調整學習率。這種調度器以較高的學習率開始,然后逐漸下降,最終以類似余弦函數的方式趨近于零。一個常見的變體是半周期余弦退火,它在訓練過程中只完成一個半周期的余弦曲線,如下圖所示。
作為實驗的一部分,我在LoRA微調腳本中加入了余弦退火學習率調度器,并發現它顯著提升了SGD的性能。然而,對于Adam和AdamW優化器,余弦退火的影響較小,幾乎沒有明顯差異
關于SGD相對于Adam的潛在優勢,我將在下一節中進一步討論。
Adam和AdamW優化器在深度學習中仍然是熱門選擇,盡管在使用大型模型時,它們會占用大量內存。這是因為Adam優化器為每個模型參數維護兩個移動平均值:一個是梯度的第一個矩(平均值),另一個是梯度的第二個矩(非中心方差)。換句話說,Adam優化器在內存中為每個模型參數存儲兩個額外的值。如果我們使用的是一個擁有70億參數的模型,則在訓練期間需要跟蹤額外的140億參數。
與此不同,SGD優化器在訓練過程中不需要跟蹤任何額外參數。那么,在訓練大型語言模型(LLM)時,將Adam替換為SGD對峰值內存需求有什么優勢呢?
在我的實驗中,使用AdamW和LoRA默認設置(r=8)訓練的70億參數Llama 2模型需要14.18 GB的GPU內存。相反,使用SGD訓練相同的模型僅需14.15 GB的GPU內存。換句話說,節省的內存(0.03 GB)幾乎微不足道。
為什么節省的內存如此之少?這是因為使用LoRA時,我們只有少量可訓練參數。例如,當r=8時,在70億Llama 2模型的6,738,415,616個參數中,只有4,194,304個是可訓練的LoRA參數。
如果僅從數字上看,4,194,304個可訓練參數聽起來仍然很多,但經過計算,我們發現這些參數的內存占用為4,194,304 × 2 × 16位 = 134.22兆位 = 16.78兆字節。我們觀察到的0.03 GB(30 MB)差異是由于存儲和復制優化器狀態所產生的額外開銷。這里的2表示Adam存儲的額外參數數量,16位指的是模型權重的默認精度。
然而,如果我們將LoRA的r增加到256(我在后續實驗中已經這樣做),Adam和SGD優化器之間的內存差異將變得更加明顯:
總的來說,當LoRA的r值較小時,替換Adam優化器為SGD可能不值得。然而,當我們增加r值時,這種替換可能會變得更加有意義。
在傳統深度學習中,我們經常對訓練集進行多次迭代,這種對訓練集的重復遍歷稱為訓練周期(epoch)。例如,在訓練卷積神經網絡時,通常會執行數百個訓練周期。那么,多周期訓練是否也適用于指令微調呢?
當我將包含50k示例的Alpaca指令微調數據集的迭代次數增加一倍(相當于兩個訓練周期)時,我注意到模型性能有所下降。
我的結論是,多周期訓練可能對指令微調并無益處,因為它可能導致結果變差。我在包含1k示例的LIMA數據集中也觀察到了相同的現象。這種性能下降可能是由于過度擬合導致的,這還需要進一步的研究和調查。
上表展示了僅對選定的權重矩陣(即每個轉換器層中的Key和Value權重矩陣)啟用LoRA的實驗結果。此外,我們也有能力為Query權重矩陣、投影層、多頭注意力塊間的其他線性層以及線性輸出層啟用LoRA。
若我們為所有這些額外的層啟用LoRA,在7B Llama 2模型中,可訓練參數的數量將從4,194,304增加到20,277,248,即增加了5倍。這同時會帶來更高的內存需求,從14.18 GB提升至16.62 GB。盡管如此,這種設置仍有望顯著提升模型的性能。
然而,我的實驗存在一個局限,即僅探索了兩個設置:一是僅對查詢和值權重矩陣啟用LoRA,二是為所有層啟用LoRA。在未來的實驗中,探索其他組合可能會很有價值。例如,探究僅為投影層啟用LoRA是否真正有益將是一個有趣的課題。
正如原始LoRA論文所描述的,LoRA引入了一個額外的縮放系數,用于在前向傳遞期間將LoRA權重應用于預訓練權重。這個縮放過程涉及到我們之前討論過的rank參數r,以及另一個超參數α(alpha),其應用方式如下:
scaling = alpha / r
weight += (lora_B @ lora_A) * scaling
如上代碼公式所示,LoRA權重的影響隨著縮放系數的調整而變化。
以往的實驗通常使用r=8和α=16,這導致了2倍的縮放。在將LoRA應用于LLM時,選擇α作為r的兩倍是一個常見的經驗法則,但我好奇這是否也適用于較大的r值。換句話說,“α = 2×rank”似乎確實是一個較好的起點。然而,在特定模型和數據集的組合中,例如r=256和α=128(縮放0.5倍)時,性能甚至更好。
我進行了r=32、r=64、r=128和r=512的實驗,但為了簡潔,我省略了這些結果,因為r=256時性能最佳。
通常選擇α為r的兩倍可能會得到較好的結果,但嘗試不同的比例也是值得的。
一個重要的收獲是,LoRA技術使我們能夠在單個GPU上微調擁有70億參數的大型語言模型(LLM)。以使用最佳配置(r=256和α=512)的QLoRA為例,使用AdamW優化器,在50k訓練樣本(這里指的是Alpaca數據集)上進行微調大約需要3小時(在A100 GPU上)。
在本文的后續部分,我將回答您可能存在的其他問題。
數據集可能非常關鍵。在我的實驗中,我使用了包含50k個訓練樣本的Alpaca數據集。選擇這個數據集是因為它廣受歡迎,而且由于文章篇幅已經很長,嘗試不同的數據集超出了本文的范圍。
然而,值得注意的是,Alpaca是一個通過查詢舊版本的ChatGPT生成的合成數據集,按照今天的標準可能不是最優選擇。
數據質量可能非常重要。例如,在六月份,我討論了LIMA數據集(領先于AI #9:LLM調整和數據集視角),這是一個精選的、只有1k個樣本的數據集。
根據“LIMA:對準少即是多”的論文,在LIMA上微調的65B Llama模型明顯優于在Alpaca上微調的65B Llama模型。
即使LIMA的數據集規模只有Alpaca的1/50,使用最佳配置(r=256,alpha=512)在LIMA上微調,我獲得了與Alpaca數據集相似甚至更好的性能。
遺憾的是,對于這個問題,我并沒有一個確切的答案。根據經驗,知識通常是從預訓練數據集中吸收的,而指令微調更多的是幫助或指導大型語言模型(LLM)遵循指令。
然而,值得注意的是,如果內存是一個問題,LoRA也可以用來在特定領域的數據集上進一步預訓練現有的預訓練LLM。
請注意,我的實驗還包括兩個算術基準測試(這些測試包含在我其他更具技術性的文章中),其中LoRA微調模型的性能明顯不如預訓練的基礎模型。我的假設是模型取消了學習算術,因為Alpaca數據集不包含相應的示例。是模型完全丟失了知識,還是因為模型無法再處理指令,這需要進一步調查。但這里的一個要點是,在微調LLM時,包含您關心的每項任務的示例可能是一個好主意。
不幸的是,我沒有任何好的啟發式方法來選擇一個好的r值,并認為它是一個超參數,需要針對每個LLM和每個數據集進行探索。我懷疑選擇過大的r可能會導致更多的過擬合。另一方面,較小的r可能無法捕獲數據集中的不同任務。換句話說,我懷疑數據集中的任務越多樣化,r值應該越大。例如,如果我只想要一個執行基本2位運算的模型,那么一個小的r可能就足夠了。然而,這只是一個假設,需要額外的調查。
我僅探索了兩個設置:一是LoRA僅用于查詢和值權重矩陣,二是LoRA用于所有層。在未來的實驗中,探索其他組合可能會更有價值。例如,了解為投影層激活LoRA是否真正有益會是一個有趣的課題。如果我們考慮各種設置,包括lora_query、lora_key、lora_value、lora_projection、lora_mlp和lora_head,那么就需要探索2^6=64種組合,這將是未來研究的一個有趣方向。
通常,較大的r值會導致更多的過擬合,因為它決定了可訓練參數的數量。如果模型存在過擬合問題,那么減小r值或增加數據集大小是首先要考慮的解決方案。此外,還可以嘗試在AdamW或SGD優化器中增加權重衰減率,并考慮增加LoRA層的dropout值。我在實驗中未探索過LoRA的dropout參數(固定使用了0.05的dropout率),這將是未來研究的一個有趣話題。
未來值得探索其他有趣的LLM(大型語言模型)優化器。例如,5月發布的Sophia:一種可擴展的隨機二階優化器,專為語言模型預訓練而設計。
Sophia作為一種二階優化算法,對Adam和AdamW這類在LLM中通常占據主導地位的優化器來說,具有特別的吸引力。據該論文所述,與Adam相比,Sophia的速度提高了2倍,且使用Sophia訓練的模型能夠實現更佳的建模性能。簡而言之,Sophia通過梯度曲率(而非像Adam中的梯度方差)來標準化梯度。
除了精度和量化設置、模型大小、批量大小以及可訓練的LoRA參數數量外,數據集本身也會影響內存使用情況。
請注意,Llama 2的區塊大小為4048。這意味著,如果LLM的區塊大小設置為4048個代幣,那么它就能夠一次性處理多達4048個代幣的序列。然而,由于未來令牌的掩蓋操作,使用較短的訓練序列可以顯著節省內存。
以Alpaca數據集為例,其規模相對較小,且最大長度僅為1304個標記。
當我試驗其他長度高達 2048 個令牌的數據集時,我注意到內存使用量從 17.86 GB 增加到 26.96 GB。
我沒有進行任何RLHF實驗(對于那些好奇的人,我在這里介紹了RLHF),但我確實考慮了全參數微調。全參數微調至少需要2個GPU,每個GPU使用36.66 GB的內存,在3.5小時內完成。然而,基準測試結果并不理想,可能是由于過度擬合或次優的超參數選擇。
是的,可以組合多組LoRA權重。在訓練過程中,我們將LoRA權重與預訓練權重分開,并在每次前向傳遞期間將它們相加。
但是,如果您有一個實際應用,其中包含多組LoRA權重,例如,每個應用客戶一組,則最好單獨存儲這些權重以節省磁盤空間。不過,可以在訓練后將預訓練權重與LoRA權重合并,以創建單個模型。這樣,我們就不必在每次前向傳遞中應用LoRA權重:
weight += (lora_B @ lora_A) * scaling
相反,我們按照上述方式應用權重更新并保存合并(相加的)權重。
同樣,我們可以不斷地添加多個LoRA權重集:
weight += (lora_B_set1 @ lora_A_set1) * scaling_set1
weight += (lora_B_set2 @ lora_A_set2) * scaling_set2
weight += (lora_B_set3 @ lora_A_set3) * scaling_set3
...
我還沒有進行實驗來評估這種方法的性能,但從Lit-GPT提供的scripts/merge_lora.py腳本來看,技術上已經可以實現這一點。
為了簡單起見,我們通常為每一層訓練具有相同學習率的深度神經網絡,而學習率是我們需要優化的超參數。更進一步,我們還可以為每一層選擇不同的學習率(在PyTorch中,這并不復雜)。然而,在實踐中很少這樣做,因為這會增加額外的開銷,而在訓練深度神經網絡時,通常已經有許多參數需要調整。
類似于為不同層選擇不同學習率的做法,我們也可以為不同層選擇不同的LoRA等級。目前我還沒有找到關于這一點的實驗,但有相關文獻詳細介紹了這種方法,稱為分層最優秩適應(Layer-wise Optimal Rank Adaptation,簡稱LORA)。從理論上講,這在實踐中聽起來是個不錯的主意。然而,在優化超參數時,這也會增加大量的選擇和復雜性。
文章轉載自:Practical Tips for Finetuning LLMs Using LoRA (Low-Rank Adaptation)