張睿峰,王鵬程,吳 鳴,徐 云
1(中國科學技術大學 計算機科學與技術學院,合肥 230026)
2(安徽省高性能計算重點實驗室,合肥 230026)
如今的軟件工程都會依賴于大型標準庫例如:.NET 框架、Java SDK 或者Android 等等,這些庫會提供大量多樣的提前實現(xiàn)好的功能,例如匹配正則表達式、解析XML和發(fā)送電子郵件等等.對于不熟悉的庫或者軟件框架對于開發(fā)者學習API 的使用是比較困難的[1].一個大型的軟件庫例如:.NET 框架或者JDK 可能包含成千上萬個API,例如JDK8 的基礎庫中有超過14 000 個類和方法,調查結果顯示如何選擇API 成為用戶編程系統(tǒng)中六個學習障礙之一[2].微軟2009年的一項調查中發(fā)現(xiàn),67.6%的受訪者反應他們在學習如何使用這些API 的時候沒有充足的示例以供參考[3].
當面對一個API (Application Program Interface)相關的任務時,開發(fā)者往往會借助搜索引擎例如:Google 或者Bing 去查找已有的API.他們往往帶著兩個問題去搜索答案:(1)對于他們的特定問題使用哪些API,(2)如何調用這些API[4],即API 調用序列.如圖1所示,從著名的程序問答網(wǎng)站Stack Overflow 上截取的開發(fā)者和研究人員在軟件開發(fā)過程中遇到的實際例子.他們想知道如何去調用已有的API 函數(shù)去解決自己的實際問題.因此,研究如何從已有的資源中(例如:Github 或者Bitbucket)挖掘出用戶需要的API 以及相應的API 調用序列已經(jīng)成為亟待解決的問題并且有重要的實際意義.
圖1 Stack Overflow 網(wǎng)站上的問答實例
對于一個用戶查詢輸入Q,返回一個API 調用序列S.Q 是對需要解決問題的英文描述,例如:“How to open a file?”.而S 是解決該問題的API 調用序列.本文主要研究Java 語言相關的問題,則相應的S 序列為:File.new(),File.open(),File.close().
按照代碼搜索方法的輸入類型劃分,相關文獻可分為以自由文本作為輸入的研究、以API 作為輸入的研究、其它形式作為輸入的研究.而推薦的內(nèi)容要么是相關的代碼片段,要么是單個API,或API 的調用序列.這里,把推薦代碼的研究稱為代碼搜索,把推薦API 及其序列的研究稱為API 推薦[5].
1.2.1 代碼搜索的研究現(xiàn)狀
在代碼搜索研究中,主要是基于基于信息檢索技術,Zhong 等人[6]提出為開發(fā)者的查詢推薦API 使用模式及對應的代碼片段.Bajracharya[7]等人基于開源代碼的結構化信息編寫的Sourcer 是代碼推薦的典型應用.McMillan[8]等人提出一個基于PageRank和SAN 對復雜任務檢索和可視化相關的代碼片段的工具Portfolio.Bajracharya 等人[9]在Lucene 的多域搜索平臺上,綜合API 使用模式的相似性等一系列特征進行代碼片段的推薦.Keivanloo 等人[10]利用向量空間模型、頻繁項挖掘等技術為自由文本的查詢進行代碼推薦.Raghothaman等人[4]提出了一種新的方法SWIM,該方法首先從用戶點擊數(shù)據(jù)中找到與用戶輸入的自由文本查詢相關的APIs,同時從Github 的代碼中抽取出結構化的API 調用序列,通過匹配找到APIs 相應的調用序列,進而產(chǎn)生合成的代碼片段.Jiang 等人[11]嘗試將信息檢索和監(jiān)督學習的方法結合為自由查詢提供Top-K 個相關的代碼片段.
1.2.2 API 序列推薦的研究現(xiàn)狀
然而傳統(tǒng)的代碼搜索引擎由于大部分使用了關鍵字匹配的技術,導致在處理自然語言查詢方面不能有良好的表現(xiàn)[12].在APIs 序列推薦研究中,近幾年也有了較大的發(fā)展.Thung 等人[13]整合了用戶對于搜索引擎結果的反饋并利用其重新排序返回結果列表使得真正相關的條目排在列表中的較前位置.Niu 等人[14]提出了使用監(jiān)督學習的方法,在兩階段的基礎上,借助于多種特征進行API 的推薦.Rahman 等人[12]嘗試從Stack Overflow 的問答對中抽取出與開發(fā)者的自由文本的查詢相關的API.Gu 等人[15]提出了一種基于深度學習的API 序列推薦方法DeepAPI,該方法受機器翻譯的啟發(fā),使用經(jīng)典的seq2seq 的RNN 模型,將“查詢-推薦”任務視作一種語言翻譯的過程,并取得了較好的效果.
SWIM[4]訓練的統(tǒng)計詞對齊模型是基于詞袋模型的,而沒有考慮到API 的單詞序列以及位置關系,例如:它很難區(qū)分查詢語句“convert date to string”與“convert string to date”.而之后Gu 等人[15]提出的DeepAPI 使用RNN 模型更好的學習到了句子的語義信息.經(jīng)測試BLEU (BiLingual Evaluation Understudy)[16]值比基于傳統(tǒng)模型的SWIM 提高了約173%.
但是,DeepAPI 采用的基于RNN 的模型并沒有充分考慮到每個單詞的重要程度,以及詞與詞之間的相互依賴關系,在句子過長的情況下會丟失之前的依賴信息,所以本文使用了完全基于注意力機制的模型,充分考慮了每個詞的重要程度和相互依賴關系,經(jīng)實驗結果可得BLEU 值在Top1 上比DeepAPI 提高了約28.5%.
由于沒有公開的可供訓練的數(shù)據(jù)集,需要我們自己生成可供訓練測試的數(shù)據(jù).我們首先通過網(wǎng)絡爬蟲從Github 上爬取關注度比較高的(即星標數(shù)的倒序排列)Java 語言的開源項目.如圖2所示,首先使用GrouMiner[17]將這些工程文件解析為程序依賴圖,再以方法級為粒度提取出我們需要的API 序列和注解對,接下來使用我們設計的基于注意力機制的模型對這些序列對進行訓練得到訓練模型,接下來針對每個查詢語句使用beam search 算法給出推薦的序列列表.具體設計分以下幾個方面:
圖2 從Java 代碼提取API 序列對流程圖
如圖3所示,需要將main 方法上的注釋“This method demonstrates square()”提取出來,而main 方法中的API 調用序列為每個對象生成以及調用的方法序列依次追加.對于條件控制語句例如:if和else 語句,分別將if和else 語句塊中的調用序列依次追加,其他條件控制語句例如switch和while 等同理.對于提取API 序列我們使用GrouMiner,它是一個基于圖方法用來挖掘程序中出現(xiàn)的使用慣例.如圖4所示,通過GrouMiner 可以將源代碼轉換為對象依賴圖.對于每個需要解析的方法,依次生成調用序列以及方法上面的注釋對,以供后面訓練使用.
圖3 代碼注釋示例圖
圖4 通過GrouMiner 將源代碼轉換為程序依賴圖
2.2.1 基于RNN 的Encoder-Decoder 模型的缺點
如圖5所示,對于編碼器Encoder 就是對輸入句子x1,…,xTi進行編碼,通過非線性變換f將上一時刻的隱藏層ht-1與 當前時刻的輸入xt轉化為當前時刻的隱藏層ht,結束時刻的hTx即為c(c為固定長度的向量).
由此可見:(1)輸入語句序列xTi(在訓練模型的時候即注釋語句)中每一個英文單詞對推薦的API 序列中每一個單詞的貢獻都是一樣的,但實際上每個單詞的貢獻是有區(qū)別的.(2)由于輸入語句映射在固定長度的向量中,因此對于較長輸入語句,特別是輸入語句長度大于向量長度或者是訓練集中沒有的長語句時,會損失上下文特征的很多信息.所以對于較長語句的處理上,基于RNN 的Encoder-Decoder 模型表現(xiàn)的不好.
圖5 基于RNN 的Encoder-Decoder 模型
2.2.2 使用注意力機制的Encoder-Decoder 模型
如圖6所示,使用注意機制,我們不再嘗試將完整的源序列編碼為固定長度的向量.而是通過Scaled Dot-Product Attention[18]對輸入語句的每個單詞進行計算,得到單詞的權重矩陣Attention(Q,K,V),每一行為一個單詞的權重向量.式(3)中,Q、K和V均為矩陣,每一行為一個向量,dk為矩陣維度的大小,模型的實現(xiàn)如圖7所示.其中Attention(Q,K,V)就是注意力值,代表對于輸出序列的不同部分需要關注輸入序列的哪些部分.所以,使用注意力機制的Encoder-Decoder 模型不會受到長距離依賴的影響.
圖6 基于注意力機制的Encoder-Decoder 模型
圖7 Scaled Dot-Product Attention 結構
圖6中,編碼器網(wǎng)絡由多個相同的層堆疊而成,每層有2 個子層,第一層是一個Scaled Dot-Product Attention的注意力層,第二層是一個全連接的feed-forward 層,每層都由一個殘差網(wǎng)絡連接,解碼器同編碼器一樣也是由多個相同層堆疊而成,不同的是插入了一個子層,如圖7所示,Mask 為可選部分,這個掩碼確保了位置i的輸出序列只能依賴比i小的已知輸出,即通過將其后位置的數(shù)據(jù)設置為- ∞.
實驗總共收集了649 個關注度較高的Java 語言的Github 開源項目,約20 GB 的數(shù)據(jù)量,共加工處理得到了114 364 個<annotation,API sequence>對.為節(jié)約我們訓練的時間以及方便測試,我們只隨機取50 000個序列對用于訓練,并隨機取500 條序列對用于測試.實驗機器配置如表1所示,Encoder -Decoder 模型主要的參數(shù)有:詞向量的最大長度設置為100,最小出現(xiàn)閾值為5 次,隱藏單元為512 個,迭代20 萬次.
表1 實驗機器配置
BLEU[16]是一種用于在機器翻譯領域評估從一種自然語言翻譯到另一種自然語言的文本質量的算法.我們通過BLEU 計算我們輸出的API 調用序列與標準參考的API 序列相似度得分可以評判結果的好壞.如圖8所示,我們分別取查詢結果的第一個,前五個以及前十個進行對比得出,在返回一個查詢結果的時候我們的方法高出DeepAPI 約28.5%.
圖8 模型的BLEU 得分圖
本文首先使用了GrouMiner[17]開發(fā)了一個可以用來從Java 代碼中提取API 序列以及注釋對的工具.其次,針對RNN(1)不能充分考慮每個單詞的權重,(2)以及將輸入序列壓縮為一個固定長度的向量,損失了很多可用信息,(3)對于句子過長產(chǎn)生的依賴信息丟失等缺點,使用了完全基于注意力機制的模型取得了比目前所知最好結果的DeepAPI 在BLEU 的Top1 得分上高出28.5%的結果.我們下一步的工作計劃是將該工具可視化以及開源,供其他科研工作者以及軟件開發(fā)人員使用.