涵蓋500多項(xiàng)研究、50多個(gè)模型,代碼大模型綜述來了
隨著 BERT 和 GPT 等預(yù)訓(xùn)練 Transformer 的出現(xiàn),語言建模近些年來取得了顯著進(jìn)步。隨著大型語言模型(LLM)的規(guī)模擴(kuò)展至數(shù)以千萬計(jì)的參數(shù)數(shù)量,LLM 開始展現(xiàn)出通用人工智能的跡象,它們的應(yīng)用也已經(jīng)不局限于文本處理。Codex 首次展現(xiàn)出了 LLM 在代碼處理方面的出色能力,之后更是出現(xiàn)了 GitHub Copilot 這樣的商業(yè)產(chǎn)品以及 StarCoder 和 Code LLaMA 等開源代碼模型。
但是,預(yù)訓(xùn)練 Transformer 在代碼處理方面的應(yīng)用可以追溯到僅解碼器(decoder-only)自回歸模型成為主流技術(shù)之前的時(shí)期,而這一領(lǐng)域還尚沒有一篇完整的綜述。
上海交通大學(xué)和螞蟻集團(tuán)的一個(gè)研究團(tuán)隊(duì)填補(bǔ)了這一空白。他們對用于代碼的語言模型進(jìn)行了全景式的總結(jié),覆蓋了 50 多個(gè)模型、30 多個(gè)下游任務(wù)和 500 多個(gè)相關(guān)研究成果。他們對代碼語言模型進(jìn)行了分類,從在一般域上訓(xùn)練的巨型模型到專門針對代碼理解或生成任務(wù)訓(xùn)練的微型模型。
他們關(guān)注的重點(diǎn)是這些模型之間的關(guān)系和差異,并格外強(qiáng)調(diào)了在語言模型中集成特定于代碼的功能(例如抽象語法樹或數(shù)據(jù)流)以及從 NLP 領(lǐng)域借用過來的最新技術(shù)。
下面機(jī)器之心將介紹這一篇綜述論文。如果你想更全面地了解代碼語言模型的發(fā)展歷程,請一定不要錯(cuò)過原論文。此外,該團(tuán)隊(duì)還在 GitHub 上建了一個(gè)開放的相關(guān)文獻(xiàn)索引庫,以跟蹤和分享代碼 LLM 的最近成果。
- 論文地址:https://arxiv.org/pdf/2311.07989v1.pdf
- 文獻(xiàn)庫地址:https://github.com/codefuse-ai/Awesome-Code-LLM
背景
這一節(jié),作者總結(jié)了基于 Transformer 的語言建模的基本知識(shí),包括單向和雙向模型的共同目標(biāo),以及 NLP 中的一些流行模型和設(shè)計(jì)。
單向語言模型(也被稱為因果語言模型)是將句子的概率分解為每個(gè) token 的條件概率與鏈?zhǔn)椒▌t的乘積。
不同于因果語言模型,雙向語言模型的訓(xùn)練目標(biāo)是為文本獲得更好的上下文表征,而不是以自回歸的方式生成文本。
GPT 式的因果語言模型和 BERT 式的雙向語言模型各有其優(yōu)點(diǎn)和缺點(diǎn)。GPT 雖可用于自回歸生成,但卻缺乏對輸入文本的雙向表征,因此不適用于翻譯和摘要等序列到序列任務(wù)(seq2seq)。另一方面,BERT 雖可產(chǎn)生雙向表征,但其預(yù)訓(xùn)練的目標(biāo)是掩碼填充,而非生成。
最基本的 Transformer 編碼器 - 解碼器架構(gòu)將 GPT 和 BERT 各自的優(yōu)點(diǎn)結(jié)合到了一起。T5 便是這樣一個(gè)模型,其預(yù)訓(xùn)練過程使用了 span corruption,可被看作是掩碼式語言建模(MLM)的一種變體。
因果語言建模(CLM)和 MLM 等語言建模目標(biāo)主要是訓(xùn)練模型捕獲 token 層面的信息,而無法高效地建模文檔結(jié)構(gòu)。因此,為了幫助模型學(xué)習(xí)全局信息,通常還會(huì)添加輔助目標(biāo),比如 BERT 的預(yù)訓(xùn)練在使用 MLM 的同時(shí)還使用了下一句子預(yù)測(NSP)目標(biāo)。
另外值得一提的是,盡管大多數(shù)預(yù)訓(xùn)練語言模型研究都集中于設(shè)計(jì)訓(xùn)練目標(biāo),但 Transformer 架構(gòu)本身的低層實(shí)現(xiàn)也在不斷進(jìn)步,獲得了更好的穩(wěn)定性、性能和效率。
評估用于代碼的語言模型
過去十年中,軟件工程社區(qū)已經(jīng)提出了多種不同的用于評估代碼模型的評估任務(wù)。CodeXGLUE 將大多數(shù)此類整合成了單一基準(zhǔn),其中涵蓋克隆檢測、缺陷檢測等代碼理解任務(wù)以及代碼修復(fù)、代碼轉(zhuǎn)譯、程序合成和代碼總結(jié)等序列到序列生成任務(wù)。但是,自 Chen et al. (2021) 引入了 HumanEval 和 Codex 之后,文本到代碼合成就被帶到了 NLP 社區(qū)的聚光燈下,并從此成為評估 LLM 的標(biāo)準(zhǔn)任務(wù)(圖 2)。
代碼處理的下游任務(wù)
在這篇綜述中,作者按照軟件工程的慣例,基于輸入 / 輸出的模態(tài)對代碼評估任務(wù)進(jìn)行了分類,而這些類別又可歸總為 5 個(gè)大類:文本到代碼、代碼到代碼、代碼到文本、代碼到模式、文本到文本。下面將簡單列出這些任務(wù),至于對這些任務(wù)的解釋,請參閱原論文。
文本到代碼任務(wù)以文本為輸入,輸出代碼。其中包括:代碼檢索、代碼合成、文本到 SQL、數(shù)學(xué)編程。
代碼到代碼任務(wù)以代碼為輸入,輸出代碼。其中包括:代碼搜索、代碼補(bǔ)全、代碼轉(zhuǎn)譯、代碼修復(fù)、填空測驗(yàn)、代碼填充、代碼混淆、單元測試生成、斷言生成、模糊測試(Fuzzing)、類型預(yù)測。
代碼到文本任務(wù)以代碼為輸入,輸出文本。其中包括:代碼摘要、代碼審查、標(biāo)識(shí)符預(yù)測。
代碼到模式任務(wù)是對代碼執(zhí)行分類。其中包括:缺陷檢測、克隆檢測、代碼分類、代碼推理。
文本到文本任務(wù)以文本為輸入,輸出文本。其中包括:文檔翻譯、日志解析。
評估指標(biāo)
代碼理解任務(wù)在形式上與自然語言理解任務(wù)相似,所使用的評估指標(biāo)也類似,比如準(zhǔn)確度、F1 和 MRR(Mean Reciprocal Rank),而標(biāo)識(shí)符預(yù)測等短生成任務(wù)則可使用精準(zhǔn)匹配的準(zhǔn)確度進(jìn)行評估。代碼到文本任務(wù)可使用文本生成任務(wù)的常用評估指標(biāo),比如 BLEU。
而涉及代碼生成的評估任務(wù)則更復(fù)雜。大多數(shù)早期研究都是評估句法正確度,即可成功解析的生成結(jié)果百分比。Chen et al. (2018) 反對此類指標(biāo),并提出了參照匹配(reference match)指標(biāo),即生成結(jié)果與參考結(jié)果完全一致的比例。Ren et al. (2020) 則提出了 CodeBLUE,這是 BLEU 的一種變體,其評估的是抽象語法樹(AST)和數(shù)據(jù)流的重疊范圍,可兼顧代碼的句法和語義。
但是,隨著這些年來代碼生成模型能力的提升,人們發(fā)現(xiàn)這些基于內(nèi)容重疊度的指標(biāo)已經(jīng)不夠用了,因?yàn)閳?zhí)行同樣功能的代碼段可能在詞匯形式上大不相同。
因此,研究者將關(guān)注重點(diǎn)轉(zhuǎn)向了功能正確性。pass@k 就是其中的代表。該指標(biāo)由 Kulal et al. (2019) 提出,并被 Chen et al. (2021) 加以優(yōu)化,能夠無偏差地估計(jì)模型使用任意 k 個(gè)生成樣本通過程序的所有單元測試的幾率。該指標(biāo)還可以泛化成 passn@k (Li et al., 2022),其將模型提交的數(shù)量限制到了 n,但允許根據(jù)輸入中給定的單元測試對 k 個(gè)樣本進(jìn)行過濾。
程序合成
隨著這些年來代碼模型的進(jìn)步,研究者的關(guān)注重點(diǎn)逐漸轉(zhuǎn)向了實(shí)踐中的程序合成任務(wù)。
2018 年的 CONCODE 是該領(lǐng)域的一個(gè)早期數(shù)據(jù)集,其中包含超過 10 萬條 Java 方法,并已經(jīng)被整合到了 CodeXGLUE 基準(zhǔn)中。
2021 年以來,相關(guān)數(shù)據(jù)集迅速增多,其中大部分都專注于 Python 語言,比如 APPS、HumanEval、MBPP;而近期也有一些工作將 HumanEval 擴(kuò)展到了其它編程語言。DS-1000 是一個(gè)更現(xiàn)實(shí)的 Python 數(shù)據(jù)集,專注于 NumPy 和 SciPy 等數(shù)據(jù)科學(xué)軟件庫,同時(shí)一些數(shù)學(xué)推理基準(zhǔn)也已被轉(zhuǎn)換為編程任務(wù),包括 MathQA-Python 和 GSM8K-Python。
代碼庫層面的評估
前面談到的大多數(shù)評估任務(wù)都僅限于單個(gè)文件甚至單個(gè)函數(shù)。
近期一些研究探索了利用代碼庫層面的上下文來進(jìn)行代碼補(bǔ)全,而 Liu et al. (2023) 提出了用于評估這些系統(tǒng)的 RepoBench。最近,Bairi et al. (2023) 研究了難度更大的代碼庫層面的 API 遷移和時(shí)間編輯任務(wù),Jimenez et al. (2023) 則引入了一個(gè)相應(yīng)的基準(zhǔn) SWE-bench。
用于代碼的通用語言模型
自從語言模型的參數(shù)數(shù)量擴(kuò)展到數(shù)以千億計(jì),它們中的許多就已經(jīng)展現(xiàn)出了非凡的編程能力,即便它們并不是專門針對代碼而設(shè)計(jì)或訓(xùn)練的。Codex 之后,研究者發(fā)現(xiàn)只需繼續(xù)在代碼上進(jìn)行預(yù)訓(xùn)練,就能顯著提升語言模型的代碼性能。
現(xiàn)成可用的語言模型
大型語言模型的預(yù)訓(xùn)練通常會(huì)使用數(shù)以萬億計(jì)的 token,遵循縮放律(scaling laws),而這巨量的文本數(shù)據(jù)中往往包含少量但不可忽視的多樣化代碼。比如 Pile 數(shù)據(jù)集包含 95GB 代碼(爬取自 GitHub 的 800GB 原始數(shù)據(jù)集);1.6 TB 的多語言預(yù)訓(xùn)練數(shù)據(jù)集 ROOTS 也包含 163GB 代碼,涵蓋 13 種編程語言。這是兩個(gè)最大型的開源預(yù)訓(xùn)練數(shù)據(jù)集,讓許多語言模型具備了編程能力。比如 GPT-J、GPT-NeoX 和 BLOOM 在 HumanEval 上都有不錯(cuò)的表現(xiàn)。
LLaMA(其預(yù)訓(xùn)練數(shù)據(jù)集包含 328GB 來自 GitHub 的代碼)在 HumanEval 指標(biāo)上取得了 23.7 的 pass@1 表現(xiàn),其后繼模型 LLaMA 2 得到了更高的 29.9。
另一方面,閉源模型的表現(xiàn)一般更好。比如 LaMDA 和 PaLM 在 HumanEval 上的 pass@1 性能分別為 14.0 和 26.2,而 GPT-4 的則達(dá)到了驚人的 67.0,這一成績直到最近都高于任何專門針對代碼預(yù)訓(xùn)練或指令微調(diào)的模型。
最近的一大趨勢是使用更大的數(shù)據(jù)集訓(xùn)練更小的模型,遵循修訂版的縮放律。
舉兩個(gè)例子:Baichuan 2 是使用 2.6T token 訓(xùn)練出的 13B 模型,而 Qwen 則是用 3T token 訓(xùn)練的 14B 模型。它們在 HumanEval 上的 pass@1 性能分別為 17.1 和 32.3。Li et al. (2023) 則表明 1.3B 的小模型也能獲得與更大型模型相當(dāng)?shù)木幊棠芰?,同時(shí)還能維持合理的一般文本處理能力,甚至也能顯現(xiàn)出一些涌現(xiàn)能力,比如思維鏈推理。他們的模型 Phi-1.5 的訓(xùn)練使用了 ChatGPT 生成的 21B token 的教材數(shù)據(jù)以及取自 Stack Overflow 和 Refined Web 的 100B token 的已過濾網(wǎng)絡(luò)數(shù)據(jù);其在 HumanEval 上的 pass@1 性能為 41.4。
表 1 給出了這些模型的性能表現(xiàn)。
在代碼上進(jìn)行過額外預(yù)訓(xùn)練的語言模型
伴隨著開創(chuàng)性的基準(zhǔn) HumanEval,Chen et al. (2021) 還開啟了將 LLM 用于代碼的時(shí)代。他們的貢獻(xiàn)是 Codex,這是一個(gè) GPT-3 檢查點(diǎn)模型,但額外使用了 100B 的代碼 token 進(jìn)行預(yù)訓(xùn)練。這是最早的超十億參數(shù)規(guī)模的代碼模型之一。
之后出現(xiàn)的還有接連成為 HumanEval 和 MBPP 當(dāng)前最佳的 PaLM-Coder 和 PaLM 2-S*。類似地,Lewkowycz et al. (2022) 用 38.5B token 的 arXiv 論文和數(shù)學(xué)內(nèi)容訓(xùn)練了 PaLM;Rozière et al. (2023) 則使用超過 500B 代碼 token 訓(xùn)練 LLaMA 2 而得到了 Code LLaMA,其在 HumanEval 上的表現(xiàn)超過除 GPT-4 外的之前所有語言模型。
Liu et al. (2023) 又使用多任務(wù)微調(diào)(MFT)進(jìn)一步訓(xùn)練了 Code LLaMA,得到了 CodeFuse-CodeLLaMA,其在 HumanEval 上的 pass@1 性能為 74.4,超過了 OpenAI 報(bào)告的 GPT-4 的性能。
盡管這些模型基本都是使用 CLM 預(yù)訓(xùn)練的 Transformer 解碼器,但研究者也在不斷改進(jìn)這種架構(gòu),引入了并行注意力、MQA、RoPE 等新方法。
專用于代碼的語言模型
隨著 GPT 和 BERT 等預(yù)訓(xùn)練 Transformer 在自然語言處理方面取得巨大成功,此類模型架構(gòu)、學(xué)習(xí)范式和訓(xùn)練目標(biāo)很快被軟件工程社區(qū)采用,打造出了用于代碼理解和生成的專用模型。表 3 給出了這些預(yù)訓(xùn)練模型的概況。
代碼訓(xùn)練數(shù)據(jù)集
現(xiàn)在已經(jīng)有許多大規(guī)模的代碼預(yù)訓(xùn)練數(shù)據(jù)集,包括 CodeSearchNet、CodeParrot、Stack;它們分別包含 20GB、50GB 和 3TB 代碼文檔(見表 2)。
編碼器
Kanade et al. (2020) 在代碼語料庫上重復(fù)了 BERT 的訓(xùn)練過程,得到了 CuBERT。而 Feng et al. (2020) 則在 CodeSearchNet 上使用 MLM 和 ELECTRA 的 RTD 訓(xùn)練得到了 CodeBERT。他們還利用了 CodeSearchNet 中的顯式「文本 - 代碼」對,并將它們分別用作 BERT 輸入的第一和第二段。
除了這些標(biāo)準(zhǔn)的訓(xùn)練目標(biāo)之外,研究者還引入了許多專為代碼任務(wù)設(shè)計(jì)的輔助目標(biāo)。GraphCodeBERT 和 SynCoBERT 會(huì)從源代碼中提取圖(graph),各自對應(yīng)于數(shù)據(jù)流圖和抽象語法樹,然后它們借此訓(xùn)練模型來預(yù)測節(jié)點(diǎn)之間的類型關(guān)系;另外 SynCoBERT 和 Code-MVP 還在預(yù)訓(xùn)練階段以標(biāo)記的形式添加了類型推理。
另一個(gè)常用目標(biāo)是對比學(xué)習(xí):SynCoBERT 和 Code-MVP 會(huì)對比輸入的不同角度(比如代碼、注釋、AST 和經(jīng)過轉(zhuǎn)換的代碼);而 DISCO 則會(huì)通過混淆等保留語義的變換來構(gòu)建正例樣本對,通過注入人工錯(cuò)誤來構(gòu)建負(fù)例樣本對。
編碼器 - 解碼器
相比于僅編碼器模型,編碼器 - 解碼器自然更強(qiáng)大,因?yàn)樗鼈兛梢杂糜跅l件文本生成,而它們的編碼器部分始終可以單獨(dú)用于執(zhí)行需要僅編碼器架構(gòu)的任務(wù),例如回歸。
受編碼器 - 解碼器架構(gòu)進(jìn)步的激勵(lì),研究社區(qū)已經(jīng)提出了許多用于代碼處理的此類模型。
PyMT5 (Clement et al., 2020) 和 Mastropaolo et al. (2021) 在代碼語料庫上重復(fù)了 T5 的預(yù)訓(xùn)練和多任務(wù)微調(diào)過程,而 Ahmad et al. (2021) 則提出了 PLBART,這是在 655GB 的 Java、Python 和自然語言組合數(shù)據(jù)上預(yù)訓(xùn)練的 BART 模型。Lachaux et al. (2021) 認(rèn)為 MLM 對于編程語言來說可能是一項(xiàng)過于簡單的任務(wù),因?yàn)闃?biāo)識(shí)符名稱經(jīng)常在單個(gè)上下文窗口中出現(xiàn)多次;他們提出了一種去混淆預(yù)訓(xùn)練目標(biāo),即模型的訓(xùn)練目標(biāo)是將經(jīng)過混淆的代碼轉(zhuǎn)換成原有形式。
基于這些之前的研究成果,Wang et al. (2021) 提出了 CodeT5,其預(yù)訓(xùn)練使用了 T5 原有的 span corruption、標(biāo)識(shí)符標(biāo)記、掩碼式標(biāo)識(shí)符預(yù)測、文本到代碼和代碼到文本生成。其后繼模型 CodeT5+ 則從 UL2 獲得了靈感,將因果語言建模(CLM)引入了預(yù)訓(xùn)練過程,此外還有基于文本 - 代碼匹配的對比目標(biāo)。
Li et al. (2022) 的 AlphaCode 也使用了多個(gè)訓(xùn)練目標(biāo):其編碼器用 MLM 訓(xùn)練,解碼器用 CLM 訓(xùn)練,此外還有淺編碼器和深解碼器、多查詢注意力等架構(gòu)上的調(diào)整;其模型規(guī)模也比 CodeT5 大很多,多達(dá) 410 億參數(shù)。
Chakraborty et al. (2022) 的 NatGen 的預(yù)訓(xùn)練則使用了一個(gè)類似于去混淆的「自然化(naturalization)」目標(biāo):通過循環(huán)變換、死代碼注入和變量重命名等預(yù)定義操作生成語義上等效但不自然的代碼,然后訓(xùn)練模型將這些不自然的代碼轉(zhuǎn)譯回其原始形式。
除了這些一般性預(yù)訓(xùn)練目標(biāo)之外,一些研究工作訓(xùn)練 Transformer 編碼器 - 解碼器時(shí)的重點(diǎn)是代碼轉(zhuǎn)譯,這是 Transformer 模型在代碼方面的一個(gè)自然應(yīng)用,畢竟 Transformer 架構(gòu)最早就是 Vaswani et al. (2017) 為機(jī)器翻譯任務(wù)提出的。但是,不同于自然語言,代碼的并行數(shù)據(jù)很少。
為了解決這個(gè)問題,Rozière et al. (2020) 提出了 Transcoder,其首先使用 XLM 預(yù)訓(xùn)練一個(gè)編碼器,然后使用這個(gè)編碼器初始化一個(gè)基本的 Transformer,再繼續(xù)使用去噪自動(dòng)編碼(DAE)對其進(jìn)行預(yù)訓(xùn)練并轉(zhuǎn)譯回去;之后的 Szafraniec et al. (2023) 還使用了與語言無關(guān)的中間表征來增強(qiáng)這一過程。
除了訓(xùn)練數(shù)據(jù)和目標(biāo)之外,這些模型大多保留了 NLP 社區(qū)提出的原始架構(gòu),如表 3 所示。
解碼器
GPT-3 歷史的發(fā)布以及上下文學(xué)習(xí)方法出現(xiàn)之后,僅解碼器 Transformer 模型已經(jīng)成為語言建模的主導(dǎo)技術(shù)。在代碼處理領(lǐng)域,也出現(xiàn)了許多類似使用 CLM 預(yù)訓(xùn)練的模型,比如 GPT-C、CodeGPT、PolyCoder、CodeGen、PyCodeGPT、Pangu-Coder、CodeGeeX、Phi-1、CodeFuse、CodeShell、DeepSeek Coder。這些模型中有一些實(shí)驗(yàn)了其它的訓(xùn)練目標(biāo),比如 Pangu-Coder 用了 MLM 和 Masked CLM,但這樣的表現(xiàn)并不及僅使用 CLM 訓(xùn)練的方法。Zan et al. (2022) 還提出了在草案(sketch)上進(jìn)行持續(xù)訓(xùn)練,也就是讓模型學(xué)習(xí)先生成程序的草案,然后再實(shí)際寫代碼。
盡管 Christopoulou et al. (2022) 報(bào)告說去噪目標(biāo)的表現(xiàn)不及僅解碼器模型,但也有一些研究工作將去噪或多任務(wù)預(yù)訓(xùn)練與解碼器架構(gòu)結(jié)合到了一起。Incoder、SantaCoder 和 StarCoder 的訓(xùn)練都使用了中間填入(FIM/fill-in-the-middle)目標(biāo)(也被稱為因果掩碼),其本質(zhì)上就是僅解碼器架構(gòu)采用的 span corruption。這些填入目標(biāo)有一個(gè)明顯優(yōu)勢:它們可以讓模型有能力在推理時(shí)間填補(bǔ)輸入代碼中間的空白部分,而 CLM 只允許自回歸生成。但是,如表 4 所示,相比于 CodeGen 等僅 CLM 模型,這些目標(biāo)也會(huì)提升模型在下游任務(wù)上的性能表現(xiàn)。
UniLM
一些研究者也將 UniLM 這另一種 Transformer 模型用在了代碼處理上。CugLM 通過交替的注意力掩碼使用了 CLM 和 MLM + NSP,而 UniXcoder 的訓(xùn)練則使用了 CLM、MLM、Span Corruption 以及對比學(xué)習(xí)和文本 - 代碼雙向生成等輔助目標(biāo)。但是,這兩個(gè)模型的規(guī)模都相對較小,因此這種架構(gòu)究竟是否適合代碼處理還有待探索。
擴(kuò)散模型
雖然目前主導(dǎo)文本生成領(lǐng)域的是 Transformer 架構(gòu),但也有一些研究者探索了使用計(jì)算機(jī)視覺領(lǐng)域的擴(kuò)散模型(Diffusion Model)來生成文本。
近期的 CodeFusion 將擴(kuò)散模型引入了代碼建模領(lǐng)域,并且研究表明:一個(gè) 7500 萬參數(shù)的擴(kuò)散模型在三個(gè)代碼合成數(shù)據(jù)集上取得了優(yōu)于 StarCoder、CodeT5+ 和 GPT-3 的表現(xiàn)。
用于代碼的指令微調(diào)和強(qiáng)化學(xué)習(xí)
跟隨自然語言領(lǐng)域的研究成果,代碼社區(qū)的研究者也已經(jīng)在使用指令微調(diào)技術(shù)。Wang et al. (2023) 使用 InstructGPT 生成的 2 萬個(gè)指令數(shù)據(jù)對 CodeT5+ 進(jìn)行了微調(diào),得到了 InstructCodeT5+。WizardCoder 按照 WizardLM 的方法,將 2 萬代碼的 Alpaca 樣本演進(jìn)成了一個(gè) 78K 的數(shù)據(jù)集,并使用其來微調(diào) StarCoder。Pangu-Coder 2 也使用 WizardLM 的 Evol-Instruct 從 2 萬代碼的 Alpaca 生成了 6.8 萬個(gè)指令樣本,其還通過排名響應(yīng)(Rank Responses)引入了強(qiáng)化學(xué)習(xí)來對齊測試與教師反饋(RRTF)。
OctoCoder 則采用了另一條路徑,其是使用 Git 提交歷史作為指令數(shù)據(jù)來微調(diào) StarCoder 和 CodeGeeX2。更近期的 CodeFuse 還使用了多任務(wù)微調(diào),顯式地將多個(gè)下游任務(wù)引入到了指令數(shù)據(jù)中。表 4 也給出了這些經(jīng)過指令微調(diào)的代碼模型的性能。
在 NLP 領(lǐng)域,另一個(gè)與指令微調(diào)緊密關(guān)聯(lián)的技術(shù)是根據(jù)人類反饋的強(qiáng)化學(xué)習(xí)(RLHF),其在對齊 LLM 與人類價(jià)值方面發(fā)揮了重要作用。將強(qiáng)化學(xué)習(xí)用于代碼有一個(gè)很自然的優(yōu)勢,因?yàn)榫幾g器可以自動(dòng)為語言模型生成的代碼樣本生成反饋。
CodeRL 就是一個(gè)這樣的模型,其會(huì)為每個(gè)生成的程序定義四個(gè)層級(jí)的獎(jiǎng)勵(lì)(即編譯錯(cuò)誤、運(yùn)行時(shí)錯(cuò)誤、單元測試失敗、通過)以及由一個(gè) critic 模型估計(jì)的細(xì)粒度的 token 層面的獎(jiǎng)勵(lì)。其 actor 模型擴(kuò)展自 CodeT5,然后再使用 REINFORCE 算法訓(xùn)練。類似地,CompCoder 和 PPOCoder 使用近端策略優(yōu)化(PPO)分別訓(xùn)練了 CodeGPT 和 CodeT5,而 RLTF 則提出基于編譯器提供的報(bào)錯(cuò)信息和位置給出細(xì)粒度反饋,并使用考慮了已通過測試案例比例的適應(yīng)性反饋。
語言模型所用的代碼特征
編程語言和自然語言的一大主要差異是:前者是人工定義的,力求精確無歧義,并且需要在執(zhí)行之前無錯(cuò)誤地編譯(或解釋)。這樣一來,除了 CLM、MLM 和 Span Corruption 等詞匯操作之外,在設(shè)計(jì)代碼的預(yù)訓(xùn)練目標(biāo)方面會(huì)有更大的靈活性。
編程語言在句法特征等方面有很大的優(yōu)勢。C、Python 和 Java 等每個(gè)主流編程語言都有現(xiàn)成可用的編譯器工具包,可以輕松且準(zhǔn)確地提取出程序的語義信息,比如抽象語法樹(AST)、與語言無關(guān)的中間表征(IR)以及每個(gè) token 的類型和控制 / 數(shù)據(jù)流圖(CFG/DFG)等輔助信息。因此,對于用于代碼的 Transformer 式語言建模,很多研究工作將這些特征整合進(jìn)了他們的訓(xùn)練流程。
抽象語法樹和中間表征
Jiang et al. (2021) 提出的 TreeBERT 是最早嘗試把 AST 用于基于 Transformer 的預(yù)訓(xùn)練 - 微調(diào)框架的模型之一。這是一個(gè) Transformer 編碼器 - 解碼器模型,其預(yù)訓(xùn)練使用了 Tree MLM 和 Node Order Prediction。
之后還出現(xiàn)了 SynCoBER、SPT-Code 和 UniXcoder 等研究成果,詳見原論文。
在編譯流程中,AST 后面通常跟著與語言無關(guān)的中間表征,比如 LLVM IR。這種獨(dú)立于特定編程語言的特征讓它們非常適合作為轉(zhuǎn)譯中樞。
控制流和數(shù)據(jù)流
盡管研究已經(jīng)證明 AST 和 IR 對特定任務(wù)(如代碼轉(zhuǎn)譯)來說很有用,但它們本質(zhì)上是靜態(tài)的,就像源代碼一樣,并且可能無法捕獲僅在運(yùn)行時(shí)揭示的代碼的語義屬性。而控制流和數(shù)據(jù)流等動(dòng)態(tài)特征中包含這樣的語義。
類似于 AST,在預(yù)訓(xùn)練 Transformer 興起之前,要使用專門的網(wǎng)絡(luò)來處理這樣的信息,比如 ProGraML 使用的消息傳遞神經(jīng)網(wǎng)絡(luò)。但是不同于 AST,即使在預(yù)訓(xùn)練 Transformer 變得主流之后,也少有研究探索這個(gè)方向。
GraphCodeBERT 就是這樣一項(xiàng)研究,其會(huì)為流圖中的變量創(chuàng)建特殊的 token 和位置嵌入,并將這個(gè)變量序列連接到文本和源代碼后面來構(gòu)建模型輸入,其還使用了針對代碼和變量段定制的注意力掩碼。
類型
除了 AST、IR 和數(shù)據(jù)流,類型信息也會(huì)被用于輔助語言模型處理代碼。舉個(gè)例子,CugLM 在微調(diào)階段使用了類型信息來輔助單向 MLM (即有單向注意力掩碼的 MLM)的 token 預(yù)測:首先是根據(jù)最終 Transformer 層的表征預(yù)測掩碼 token 的類型,然后基于隱藏表征和預(yù)測的類型預(yù)測 token 本身。相比之下,CodeT5 和 SynCoBERT 的預(yù)訓(xùn)練目標(biāo)中都包含標(biāo)識(shí)符標(biāo)記,這可以被視為粗粒度的類型預(yù)測。
值得一提的是,Wang et al. (2022) 將上述的許多特征整合進(jìn)了 Code-MVP:源代碼、文檔字符串、AST、CFG 以及通過標(biāo)識(shí)符重命名、循環(huán)交換和死代碼插入等方式轉(zhuǎn)換過的源代碼。該模型是從 GraphCodeBERT 初始化,然后使用 MLM、細(xì)粒度的類型預(yù)測和不同角度的對比學(xué)習(xí)(比如文本與代碼、代碼與 AST、代碼與 CFG)來進(jìn)行訓(xùn)練。
軟件開發(fā)中的 LLM
隨著語言模型在軟件工程基準(zhǔn)上創(chuàng)造新記錄,軟件工程技術(shù)也正反過來擴(kuò)展語言模型的邊界,并將其帶入現(xiàn)實(shí)世界的開發(fā)周期。
使用編程工具擴(kuò)展 LLM
NLP 社區(qū)的研究已經(jīng)表明 LLM 可以學(xué)習(xí)使用外部工具,比如計(jì)算器、機(jī)器翻譯系統(tǒng)和搜索引擎。因此可以使用解釋器來增強(qiáng) LLM 處理復(fù)雜推理任務(wù)的能力。PAL 和 PoT 都使用了 Python 解釋器來擴(kuò)展 Codex,使其具備數(shù)值計(jì)算能力,而 ViperGPT 則是通過調(diào)用視覺 API 進(jìn)行了進(jìn)一步擴(kuò)展,使其可以提取視覺輸入的信息并回答相關(guān)問題。
除了減輕抽象的推理任務(wù)中數(shù)值計(jì)算的負(fù)擔(dān),解釋器也可對代碼生成過程本身提供反饋以及進(jìn)行單元測試。CodeT 和 TiCoder 使用 Codex 來生成單元測試,這些測試運(yùn)行在生成的代碼樣本上,可以提升模型在代碼合成上的性能。類似地,TransCoder-ST 通過執(zhí)行代碼轉(zhuǎn)譯的外部單元測試增強(qiáng)了 TransCoder 和 DOBF。另外,單元測試的執(zhí)行結(jié)果可作為代碼強(qiáng)化學(xué)習(xí)的自然監(jiān)督信號(hào)。
值得一提的是,OpenAI 在 2023 年 3 月為 ChatGPT 發(fā)布了一個(gè)解釋器插件,該插件可以接受用戶的文件輸入,根據(jù)用戶指令生成代碼,并通過實(shí)時(shí)執(zhí)行提供反饋。Zhou et al. (2023) 的研究表明這一功能讓 GPT-4 可以自我調(diào)試。
在 LLM 研究中,一個(gè)與使用工具緊密關(guān)聯(lián)的主題是作為智能體進(jìn)行規(guī)劃,理論和實(shí)驗(yàn)研究均表明這可以提升 LLM 的能力。Ruan et al. (2023) 發(fā)現(xiàn) LLM 可以使用外部 SQL 生成器和 Python 生成器進(jìn)行規(guī)劃來解決復(fù)雜任務(wù),而 CodePlan 可通過自適應(yīng)規(guī)劃執(zhí)行代碼庫層面的編程。
另一類工作是使用 LLM 來創(chuàng)建用于代碼生成的多智能體系統(tǒng),比如 self-collaboration、ChatDev 和 MetaGPT。在這些框架中,多個(gè) LLM 各自扮演著不同的角色,比如編程者、審查者和管理者。這些角色相互交互,將代碼生成任務(wù)分為不同的階段(比如設(shè)計(jì)、寫代碼、測試和做文檔),并通過協(xié)作來完成復(fù)雜任務(wù)。
將 LLM 整合進(jìn)軟件開發(fā)
隨著 LLM 的交互式編程能力的提升,研究者已經(jīng)開始將其整合進(jìn)軟件開發(fā)的整個(gè)過程中。
自動(dòng)代碼補(bǔ)全是語言模型在軟件開發(fā)領(lǐng)域的最早期應(yīng)用之一,因?yàn)檫@一任務(wù)只需要預(yù)測下一 token 的能力。即使是在語言模型的規(guī)模達(dá)到數(shù)十億參數(shù)之前,就已經(jīng)有人將 Pythia 和 IntelliCode 等代碼補(bǔ)全系統(tǒng)整合進(jìn)常用的 IDE 了。
不過近段時(shí)間,代碼語言模型的應(yīng)用已經(jīng)超越了簡單的代碼補(bǔ)全。GitHub Copilot 可以說是最流行的 AI 編程助理之一,其具備非常多功能,包括代碼生成、漏洞檢測和證書管理,而 CodeFuse 也將代碼生成、代碼轉(zhuǎn)譯、代碼注釋和測試用例生成整合成了單一的 IDE 插件,但是,隨著代碼語言模型越來越大,它們的客戶端部署和實(shí)時(shí)性能也遭遇了新的挑戰(zhàn)。
隨著 LLM 持續(xù)發(fā)展,基于它們構(gòu)建應(yīng)用本身也正在變成一項(xiàng)具有重要價(jià)值的任務(wù)。目前已經(jīng)出現(xiàn)了許多針對此類應(yīng)用的開源框架,包括 LangChain、AutoGPT 和 WorkGPT。
總結(jié)和挑戰(zhàn)
這份綜述系統(tǒng)性地回顧了使用預(yù)訓(xùn)練 Transformer 語言模型處理代碼的歷史,并強(qiáng)調(diào)了它們與一般領(lǐng)域預(yù)訓(xùn)練模型的關(guān)系,還進(jìn)行了比較。
代碼建模的進(jìn)步通常緊隨 NLP 的歷史進(jìn)程:從 SMT 模型發(fā)展到 NMT 模型,然后到微調(diào)的預(yù)訓(xùn)練 Transformer,最后到 LLM 的少樣本應(yīng)用甚至現(xiàn)實(shí)世界產(chǎn)品中的自主智能體。
不用于自然語言,代碼的本質(zhì)讓我們可以輕易從不同角度提取輔助信息,并利用解釋器和單元測試來獲取自動(dòng)反饋。
在此基礎(chǔ)上,作者最后指出了當(dāng)前代碼建模領(lǐng)域所面臨的一些挑戰(zhàn):
- 為了將代碼 LLM 推進(jìn)至下一階段,需要一些全面的基準(zhǔn)
- 獲取高質(zhì)量數(shù)據(jù)
- 將代碼特征整合進(jìn)語言模型
- 將 LLM 用于更多代碼下游任務(wù)
- 其它可替代的模型架構(gòu)和訓(xùn)練目標(biāo)
- 構(gòu)建用于軟件開發(fā)整個(gè)生命周期的代碼 LLM 生態(tài)系統(tǒng)
- 與代碼 LLM 相關(guān)的安全和道德倫理問題