楊 光 周 宇 陳 翔 張翔宇
1 (南京航空航天大學計算機科學與技術學院/人工智能學院/軟件學院 南京 211106)
2 (南通大學信息科學技術學院 江蘇南通 226019)
(yang.guang@nuaa.edu.cn)
代碼合成是一項自動化程序開發技術,旨在根據給定的規范和約束條件生成代碼[1]. 根據輸入的模態,Ren 等人[2]將代碼合成分為文本到代碼 (text-tocode)和代碼到代碼 (code-to-code)這2 種類型[3]. 其中,文本到代碼是將自然語言描述轉換為可執行代碼的過程,例如代碼生成[4];而代碼到代碼則是將現有代碼轉換為滿足新需求的代碼,例如代碼遷移[5].這2 種技術都可以提高軟件開發效率和質量,在實際應用中都具有重要的價值. 此外,代碼合成還可以為程序員提供一種更加友好的編程方式[6],并吸引那些在特定編程語言上經驗有限的程序員新手參與軟件開發. 因此,代碼合成對軟件開發行業具有重要意義,并在其發展過程中變得越來越重要.
近年來,隨著生成式AI 模型[7]的快速迭代,代碼合成領域取得顯著的發展,包括各種強大模型 (例如CodeT5[8],CodeGen[9]和CodeGeeX[10])的出現和多種數據集(例如Lyra[11],MBPP[12]和CONCODE[13])的構建. 盡管有這些令人振奮的進展,但代碼合成的評價指標在現有的研究中受到的關注有限. 評估指標在代碼合成領域起著至關重要的作用,它們可以為研究人員和開發人員提供重要的指導和支持,幫助改進模型性能. 目前,常用的代碼評估指標可以分為3 類:基于匹配、基于語義和基于執行的指標. 基于匹配的指標,例如BLEU[14]和ChrF[15],將代碼視為文本,并僅關注詞素 (token)級別的匹配分數. 基于語義的指標,例如CodeBLEU[2],考慮到代碼的句法結構和數據流信息可作為代碼的語義信息,并將代碼與詞素信息混合計算. 基于執行的指標,例如Pass@k[16],通過人工編寫測試用例,并根據代碼能否通過測試用例來評估模型的性能. 其中,基于執行的Pass@k指標能更精準地判斷預測代碼的功能準確性,因此,本文以Pass@k 指標作為標準的功能準確性. 但該指標在實際評估時,需要大量的人力、時間和成本開銷,這在實際應用場景中并不總是可行的. 因此,亟需設計一種自動化評估指標,在無需測試用例時仍可評估預測代碼的功能準確性.
此外,一個好的評估指標應該具備魯棒性,即當預測代碼發生微小改變時,評估指標仍能保持準確性. 然而現有的評估指標并不魯棒,如圖1 所示,只有當預測代碼b與參考代碼a完全一致時,現有的指標才能給出正確的分數. 然而,當代碼中的用戶標識符被修改或對代碼進行了等價的語法轉換時,即預測代碼c和代碼d,此時代碼c、代碼d與參考代碼a的功能是一致的,但現有的指標無法識別它們,特別是BLEU 指標,認為代碼c與參考代碼a的相似度僅為0.040. 另外,即使對代碼進行微小的語義改變,即預測代碼e,此時代碼e與參考代碼a的功能并不一致,但現有的評估指標仍無法正確識別它們,這種不魯棒問題限制了現有評估指標的有效性. 因此,本文對代碼合成評估指標的魯棒性檢驗提出了3 種假設:

