編碼大模型系列:Meta創(chuàng)新的“代碼編譯優(yōu)化”的LLM 原創(chuàng) 精華
大型語言模型 (LLM) 已在各種軟件工程和編碼任務中展現(xiàn)出卓越的能力。然而,它們在代碼和編譯器優(yōu)化領域的應用仍未得到充分探索。訓練LLM需要大量資源,需要大量的 GPU時間和大量的數(shù)據(jù)收集。Meta語言模型編譯器 (LLM Compiler),這是一套專為代碼優(yōu)化任務設計的強大、公開可用的預訓練模型。
LLM Compiler建立在Code Llama的基礎上,增強了對編譯器中間表示 (IR)、匯編語言和優(yōu)化技術的理解。該模型已在546B的LVM-IR和匯編代碼的龐大語料庫上進行了訓練,并經(jīng)過了指令微調(diào)。
LLM Compiler是根據(jù)定制的商業(yè)許可發(fā)布的,允許廣泛重用。除了7B和 13B的規(guī)模,還有該模型的微調(diào)版本,展示了其在優(yōu)化代碼大小和從 x86_64和ARM匯編反編譯回LLVM-IR的增強功能。
1.Code Llama
2024年1月29日發(fā)布代碼Llama 70B是一個可以使用文本提示生成代碼的大型語言模型。Code Llama是最先進的代碼任務公開可用LLMs,可以使得當前開發(fā)人員的工作流程更快、更高效,并降低學習編碼的門檻。Code Llama可以被用來作業(yè)以及教學。
Code Llama是Llama 2的代碼專用版本,它是通過在特定的代碼數(shù)據(jù)集進一步訓練Llama 2而得到。它可以從代碼和自然語言提示生成代碼和關于代碼的自然語言,例如,“寫一個斐波那契數(shù)列的函數(shù)”。它還可用于代碼的補全和調(diào)試,支持當今使用的許多最流行的語言,包括Python、C++、Java、PHP、Typescript (Javascript)、C#和Bash。
Code Llama提供多達100,000 個上下文Token。所有的模型都基于16,000個Token序列進行訓練,在多達100,000個Token輸入中顯示出明顯的改進。
Meta還微調(diào)Code Llama的另外兩個變體:Code Llama-Python和Code Llama-Instruct。Code Llama-Python是Code Llama的專用語言變體,在 Python代碼的100B的Token上進一步微調(diào)。Meta選擇Python的原因是Python和PyTorch在AI社區(qū)中發(fā)揮著重要作用。
上圖為Code Llama的家族譜系
2.LLM Compiler
剛剛,Meta在編譯器優(yōu)化方面又邁出了一大步,它推出了一套突破性的工具,基于LLM的編譯器能夠處理編譯和反編譯任務,在編譯器技術領域樹立了新的標桿。
編譯器的中間表示(Intermediate Representation,IR)是編譯過程中的一種抽象表示形式,位于源代碼和目標代碼之間。它的存在主要是為了幫助編譯器在多個階段進行優(yōu)化和轉換,從而生成高效的目標代碼。
上圖為LLM Compiler的訓練過程,分兩個階段對546B的數(shù)據(jù)集進行訓練,這些數(shù)據(jù)集以編譯器為中心。在第一階段,模型主要在未標記的編譯器IR和匯編代碼上進行訓練。第二階段對模型進行指令微調(diào),以預測優(yōu)化的輸出和效果。進而生成7B和13B的LLM Compiler。
不同階段使用的訓練數(shù)據(jù)集,可以看出在編譯優(yōu)化方面還是加入不少的訓練數(shù)據(jù)。尤其是第三階段和第四階段中,和代碼相關的自然語言成為主力。
之后在164B個下游標記和反匯編任務數(shù)據(jù)集上進一步微調(diào)形成新的LLM Compiler FTD。在四個訓練階段中,每階段都會保留先前15%的任務數(shù)據(jù)。
3.核心要點:如何學習編譯優(yōu)化
既然要優(yōu)化編譯,那么就需要想解鎖下LLVM。LLVM是一套編譯器基礎設施項目,以C++寫成,包含一系列模塊化的編譯器組件和工具鏈,用來開發(fā)編譯器前端和后端。它是為了任意一種編程語言而寫成的程序,利用虛擬技術完成編譯時期、鏈接時期、執(zhí)行時期以及“閑置時期”的優(yōu)化任務。
它最早以C/C++為實現(xiàn)對象,而目前它已支持包括ActionScript、Ada、D語言、Fortran、GLSL、Haskell、Java字節(jié)碼、Objective-C、Swift、Python、Ruby、Crystal、Rust、Scala以及C#等語言。
LLVM pass框架是LLVM系統(tǒng)的一個很重要的部分。LLVM的優(yōu)化和轉換工作就是由多個pass來一起完成的。類似流水線操作一樣,每個pass完成特定的優(yōu)化工作。
上面就是所有的pass(優(yōu)化算子),各自身懷絕技!
總的來說,所有的pass大致可以分為兩類:
- 分析(analysis)和轉換分析類的pass主要以提供信息為主
- 轉換類(transform)的pass主要優(yōu)化中間代碼
常用的代碼優(yōu)化方法(不同的pass):
- 刪除公共子表達式:如果表達式x op y先前已被計算過,并且從先前的計算到現(xiàn)在,x op y中的變量值沒有改變,則x op y的這次出現(xiàn)就稱為公共子表達式(common subexpression)
- 刪除無用代碼無用代碼(Dead-code):其計算結果永遠不會被使用的語句
- 常量合并:如果在編譯時刻推導出一個表達式的值是常量,就可以使用該常量來替代這個表達式。
- 代碼移動:這個轉換的結果是那些不管循環(huán)多少次都得到相同結果的表達式(即循環(huán)不變計算,loop-invariant computation),在進入循環(huán)之前就對它們進行求值。
- 強度削弱:用較快的操作代替較慢的操作,如用加代替乘 。(例:2*x ? x+x)
- 刪除歸納變量:對于一個變量x ,如果存在一個正的或負的常數(shù)c使得每次x被賦值時它的值總增加c ,那么x就稱為歸納變量(Induction Variable)。在循環(huán)中,若有一組歸納變量的值的變化不變,可以將這組變量保留一個
聰明的讀者一定反應過來了,感情這模型是在學習如何針對代碼選擇最優(yōu)的pass list(優(yōu)化算子組合)然后進行優(yōu)化。對了!
Meta為了讓LLM Compiler了解編譯器優(yōu)化的工作原理,它使用編譯器模擬辦法。這個辦法將未優(yōu)化的代碼和隨機選擇的pass lists(優(yōu)化算子組合,黃色部分)一起丟給opt,進而生成優(yōu)化代碼(IR 或匯編,綠色部分)。最后黃色部分和綠色部分一起作為訓練集喂給LLM。
上圖中的opt是LLVM工具鏈中的一個工具,用于分析和轉換LLVM源文件中的中間表示(IR)。這個工具通常用于應用各種優(yōu)化和轉換操作,例如執(zhí)行優(yōu)化傳遞、插入優(yōu)化插件等。
>opt input .bc -o output .bc -p ’module ( default <Oz >) ,module ( iroutliner )’
>clang output .bc -o output .o
>size output .o
上圖展示了訓練1和推理2期間的模型輸入(提示)和輸出(標簽)的過程。為了生成訓練提示的標簽,未優(yōu)化的代碼和多個隨機pass組合進行編譯,然后針對輸出二進制最小的pass組合進行最小化,之后再使用 PassListEval檢查其正確性。最終被選擇的pass list以及其相應的優(yōu)化IR在訓練期間用作標簽。期間最經(jīng)常被選擇的100個pass組合將會在所有的應用中廣播。
對于部署,Meta選擇優(yōu)化過的傳遞列表,以確保優(yōu)化的代碼是正確的。為了保證正確性,PassListEval很是關鍵,下圖展示了這個過程:
那么如何進行反編譯的微調(diào)呢,其實也很簡單,通過訓練模型將給定的代碼樣本反匯編為相應的IR來訓練模型,以了解匯編(ASM,機器指令,黃色)和IR(優(yōu)化過后的綠色部分)之間的關系。用于標記此訓練任務的IR是利用優(yōu)化過的IR。如下圖所示:
這樣LLM編譯器經(jīng)過微調(diào),可在特定任務中表現(xiàn)出色,例如將編譯后的代碼反匯編回其中間表示 (LLVM-IR)。這對于理解遺留代碼或反向優(yōu)化特別有益,使LLM編譯器成為維護和升級現(xiàn)有軟件系統(tǒng)的寶貴工具。
4.效果如何
若要比較效果的話,肯定和優(yōu)化命令-Oz作為基準來比較,從圖中可以看出,效果還是挺不錯的。雖然LLM Compiler在編譯器優(yōu)化任務上表現(xiàn)良好,并且相比先前的工作,對編譯器表示和匯編代碼的理解有所改進,但仍存在一些局限性。主要限制是輸入的有限序列長度(上下文窗口)。
LLM 編譯器支持 16k tokens的上下文窗口,但程序代碼往往超過這個長度。例如,67%的MiBench基準中顯示超過了這個上下文窗口。為了緩解這個問題,研究人員拆分了內(nèi)容,然而仍有18%還是過長,無法作為輸入。這樣也是是后續(xù)的一個研究熱點。
本文轉載自 ??魯班模錘??,作者: 龐德公
