注:以下的理解只是我自己的理解,如果要看权威的解释,你可以看看论文。当然,权威的解释有时候也不好理解。如有什么问题,欢迎到评论区指正🥰
LoRA 是什麼#
簡單來說,LoRA 是一種技術,可以微調模型(神經網絡)裡的參數。可以將模型看成是一個具有很多參數的函數,你輸入一個東西,這個模型就會輸出一個數字、文本或者圖像。拿 ChatGPT 舉例來說,你輸入的文本會先轉換成一個個數字(Word Embedding),然後這些數字放到模型這個函數裡面,這個模型會給出一系列輸出的數字,每個數字都在之間,而這個每一個數字會對應一個單詞,這個數字就代表這個單詞出現在這句話後面的概率,ChatGPT 就像這樣將單詞一個個 “吐出來”。
既然模型是一個函數,那函數中的每一個參數,比如 其中 和都是這個一次函數的參數,如果你更改其中的任意一個參數,那麼這個一次函數代表的直線的位置就會發生改變。對於模型來說也是一樣,如果你更改了模型的一個參數,那麼這個模型的功能也會發生變化。
所以,如果你在網上下載了一個模型,這個模型用來分類不同水果的,但是你在使用這個模型進行分類任務時,你發現這個模型的性能並不怎麼樣,比如說,這個模型誤把一個葡萄識別成了提子。就說明這個模型裡面的參數並不好,導致了模型的性能不好。所以你想要調整一下這個模型裡面的參數,讓模型順利把葡萄識別成提子。而調整模型參數的一個方法就是使用 LoRA。簡單來說,你覺得當前模型的功能並不能滿足你的要求,你就可以使用 LoRA 微調當前的模型。
注:為了直觀的感受 LoRA 的能力,我想說說之前我在折騰的 Stable Diffision (AI 繪圖軟體),其中的模型影響生成的圖是二次元還是三次元,而你可以在這個模型中添加 LoRA 來微調這個 AI 畫師。我記得非常清楚裡面有一個叫做水墨風 LoRA,如果你把這個 LoRA 應用到模型中,那個最後畫出的圖就有水墨風,但是圖像的本質區別 -- 二次元還是三次元,是沒有變的。
微調現存的模型,為何不直接訓練出一個模型#
當下,大模型的種類越來越多了。基本上比較大的互聯網公司都發布了自己公司的大模型。為何我們不自己訓練出來一個大模型,而是想要微調別人訓練完成的模型呢?其中一個很大的原因就是 “大”,現在的模型的參數動不動上 7B,12B(billion)。修改(訓練)這麼多的參數,一方面需要電腦運算的快(顯卡,CPU 的算力高),另一方面需要電腦有足夠的內存存儲這麼多的參數供計算單元進行計算。我們拿 7B 的模型舉個例子,如果模型參數的類型是 float16,一個模型的參數占 2 個字節,那麼 7B 個參數占字節,換算成 GB 就是 13GB。也就是說,如果你要在 GPU 上運行這個模型,顯卡的顯存需要 13GB,而如果你想要調整裡面的參數,則電腦還要為其中每一個參數再預留一個參數的空間來放每個模型的梯度,所以要訓練這個模型至少要GB。這麼大的顯存一般在消費級顯卡不會出現,比如現在性能最好的消費級 GPU--4090 的顯存最多也就 24GB。而專業的計算卡如 A100 可以達到 80GB,但是專業的計算卡價格高昂。
由於訓練一個大模型需要很多專業級的顯卡,只有大的互聯網公司才能訓練得起。有些大公司會把它們訓練好的模型進行開源,也就是把它們訓練好的模型公開,別人就可以在它們的基礎上調整模型裡面的參數了。
所以,為了能在普通消費級顯卡上能夠調整模型裡面的參數,也就是在普通人的電腦上能夠改變模型的性能,我們只能微調裡面的一些參數,不可能和大公司訓練模型那樣調整模型裡面的所有參數。可以說,如果我們需要的模型想要訓練成 100%,那大公司一開始的訓練就占了 80%,然後在我們電腦上微調模型就占其中的 20%。
LoRA#
上面我提到,普通人的電腦上能夠改變模型的性能,我們只能微調裡面的一些參數,但是微調這些參數的方式也有多種,其中最常見的方式就是 LoRA。
在論文中提到了一個公式,我覺得比較重要:
其中,是模型的原始參數,這是一個矩陣的形式,根據論文,$W_0$ 矩陣中的數字是不變的,而 $\Delta W = BA$ 是另外一個矩陣,LoRA 主要是改變這個矩陣。通過將和相加就得到了一个新的參數,如果我們將這個新的參數作用到模型上時,模型的參數更改,模型的功能也就發生了變化,達到了微調的目的。
那我們就出現了一個問題,我們根據矩陣的加法,如果兩個矩陣想要相加,那麼這兩個矩陣就要有相同的大小。比如,下面中,矩陣的大小就是的,如果要和相加,那麼的大小也必須是的。如果我們直接更改這個,也就是更改其中個參數,那我們怎麼不直接更改原模型中的參數,反正這兩個矩陣的大小是一樣的。那我們的目的沒有達到啊 -- 普通人的電腦上為了能夠改變模型的性能,我們只能微調模型裡面的一些參數,因為根據消費級的電腦的算力和內存,是不可能的更改原模型那成千上萬的參數的。
為了解決這個問題,論文提出了一個新的方法
LoRA allows us to train some dense layers in a neural network indirectly by optimizing rank decomposition matrices of the dense layers’ change during adaptation instead, while keeping the pre-trained weights frozen
其中,我覺得這句話中,關鍵詞就是rank decomposition,直接翻譯是秩分解?
什麼是 rank decomposition#
根據矩陣的乘法,如果矩陣的大小是的,矩陣的大小是的,那麼它們兩相乘的話矩陣的大小就是的。
我還是拿上面的等式舉例子,由可知,的大小是的,由矩陣加法,的大小也要是的。關鍵的地方來了,為了得到,我們可以讓,如所示。也就是說,將變成兩個矩陣相乘。其中矩陣的大小是的,矩陣是的,其中 r 是一個變量,隨便更改,這個 r 也非常重要,我後面會說明。由矩陣乘法可知結果的矩陣大小是的。這樣就可以與相加了。
從中可以看出,一個擁有 9 個參數的大矩陣分解成了兩個擁有 3 個參數的小矩陣相乘,秩分解可以簡單理解為大矩陣分解成小矩陣相乘。這樣為了得到,我們只要關注,更改兩個小矩陣中的 6 個參數就行了,相比於中的 9 個參數,6 個參數減少許多。
由 LoRA 訓練帶來的訓練參數減少的效果是顯著的,論文中提到
When the pre-trained model is GPT-3 175B, the number of trainable parameters can be as small as 0.01% of $W_0$
也就是說,用 LoRA 訓練 GPT-3,可訓練參數是模型參數的 0.01%。
關於 LoRA 中 r 參數的選取#
由前面可知,被分解成了兩個矩陣的相乘,其中矩陣的大小是的,矩陣是的。由線性代數的知識可得,一般來說,兩個矩陣相乘的結果矩陣的秩不會超過兩個原始矩陣的秩中的最小值。也就是說,如果我們選取的 r 小於 3,那麼和相乘得到的矩陣的秩不會超過 r,小於 3。其實,對於這個例子,我們選的 r 也要必須小於 3,如果我們選 r 等於 4,那麼要更改(訓練)的參數為,比原模型的參數都要多,這就違背我們使用 LoRA 的目的 -- 減少可訓練參數的數量。
這裡面就存在問題了,如果模型原來的參數矩陣是滿秩的,但是我們由 LoRA 得到的的秩是小於的。也就是說,LoRA 只能微調模型參數矩陣的一個子空間。還是以舉個例子,的秩是 3。簡單來說,這個模型需要拿三維坐標系來進行建模來解決問題,但是如果我們使用 LoRA 並且設,則我們只是在更改模型的一個維度,別的兩個維度並沒有考慮到,這樣模型的參數怎麼更改,效果都比較差。
既然 LoRA 只能微調模型參數矩陣的一個子空間,那我們使用 LoRA 幹啥呢,無論如何都有一兩個維度沒考慮到。
幸好,由之前的論文可知:the learned over-parametrized models in fact reside on a low intrinsic dimension. 也就是說,我們給模型三維坐標系進行建模,但是模型最後只是利用了一條線,它只用了其中的一個維度。說明模型參數這個矩陣裡的列向量存在線性相關,模型參數的秩其實是 1,這也就是論文所說的low intrinsic dimension。這時,如果我們令時,效果就比較好。我們只要關注,更改兩個小矩陣中的 6 個參數就行了,相比於中的 9 個參數,6 個參數減少許多。但是,我們也可以令, 但是這樣可訓練參數變為 12 了,還起到了副作用。
由於我們並不知道模型用了幾個維度進行建模,所以參數 r 需要我們手動嘗試取得最優值,這種參數叫做超參數。如果 r 大了,可訓練參數變多;r 小了,訓練效果不行。
LoRA 優點#
為了形成對比,我先講講其他可微調模型參數的方法
-
Adapter Layers:這就相當於改變模型的架構,在模型中添加一些層,然後只是更改這些層的參數。但是這有一個問題,這會使模型推理時間變長,學名好像叫Inference Latency。類比一下,我們將模型想成一條水泥路連接 A 和 B。你的輸入是一輛在 A 的車,這個車要經過水泥路到達 B,輸出得到結果,車在路上要時間。然後Adapter Layers就是在這個路上加了一小塊水泥路,並只對這個小塊水泥路進行優化。但是路程變長了,導致汽車路途時間變長,這就是推理時間變長。但是 LoRA 好像就是在不改變路長度的同時,將一部分路升級成高速公路(不是說明速度快,而是效果好,LoRA 並不會加快推理速度)。
-
Prefix tuning: 前綴微調這個方法其實是一種提示詞工程,並不直接對模型進行改變。將提示詞分成前綴 (prefix) 和後綴。用戶輸入到後綴,前綴被佔領用於微調。這樣用戶的輸入就變少了。這是它的缺點。