Fig. 1 Example of a robustness problem for code synthesis evaluation metrics圖1 代碼合成評估指標的一個魯棒性問題示例
假設1. 當生成的代碼中發生用戶自定義標識符替換時,指標分數應基本不變;
假設2. 當生成的代碼中發生語法等價轉換時,指標分數應基本不變;
假設3. 當對語義正確的代碼進行語義變異時,原本得分高的指標應該大幅度降低.
假設1~3 旨在評估現有評估指標在應對代碼改變時的魯棒性,并為改進和開發更可靠的評估指標提供指導.
近年來,評估代碼合成的一個流行趨勢是設計基于代碼的預訓練語言模型[17](pre-trained language models of code,CodePTMs). 相較于依賴詞素層面的評估指標,通過提取代碼內在的語義向量進行評估被認為是一個具有潛力的方向[18]. 本文提出了一種魯棒的評估指標CodeScore-R,它利用代碼預訓練語言模型UniXcoder[19]來評估代碼合成的功能準確性. 為了減輕用戶標識符命名風格對指標的干擾,本文提出了一種基于抽象語法樹 (abstract syntax tree,AST)的代碼草圖化處理方法,該方法從代碼中提取用戶自定義標識符,并用統一的占位符進行替換. 為了提升指標評估代碼合成的功能準確性和魯棒性,本文提出了針對代碼的對比學習框架ConCE (contrastive learning of code embedding). 該框架通過最小化正樣本之間的語義距離和最大化負樣本之間的語義距離來學習代碼的表征. 通過語義向量之間的余弦相似度,可以評估代碼合成的功能準確性. 在構造正樣本方面,CodeScore-R 通過進行語法等價轉換來生成代碼變體;而對于負樣本,則通過利用變異測試中的運算符變異來對代碼進行微小的改變.
為評估CodeScore-R 的有效性,本文在代碼生成和代碼遷移任務上進行實驗. 在代碼生成任務中,使用帶有測試用例的HumanEval[20]和HumanEval-X[10]數據集,而在代碼翻譯任務中,本文使用AVATAR[21]數據集,并通過眾包的方式手工構造了相應的測試用例. 實驗結果表明,對于Java 與Python 語言上的代碼生成和遷移任務中,CodeScore-R 的表現優于現有評估指標,可以更接近Pass@k 指標,并具有更強的魯棒性.
本文的主要貢獻有3 點:
1) 提出一種基于UniXcoder 和對比學習的魯棒指標CodeScore-R,用于自動化評估代碼合成功能的準確性.
2) 引入草圖化處理、語法等價轉換和變異測試等技術,以減輕標識符、語法結構和運算符對評估結果的擾動.
3) 在Java 和Python 語言上的代碼生成和遷移任務中,CodeScore-R 的表現優于現有評估指標,并具有更強的魯棒性.
當前已經有部分研究專注于不同的代碼合成評估指標,這些指標對于衡量代碼合成系統生成的代碼質量至關重要. Liguori 等人[22]對現有代碼合成評估指標和人工評估在生成攻擊性代碼 (offensive code)的相似性進行了全面分析,他們的實驗結果指出現有的指標通常不能提供準確的評估結果. 目前,自動化代碼評估指標主要可以分為3 類:基于匹配、基于語義和基于執行的指標. 此外,一些研究還通過人工評估的方法對預測代碼進行分析.
基于匹配的評估指標主要局限于對詞素粒度的相似性計算,而忽略了代碼的潛在語義信息. 這類指標源自機器翻譯、文本摘要等領域,包括BLEU[14],Rouge[23],和ChrF[15]等指標. 它們通過比較參考文本和預測文本之間的n-gram 匹配程度來計算分數. 此外,精準匹配度 (exact match,EM)指標也被廣泛應用于代碼合成任務[24]中.
然而,Eghbali 等人[25]指出,由于編程語言冗長的語法和編碼約定,即使是完全不相關的代碼片段也可能存在許多共同的n-grams 信息. 例如,在Java 代碼中,會出現大量的括號與分號的組合,這些冗余的信息可能導致BLEU 指標的結果虛高;為了提高評估指標的準確性和可區分性,提出了CrystalBLEU 指標,該指標在BLEU 指標的基礎上移除出現頻率最高的n-grams 信息. 此外,Liguori 等人[22]認為,與其他基于匹配的指標相比,編輯距離(edit distance,ED)能夠更好地衡量代碼之間的相似性.
基于語義的評估指標考慮了代碼的語法結構、數據流信息和潛在語義信息,但是仍不夠魯棒. Ren 等人[2]認為基于匹配的指標忽略了代碼中的句法和語義特征,而EM 指標過于嚴苛,無法識別出語義相同但語法不同的樣本. 為此,他們提出了CodeBLEU 指標,該指標根據代碼中的關鍵詞進一步改進BLEU 指標,并進一步通過AST 注入代碼語法和通過數據流注入代碼語義.
Dong 等人[26]則基于CodePTM 提出CodeScore 指標,在帶有測試用例的數據集上進行有監督學習,以此進行代碼合成的功能性評估. 然而,這種方法在訓練時依賴于帶有測試用例的數據集,成本較高. 另一方面,Zhou 等人[27]利用CodePTM 提取代碼的潛在語義. 具體而言,他們提出了CodeBERTScore,利用CodeBERT 模型[28]在大規模數據集上進行自監督學習,再對參考代碼和預測代碼進行上下文編碼,計算每個詞素之間的相似性分數.
基于執行的評估指標能準確判斷預測代碼的功能準確性,但需要投入大量的成本,包括測試用例的構造、解決運行環境的依賴問題,以及耗費大量時間進行測試用例的運行.
Kulal 等人[16]首次提出了基于測試用例的評估指標Pass@k,為每個問題生成了K個代碼樣本,并評估了K個樣本中任意一個樣本能夠通過單元測試集的比率. 另一方面,Liang 等人[11]則提出了Code Executable 指標,用于判斷預測代碼是否能通過編譯器的編譯,該指標旨在沒有測試用例的情況下觀察預測代碼的質量.
除了自動化評估指標外,人工評估也是一種可靠的方法,可以全面評估預測代碼的準確性、語法、語義、復雜性、可讀性、安全性等方面. 然而,對每個編程問題進行手動評估是不切實際的,因為這需要大量的時間和成本.
因此,Yang 等人[29]提出了基于采樣的方法,并將該方法應用于小規模實證研究中. 這種方法可以在可承受的時間和資源范圍內獲取對預測代碼的高質量評估.
在代碼合成任務中,通常面臨以下問題:給定一個上下文x(例如,自然語言功能描述或者源代碼),將x輸入到代碼合成模型M中,生成一個預測代碼片段,然后使用自動化評估指標來評估預測代碼的質量. 評估通常使用度量函數來比較預測代碼與參考代碼y?.
UniXcoder[19]是一種基于Transformer[30]的代碼預訓練語言模型,它在多項編程任務中表現出色. 該模型使用CodeSearchNet 數據集[31]進行了預訓練,該數據集包含了來自6 種編程語言(Ruby,Java,Python,PHP,Go和Javascript)的約2.3×107個代碼樣本. UniXcoder通過使用3 種不同類型的自注意力掩碼策略來控制模型的行為,同時兼容編碼、解碼和編解碼3 種模式.除了基本的預訓練任務,如掩碼語言模型(masked language modeling,MLM),還提出了一些新的預訓練任務,包括統一語言建模、去噪任務和代碼片段表征學習等.
與其他CodePTMs 相比,UniXcoder 能更全面地利用AST 提供的代碼結構信息,從而彌補了AST 和詞素表示的差異. 此外,UniXcoder 還通過對比學習來學習代碼片段的表征,使其在計算代碼之間的相似度任務中更加適用.
本節主要介紹CodeScore-R 指標的設計方法及具體實現,該指標的整體框架如圖2 所示. CodeScore-R 以UniXcoder 為基座模型,并采用本文提出的ConCE框架進行自監督的代碼表征學習. 通過利用經過表征學習的UniXcoder 模型,CodeScore-R 能夠對生成的代碼進行評估計算. 接下來將介紹CodeScore-R 的具體實現細節.

Fig. 2 CodeScore-R framework圖2 CodeScore-R 框架
ConCE 框架由數據預處理、正負樣本構造以及表征學習任務3 部分組成.
3.1.1 數據預處理
為了降低不同標識符命名風格對評估指標的干擾,即為了滿足假設1,CodeScore-R 在數據預處理階段對代碼片段進行處理. 首先,CodeScore-R 將代碼片段解析為抽象語法樹(abstract syntax tree,AST),并根據預定義的規則識別出代碼中用戶自定義的標識符,例如函數名、參數名和變量名. 然后,采用草圖化的方法統一變量命名風格. 圖3 展示了預處理前后的對比示例圖. 由于參數、變量及函數名的命名與程序員的編碼習慣相關,這可能會對評估指標的計算產生干擾. 但是,對參數、變量及函數名進行草圖化處理并不會影響代碼的語法和語義信息.

Fig. 3 An example of code pre-processing圖3 代碼預處理示例
具體來說,CodeScore-R 利用tree-sitter 工具①https://github.com/tree-sitter對代碼片段進行解析,并根據每個類型為identifier 的葉子節點的父節點進行判斷,以識別出函數名、參數名和變量名的詞素信息. 草圖化是將這些詞素以統一的編碼方式進行逐一替換. 例如,函數名替換為“f”,參數名和變量名分別按照先后順序替換為{arg_0,arg_1, …,arg_m}和{var_0,var_1, …,var_n}. 在后續的正負樣本構造及表征學習中,CodeScore-R 都是使用草圖代碼(sketch code)而不是原始代碼(origin code)進行實驗,以盡可能地避免標識符詞素對評估指標的影響.
3.1.2 正負樣本的構造
為了進行后續的表征學習,CodeScore-R 需要構造正負樣本. 對于正樣本的構造,CodeScore-R 借鑒了SimCSE[32]中的思想,一方面采用2 次不同的dropout 方法生成正樣本,以增強其對代碼語義的理解和魯棒性. 另一方面,本文根據代碼的語法特性,對代碼進行語法上等價的轉換,生成與原始代碼功能相同但形式不同的代碼片段. 這種轉換可以包括改變代碼中的控制流結構、使用不同的語法特性等.通過這樣的等價轉換,可以擴展訓練數據集,提供更多樣化的正樣本供CodeScore-R 進行學習. 為了確保生成語法等價的代碼質量,選擇了代碼重構[33]中常見的4 種規則進行操作,具體規則見表1.

Table 1 Table of Code Syntax Equivalence Transformation Rules表1 代碼語法等價轉換規則表
循環交換是將for 循環替換為等效的while 循環或將while 循環替換為等效的for 循環. 這樣的交換可以改變循環結構的表達方式,但保持了代碼功能的等效性. 表達式交換是基于運算符特性進行等價替換,例如將“a+=b”替換為“a=a+b”. 這種交換在語義上保持了表達式的等效性,但改變了表達式的形式. 判斷體交換和判斷條件交換是常見的代碼重構規則,用于條件語句的等價轉換. 判斷體交換將條件語句中的if 分支和else 分支進行交換,而判斷條件交換交換條件表達式中的2 個子表達式. 這樣的交換保持了條件語句的等效性,但改變了條件語句的結構或條件的順序.
對于負樣本的構造,CodeScore-R 采用了變異測試的思想. 變異測試[34]是一種軟件測試方法,通過對原始代碼進行變異 (如改變運算符、改變變量引用等),生成具有細微差異的代碼,從而檢驗測試用例的充分性和代碼的健壯性. 在構造負樣本時,Code-Score-R 也使用了類似的方法. 它通過對原始代碼進行運算符的變異操作,例如將加法操作變異為減法操作或將邏輯運算符變異為移位運算符等,可以生成與原始代碼形式上相似但在語義上存在不同的負樣本,具體變異規則如表2 所示. 通過引入這樣的負樣本,CodeScore-R 能夠區分細微差異的代碼,并提升對代碼變異的魯棒性.

Table 2 Table of Code Mutation Testing Rules表2 代碼變異測試規則表
3.1.3 表征學習任務
為了進行表征學習,CodeScore-R 采用了2 個自監督預訓練任務,分別是掩碼語言模型和對比學習,如圖4 所示. 這些任務旨在讓模型學習代碼的語義信息,并能夠區分代碼之間的微小差異.

Fig. 4 Illustration of code representation learning tasks圖4 掩碼表征學習任務示例圖
1)掩碼語言模型. 掩碼語言模型的任務是最大化正確預測被屏蔽詞素的概率,以使CodeScore-R 能夠學習到代碼的語義表示. 在數據預處理階段,由于對代碼進行了草圖化處理,導致草圖代碼的詞素失去了原始代碼中部分語義信息. 為了確保模型能夠學習到完整的語義信息,本文引入了代碼對應的注釋NL,并隨機選擇草圖代碼中15%的詞素進行掩碼操作. 具體而言,該任務以一定的概率對選定的詞素進行替換,其中,以80%的概率將詞素直接替換為特殊標記“<mask>”,以10%的概率將詞素隨機替換為其他詞素,而剩下的以10%的概率保持詞素不變. 通過這種方式,模型需要預測被掩碼的詞素,從而學習到代碼的語義信息.
給定一個NL-code 對的數據 (d={w,c}) 作為輸入,其中w是NL 的序列,c是代碼詞素的序列,可以將掩碼操作定義為:
掩碼語言模型的目標是預測被屏蔽掉的原始標記,可以定義為:
2)對比學習. 對比學習任務旨在使模型能夠區分正樣本和負樣本,以增強對微小差異的敏感性. 對于正樣本的構造,本文采用3.1.2 節提出的2 種方法:50%的概率通過2 次dropout 得到正樣本和50%的概率通過代碼語法等價轉換得到正樣本. 這樣的設計既避免了模型對輸入長度的敏感性問題,又增加了模型對不同語法的識別能力,提高了模型的語法魯棒性. 對于負樣本的構造,同樣采用3.1.2 節提出的基于變異測試的方法. 考慮到正、負樣本的構造都是基于多種規則的,為了提升樣本的多樣性,本文使用組合的方式將這些規則進行融合,再從中隨機抽選出正樣本和負樣本.
給定一個代碼片段ci,我們將ci+記為正樣本,將ci?記為負樣本,一起組合為 (ci,ci+,ci?),利用UniXcoder對它們進行語義向量提取,得到向量hi,hi+,hi?. 具體的提取方法是先對輸入的代碼進行上下文編碼得到其隱藏向量,其中N表示為輸入代碼的長度,d表示為向量的維度. 接著提取第一個詞素,即[CLS]的向量值,并經過一層ReLU 層進行激活,最終作為代碼的語義表征h. 對比學習任務的損失函數定義為:
其中batch代表批次的大小,sim 代表余弦相似度. 最終,ConCE 框架的優化目標可設置為:
CodeScore-R 的評估流程為:首先,以預測代碼和參考代碼作為輸入. 為了避免預測代碼包含語法錯誤,CodeScore-R 借助編譯器判斷預測代碼是否能夠編譯通過. 如果預測代碼無法通過編譯,則直接輸出的功能準確性分數為0. 如果預測代碼通過了編譯,則對預測代碼和參考代碼進行草圖化處理,以減輕標識符對評估結果的影響. 接著,CodeScore-R 借助經過表征學習后的UniXcoder,分別提取預測代碼和參考代碼的語義表征向量,并進行余弦相似度計算. 通常來說,余弦相似度計算結果的值域為[?1, 1]. 然而,由于在語義表征向量提取過程中使用了ReLU 激活函數,語義表征向量保持非負值不變. 因此,經過ReLU 激活后的語義表征向量中的每個元素都是非負的.
余弦相似度的計算公式為:
其中,x·y表示向量x和y的內積,‖x‖ 和 ‖y‖分別表示向量x和y的范數. 由于語義表征向量中的元素都是非負的,內積和范數的結果也是非負的. 因此,余弦相似度的分子是非負的內積,分母是非負的范數乘積,所以余弦相似度的結果也是非負的,即值域為[0, 1].
為了更好地擬合Pass@k 指標,CodeScore-R 加入了后處理操作,即對相似度分數進行二值化處理,最終輸出預測代碼的功能準確性分數:若相似度分數大于0.5,輸出為1;否則輸出為0.
為了驗證本文提出的CodeScore-R 的有效性,本文設計了5 個實驗問題.
問題1:與現有指標相比,CodeScore-R 對功能準確性的擬合程度如何?
問題2:與現有指標相比,CodeScore-R 針對代碼標識符擾動下的魯棒性如何?
問題3:與現有指標相比,CodeScore-R 針對代碼語法擾動下的魯棒性如何?
問題4:與現有指標相比,CodeScore-R 針對代碼語義擾動下的魯棒性如何?
問題5:不同的語義提取方法對CodeScore-R 有什么影響?
本文以CodeSearchNet 數據集[31]作為表征學習的數據集,具體來說,我們提取其中的Java 代碼和Python 代碼以及它們相應的功能注釋,并對它們進行預處理和正、負樣本的構造. 由于不是每個代碼都能根據規則轉換為相應的變體代碼,因此過濾出那些無法構造正、負樣本的代碼以作為最終的預訓練數據集.
對于下游任務,本文在2 種編程語言Java 和Python 任務上評估了CodeScore-R,包括代碼生成任務和代碼遷移任務.
代碼生成任務是根據用戶的功能描述加上代碼簽名(signature)來生成相應的代碼. 本文使用由Python語言構造的HumanEval 數據集[20]和包含了Java 語言的HumanEval-X 數據集[10]作為實驗對象,這些數據集由包含了164 條帶有測試用例的樣本構成.
代碼遷移任務是根據一種編程語言的源代碼生成另一種編程語言的目標代碼. 本文使用AVATAR數據集[21],其中包含了挖掘自在線編程網站上的Java 和Python 的代碼對. 我們從中隨機挑選了200 對數據并手工構造測試用例,為了保證測試用例的質量,我們通過眾包的方式聘請具有2~3 年開發經驗的工程師為每個代碼段構造5 條測試用例以確保測試用例的多樣性.
本文選擇10 種代碼合成評估的基準指標,包括BLEU[14],ROUGE-L[23],ChrF[15],ED[22],WeightBLEU[2],SyntaxMatch[2],DataflowMatch[2],CodeBLEU[2],CrystalBLEU[25],和CodeBERTScore[27]. 這些指標被廣泛使用在代碼合成的相關研究中. 其中,BLEU,ROUGE-L,ChrF,ED 和CrystalBLEU 是基于匹配的評估指標;CodeBLEU 和CodeBERTScore 是基于語義的評估指標;WeightBLEU,SyntaxMatch,DataflowMatch是CodeBLEU 計算過程中設計出的指標,分別對應改進的BLEU、語法匹配與數據流匹配的計算.
為了評估現有評估指標和代碼功能準確性之間的擬合程度,現有的研究通常選擇相關系數指標[35](如Pearson 相關系數、Spearman 相關系數和Kendall相關系數)和擬合指標[36](如平均絕對誤差). 其中,相關系數是用來衡量2 個變量之間線性相關程度的指標,而擬合指標則是用來衡量模型的擬合程度的指標.
本文的目標是檢驗CodeScore-R 能否自動評估預測代碼的功能準確性,即是否能擬合Pass@1 指標的結果,因此本文選擇平均絕對誤差(mean absolute error,MAE)來評估預測的結果與實際Pass@1 結果之間的絕對誤差.MAE值越大,說明擬合程度越差;反之則說明擬合程度越好.MAE可以定義為:
在后續的實證研究中,所有實驗均運行在Windows 10 操作系統上,其內存為32 GB,CPU 處理器為Intel Core i7-9750H. 對于編譯器,本文使用Python 3.9.1 版本①https://www.python.org/downloads/release/python-391/作為Python 代碼的編譯器,并使用JDK 18.0.2.1版本②https://www.oracle.com/java/technologies/javase/18-0-1-relnotes.html編譯Java 代碼.
隨著語言模型和訓練數據的規模不斷增長,基于大型語言模型的生成式AI 表現出各種涌現行為.其中一種能力是零樣本學習,它允許模型在特定指令或提示中回答. 這些生成式AI 模型取得了出色的性能,并在代碼合成任務上也展示了廣闊的潛力. 因此,本文通過調用ChatGPT 的接口③https://platform.openai.com/docs/models/gpt-3-5(gpt-3.5-turbo)完成代碼生成與代碼遷移任務. 為了保證結果的穩定性,本文將接口中的temperature 參數設置為0,并只返回1 個代碼結果,用于計算Pass@1 指標.
經測試,ChatGPT 在Java 代碼生成任務上的Pass@1 指標為68.29%,在Python 代碼生成任務上的Pass@1 指標為71.34%;在Python-to-Java 代碼合成任務上的Pass@1 指標為80.5%,在Java-to-Python 代碼合成任務上的Pass@1 指標為86.5%.
為了評估CodeScore-R 的擬合程度,本文選用了機器翻譯領域以及代碼合成領域中常用的指標作為基準評估指標. 表3 給出了CodeScore-R 和選擇的基準方法與功能準確性之間的MAE擬合結果.

Table 3 Comparison Results Between CodeScore-R and Baseline Metrics for MAE表3 CodeScore-R 與基準指標的MAE 對比結果
表3 顯示,與所有基準指標相比,CodeScore-R 在所選的4 個下游任務數據集上對功能準確性的擬合更好. 在Java 代碼生成、Python 代碼生成、Python-to-Java 代碼遷移和Java-to-Python 代碼遷移任務中,與最優的基準指標相比,CodeScore-R 的擬合誤差分別降低了7.31%、11.42%、13.37%和17.22%. 其中,在代碼遷移任務上的擬合程度普遍優于在代碼生成任務上的擬合程度;在Python 編程語言上的擬合程度普遍優于在Java 編程語言上的擬合程度.
此外,表3 的結果指出,基于大語言模型(large language model,LLM)的評估指標普遍優于其他的基準指標,這也體現出該類指標的優勢和可行性. 在基于匹配的基準指標中,ED 的擬合結果最優,這與文獻[22]的研究結論一致,而在基于語義的基準指標中,CodeBERTScore 則表現出最好的擬合結果.
考慮到CodeScore-R 輸出的是0~1 的值,因此相較于其他指標,我們可以將CodeScore-R 的輸出與功能準確性視作分類任務,通過比較CodeScore-R 的輸出與功能準確性之間的準確率、精度、召回率和F1-Score 以進一步評估CodeScore-R 的性能. 同時可以分析表3 結果中的MAE指標是否存在假陽性或者假陰性數據過多而導致的誤差虛低的情況. 結果如圖5 所示,在代碼生成任務上,CodeScore-R 的F1-Score 值在0.8 左右,而在代碼遷移任務上,CodeScore-R 的F1-Score值在0.9 以上,該結果可以進一步表明CodeScore-R的準確性.

Fig. 5 Classification results of CodeScore-R and functionalcorrectness圖5 CodeScore-R 與功能準確性的分類結果
基于問題1 中的分析結果,我們發現CodeScore-R 在所有任務中對功能準確性的擬合程度超過了本文考慮的10 種基準指標. 然而,一個好的評估指標應具備魯棒性. 為了研究CodeScore-R 與現有基準指標在代碼標識符擾動下的魯棒性(即是否滿足假設1),以及我們提出的代碼草圖化處理的有效性,我們進行了2 組對比實驗:針對Origin-to-Sketch (O2S)的對比實驗和針對Sketch-to-Sketch (S2S)的對比實驗.
O2S 僅對預測代碼進行草圖化處理,而參考代碼保持不變. 由于草圖化處理會識別代碼中的所有用戶自定義標識符并進行統一替換,我們將其視為代碼標識符擾動的一種極端情況.
S2S 則對參考代碼和預測代碼都進行草圖化處理,以探究草圖化處理是否能緩解對指標的影響.
表4 和表5 分別展示了CodeScore-R 和所選基準方法在代碼生成和代碼遷移任務上的評估結果. 在問題2 的分析結果中,除了CodeScore-R 之外,現有基準指標對于代碼詞素擾動普遍不具備魯棒性. 以Java-to-Python 代碼遷移任務為例,在原始設置下,其BLEU 的MAE值為0.347. 然而,在O2S 設置下,即僅對預測代碼進行草圖化處理的情況下,MAE值增加至0.718,即擬合誤差增加了106.92%. 而在S2S 設置下,即對參考代碼和預測代碼都進行草圖化處理的情況下,MAE值降至0.340,與原始設置相比,誤差減少了2.02%. 這表明草圖化處理能夠提升現有基準指標的評估準確性和魯棒性. 在后續的問題3 和問題4 中,為了公平比較CodeScore-R 和現有基準方法的魯棒性,我們提前對參考代碼和預測代碼都進行了草圖化處理.

Table 4 Comparison Results for Token Perturbation on Code Generation Tasks表4 在代碼生成任務上針對詞素擾動的對比結果

Table 5 Comparison Results for Token Perturbation on Code Migration Tasks表5 在代碼遷移任務上針對詞素擾動的對比結果
為了探究CodeScore-R 與現有基準指標對代碼語法擾動下的魯棒性,即是否滿足假設2,我們根據表1 中提出的4 種規則,并通過相關組合構造出多個語法轉換方法. 在問題3 中,為了避免實驗的偶然性,我們選擇了5 個不同的隨機種子,并為每個預測代碼生成了5 種變體代碼. 然后,我們計算每個變體代碼與參考代碼之間的評估指標,并在表6 中給出了這些指標的5 次MAE值的均值.
從表6 可以觀察到,相對于代碼中的詞素擾動,現有指標在面對語法擾動時受到的影響較小. 然而,ROUGE-L 受語法擾動的影響最為顯著,在Java-to-Python 代碼遷移任務中,其MAE值從0.192 增加到0.502,即誤差增加了161.46%. 與此相比,CodeScore-R 對語法擾動的影響較小,并且在語法擾動下,其MAE值的擬合結果仍然是最佳的. 表6 的結果進一步證明了ConCE 中的表征學習方法的有效性.
為了探究CodeScore-R 與現有基準指標在代碼語義擾動下的魯棒性,即是否滿足假設3,我們根據表2 中提出的6 種運算符變異規則,并通過相關組合構造出多個語義擾動方法. 在問題4 中,我們控制了變異的比例,分別對代碼數據的25%,50%,75%和100%進行變異,以觀察不同語義擾動比例下Code-Score-R 和現有基準指標的魯棒性. 在實驗中,我們僅對能通過測試用例的代碼進行語義擾動. 如果擾動成功,將對應的Pass@1 值變為0. 為了避免實驗結果的偶然性,同樣選擇了5 個不同的隨機種子,并相應地為每個預測代碼生成5 種變異代碼. 然后,計算每個變異代碼與參考代碼的評估指標,并在表7~10 中分別給出在Java 代碼生成任務、Python 代碼生成任務、Python-to-Java 代碼遷移任務和Java-to-Python 代碼遷移任務上的MAE擬合均值.

Table 7 Comparison Results for Semantic Perturbation on Java Code Generation Task表7 在Java 代碼生成任務上針對語義擾動的對比結果

Table 8 Comparison Results for Semantic Perturbation on Python Code Generation Task表8 在Python 代碼生成任務上針對語義擾動的對比結果

Table 9 Comparison Results for Semantic Perturbation on Python-to-Java Code Migration Task表9 在Python-to-Java 代碼遷移任務上針對語義擾動的對比結果

Table 10 Comparison Results for Semantic Perturbation on Java-to-Python Code Migration Task表10 在Java-to-Python 代碼遷移任務上針對語義擾動的對比結果
從表7~10 可知,現有指標在面對語義擾動時受到的影響最嚴重,尤其是CodeBERTScore,在代碼遷移任務上的MAE值超過0.94. 一方面,其模型不具備識別代碼中微小語義誤差的能力,導致計算的相似度過高;另一方面,CodeBERTScore 計算的是每個詞素之間的相似度,導致改變語義的關鍵詞素信息被忽視. 以圖6 為例,我們根據CodeBERTScore 計算代碼段“a=a+b”和“a=a?b”之間的相似度,其計算公式為 (0.995 + 0.986 + 0.990 + 0.730 + 0.998) / 5 = 0.9398.其中,關鍵的語義詞素為“?”,但是在CodeBERTScore 的計算過程中沒有考慮為該詞素賦予更大的權重,導致了計算結果的虛高.

Fig. 6 Process diagram of CodeBERTScore calculation圖6 CodeBERTScore 計算過程圖
相比于現有指標存在一定的不魯棒問題,Code-Score-R 在下游任務上都能表現出對語義擾動具有良好的魯棒能力. 一方面,這得益于ConCE 框架讓模型具有區分語義差異的能力;另一方面也得益于使用的編譯器進行預測代碼語法正確的判斷,能夠避免變異后有語法問題的代碼對指標計算的干擾.
本文通過提取[CLS] 的語義向量并經過ReLU函數進行激活來提取代碼的語義信息. 為證明該提取方法的優勢,將本文方法其與3 種常見的語義提取方法進行比較. 這3 種語義提取方法為:
1)last-avg. 該方法對隱藏向量H的最后一層進行語義提取,并通過均值化處理得到語義向量.
2)first-last-avg. 該方法對隱藏向量H的第一層和最后一層進行語義提取,并通過均值化處理得到語義向量.
3)CLS. 該方法對隱藏向量H最后一層的[CLS]進行語義提取,不額外加入激活函數層.
將這3 種語義提取方法和本文提出的語義提取方法在S2S 的設定下進行比較. 從表11 和表12 中可以分析出,在針對Python 編程語言的下游任務中,本文提出的[CLS]+ReLU 能夠取得最優結果,而在Java編程語言的下游任務中,first-last-avg 方法可能取得更好的性能結果,因此,可以將語義提取方法當作CodeScore-R 的超參數,以更靈活地為下游任務進行評估.

Table 11 Comparison Results of Different Semantic Extraction Methods for CodeScore-R on Code Generation Tasks表11 不同的語義提取方法在代碼生成任務上對CodeScore-R 的對比結果

Table 12 Comparison Results of Different Semantic Extraction Methods for CodeScore-R on Code Migration Tasks表12 不同的語義提取方法在代碼遷移任務上對CodeScore-R 的對比結果
先前的實驗結果表明CodeScore-R 的指標誤差均小于現有基準指標,但是并沒有直觀地分析該指標滿足對代碼合成評估指標的魯棒性提出的3 個假設. 為進一步探究CodeScore-R 是否滿足對代碼合成評估指標的魯棒性提出的3 個假設,本節旨在通過直觀的分數值對比來進行驗證.
具體而言,分別給出了CodeScore-R 和選擇的基準指標在Java 代碼生成、Python 代碼生成、Python-to-Java 代碼遷移和Java-to-Python 代碼遷移的計算分數.如表13~14 所示,其中,“原始”意為不對預測代碼進行擾動,“詞素擾動”意為對所有的預測代碼進行草圖化處理,而參考代碼保持不變,“語法擾動”意為對所有的預測代碼進行等價語法轉換,而參考代碼保持不變,“語義擾動”意味對所有的預測代碼進行變異,而參考代碼保持不變. 這些擾動的方法的設置與實驗部分的設置保持一致.

Table 13 Comparison Results of Different Metrics Score on Code Generation Tasks表13 代碼生成任務上不同指標分數對比結果

Table 14 Comparison Results of Different Metrics Score on Code Migration Tasks表14 代碼遷移任務上不同指標分數對比結果
從表13~14 中可以分析出,無論是在代碼生成任務還是代碼遷移任務上,現有的指標均不能同時滿足提出的3 種假設. 其中,大部分指標滿足假設2,即當生成的代碼中發生語法等價轉換時,指標分數應基本不變. 然而,指標分數對于詞素的擾動和語義的擾動并不敏感,以CodeBERTScore 在Java-to-Python代碼遷移任務上的指標分數為例,其在“原始”條件下的指標分數為0.966,但是在“詞素擾動”條件下的分數為0.803,并不符合假設1;此外,在“語義擾動”條件下,其指標分數為0.960,表明該指標不能真實分辨出代碼的功能語義,即不符合假設3.
相比之下,CodeScore-R 能同時滿足提出的3 種假設. 特別是假設3,以Java-to-Python 代碼遷移任務上的指標分數為例,CodeScore-R 在“語義擾動”條件下計算出的指標分數為0.371,遠低于其在“原始”條件下計算出的指標分數0.980,符合假設3. 因此,Code-Score-R 相較于其他基準指標,具有更強的魯棒性.
CodeScore-R 計算相似度并進行二值化操作后,通過比較閾值返回最終的預測結果. 為了進一步分析閾值的取值,我們對閾值0~1,以步長為0.1 進行了詳細的分析. 表15 展示了不同相似度閾值下Java 與Python語言的代碼生成和代碼遷移任務的對比結果. 這些結果展示了CodeScore-R 在不同閾值下的擬合性能.

Table 15 Comparison Results of Different Similarity Thresholds表15 不同相似度閾值的對比結果
觀察結果可以發現,閾值的選擇對代碼生成和代碼遷移任務的評估指標有類似的影響. 具體而言,當閾值過大時,擬合效果會變差. 例如,在Python代碼生成任務中,當閾值設定為0.9 時,MAE值會從0.2 上升到0.5. 此外,閾值的最優選擇也會受到不同數據集和任務的影響. 綜合考慮整體效果,我們建議將閾值默認取值設定為0.5,這樣可以獲得比較綜合的優勢.
本文提出了一種自動化魯棒指標CodeScore-R,用于評估代碼合成功能的準確性. 然而,該指標仍然存在一些局限性. 一方面,CodeScore-R 需要依賴編譯器來檢測預測代碼的語法正確性,而現有的基準指標則不存在上述限制,這可能導致CodeScore-R 與基準指標的比較存在一定的不公平性. 另一方面,由于深度神經網絡本身存在“各向異性” (anisotropic)的特性,在一些情況下,即使2 個代碼片段存在一定的語義差異,但由于它們之間仍然具有一些共享特征,導致其在余弦相似度計算時一般會得到較高的分值.
第1 個內部有效性威脅因素是CodeScore-R 在實現過程中可能存在潛在缺陷,包括代碼的草圖化處理方法、正負樣本的構造和模型的表征學習等方面.為了減輕這些缺陷的影響,我們對處理后的代碼進行了檢驗,以驗證其是否能通過測試用例. 在模型的表征學習方面,我們采用了PyTorch 框架①https://pytorch.org/和成熟的第三方庫Transformers②https://github.com/huggingface/transformers進行實現,以確保實現的正確性和可靠性.
第2 個內部有效性威脅是選擇的基準指標是否合理. 考慮到CodeScore 工作需要在相關數據集上進行有監督學習,而其余指標則是通過自監督或者無監督的方法進行計算. 為了確保結果的公平性和可比性,我們選擇了在先前的代碼合成研究中廣泛采用的基準指標,并使用公開的第三方庫進行了統一實驗.
外部有效性是指研究結果在多大程度上可以推廣到實驗所使用的數據集之外. 我們在2 個下游任務上進行了實驗,并同時關注Java 和Python 編程語言. 對于Java 和Python 編程語言的其他數據集,CodeScore-R 可以直接使用. 然而,對于其他編程語言的代碼合成任務,需要先在相應編程語言的數據集上進行ConCE 表征學習,然后才能應用于該編程語言的代碼合成任務中.
此外,在研究中,我們僅調研了ChatGPT 模型而未考慮傳統的方法,這是因為傳統方法在代碼生成和遷移任務中存在的一些限制和挑戰,例如代碼的復雜性和語義的多樣性,傳統的方法一般難以解決這些問題,導致這些代碼的Pass@1 指標不高. 因此,我們選擇了ChatGPT 這樣的大規模語言模型作為驗證工具,因為它具有更強大的語言理解和生成能力,可以應對復雜的代碼生成和代碼遷移任務.
構造有效性威脅是指實證研究中使用的評價指標是否真實反映了評估方法的性能. 在本文的研究中,考慮了MAE作為評判指標對功能準確性的擬合程度. 此外,為了避免假陽性或者假陰性數據過多而導致的誤差虛低的情況,本文額外將CodeScore-R 與功能準確性的擬合程度視為分類任務,根據準確率、精度、召回率和F1-Score 來進一步評估CodeScore-R指標的性能.
本文旨在提出一種新的代碼質量評估指標Code-Score-R,該指標基于UniXcoder 和對比學習. 實驗結果證明,CodeScore-R 相對于現有基準指標在功能準確性上擬合程度更好. 此外,CodeScore-R 與現有基準指標相比,在代碼詞素擾動、代碼語法擾動和代碼變異擾動下的魯棒性表現更好.
在后續研究工作中,我們將在更大規模、更多樣性的數據集上驗證CodeScore-R 的性能,同時考慮能力更強大的代碼模型作為底座模型,以進一步探索和改進其在特定領域或特定編程語言上的適用性.
同時,在構造正負樣本的方法上也將進一步地探索,豐富正負樣本的多樣性,以適應其在真實數據上的評估.
此外,本文僅在ChatGPT 模型上進行實證研究,在未來工作中,我們將對傳統的方法和基于大規模語言模型的方法進行統一驗證,以進一步探索和比較CodeScore-R 在不同方法中的性能和效果.
作者貢獻聲明:楊光提出了算法思路,負責完成實驗并撰寫論文;周宇對實驗思路提出改進和指導,并給出修改意見;陳翔提出指導意見并修改論文;張翔宇幫助推進實驗并檢查實驗結果.