LLM 中間填充(Fill-In-the-Middle)技術

在整合 DeepSeek API 的時候看到他們有一個名為 FIM Completion(Beta)的功能,之前對 FIM 一直很陌生,趁這機會花了些時間補充這一段的知識,LLM 已在 AI 的許多領域帶來了顯著的衝擊,其中也包括程式碼生成。在 AI Coding 裡『中間填充(Fill-In-the-Middle,簡稱 FIM 或中綴填充)』是一個熱門的研究領域,這項技術讓 LLM 能夠根據給定的上下文產生缺少的程式碼片段。成熟的 FIM 不僅有可能大幅提升軟體開發速度,還可以增強程式碼自動完成的功能。

什麼是中間填充(Fill-In-the-Middle)?

中間填充(FIM)指的是 LLM 在給定前綴(prefix)和後綴(suffix)的情況下,產生符合中間程式碼的能力。這和傳統的從左到右(Left-to-Right, L2R)程式碼生成不同,傳統方式是根據之前的序列來預測下一個 Token。在中間填充中,模型需要同時考慮前面和後面的程式碼,才能產生連貫且可用的程式碼片段。

更明確地說,FIM 技術最初源自於自然語言處理(NLP),後來被成功應用於程式碼生成領域。想像一下填空題,你需要根據句子的前後文來推斷中間缺失的詞語。FIM 任務與此類似,只是模型需要填充的是程式碼片段,而非自然語言的詞語。

例如:輸入 (前後綴): def add(x, y):(前綴)和 return result(後綴)缺失部分 (中間): 需要模型填充 期望的輸出 (補全後): def add(x, y):(前綴)result = x + y (中間)return result (後綴)

中間填充是怎麼運作的?

目前的 FIM 模型主要使用自然語言處理(NLP)技術來預測缺少的程式碼,其核心機制是利用下一個 Token 預測(Next Token Prediction, NTP)。為了讓模型學會 FIM,常見的做法是重新排列訓練序列。例如:

  • SPS(Suffix-Prefix-Span):指的是將原始序列重新排列成『後綴 – 前綴 – 中間跨度(Span)』的形式。
  • PSM(Prefix-Suffix-Mask):指的是保留原始序列的順序『前綴 – 後綴 – 遮蔽區域/跨度』,但在訓練時將中間部分(Mask)遮蔽起來。

透過這些特殊的訓練序列排列方式,模型可以學習到如何根據前後綴來推斷中間缺失的程式碼。

然而,這種方法有一些限制,例如可能導致「中間迷失」現象,即模型難以充分利用長上下文中的所有資訊。

最近的研究發現一個有趣的現象,FIM 的預訓練不只提升了中間填充的能力,還改善了使用 LLM 的從左到右推理能力。這說明訓練模型進行中間填充對程式碼生成任務有更廣泛的好處。

另一項研究發現,FIM 模型在測試損失上可以達到和從左到右模型差不多的結果,同時在中間填充損失上表現更好。這說明 FIM 模型在處理中間填充任務時特別有效率。

不同類型的 Transformer 語言模型

要了解中間填充的運作方式,先認識不同類型的 Transformer 語言模型會很有幫助。這些模型是許多 LLM 的基礎,大致可以分成以下幾類:

  • 僅編碼器模型(Encoder-only): 像是 BERT 這類模型,是用遮罩語言建模(Masked Language Modeling)的目標來訓練。它們很擅長理解句子中字詞之間的關係和上下文。在程式碼生成任務中,這類模型通常不太擅長直接生成程式碼,但可以通過微調來適應特定任務。
  • 編碼器-解碼器模型(Encoder-Decoder): 像是 T5 這類模型,通常是用區段預測(Span Prediction)的目標來訓練。它們在產生文字序列方面表現特別好,例如翻譯或摘要任務。對於程式碼生成,這類模型可以用來處理程式碼翻譯或程式碼摘要等任務。
  • 因果解碼器模型(Causal Decoder-only): 像是 GPT-3 這類模型,是訓練來預測序列中的下一個 Token。它們特別適合開放式的文字生成和程式碼完成任務。對於程式碼生成的 FIM,目前 Decoder-only 架構更為常見,因為它能夠自然地融入前後綴信息來生成中間程式碼。

挑戰和進展

  • 中間迷失現象Middle-Lost Phenomenon): FIM 的一個主要挑戰是「中間迷失」現象,即 LLM 在處理長上下文時,會很難完全運用其中的資訊,特別是位於中間位置的資訊。這對 FIM 來說特別麻煩,因為模型需要同時考慮前綴和後綴,而這兩者之間可能隔了很多 Token。
  • 後綴整合的挑戰(Suffix Integration Challenges): 另一個問題是很難確保產生的程式碼能夠和後綴完美整合。模型常常無法產生和周圍上下文順暢銜接的程式碼。這可能會造成產生的程式碼出現錯誤或不一致。

為了解決這些挑戰,研究人員正在探索新的訓練方法和模型架構。其中一個很有希望的方法是『Horizon-Length Prediction(HLP)』,這個方法教導模型在每一步預測剩餘的中間 Token 數量。這幫助模型提前規劃並考慮更廣的上下文,產生更準確和連貫的程式碼。

除了 HLP 之外,研究人員也在探索其他方向,例如:

  • Special Tokens:使用特殊標記來分隔前後綴和中間部分,幫助模型更好地理解輸入結構。
  • 修改注意力機制(Attention Mechanism):讓模型更有效地關注前後綴資訊,例如限制模型在生成中間程式碼時只能關注前綴和後綴,而不是整個序列。

中間填充的實際應用範例

有些 LLM 是特別設計或改造來支援中間填充的。以下是幾個例子:

  • Codestral
  • CodeGemma
  • Granite Code Models
  • SantaCoder
  • StarCoder
  • DeepSeek-Coder
  • WizardCoder
  • GitHub Copilot
模型 HumanEval-FIM 推理速度 (tok/s)
DeepSeek 33B 72.1% 84
CodeLlama 70B 65.3% 37

這些例子說明不同的 LLM 如何使用各種技術來實現中間填充,提升程式碼生成的準確度和效率。

中間填充的應用

中間填充在程式碼生成上有很多潛在的應用:

  • 程式碼完成(Code Completion):在現有的程式碼結構中產生缺少的程式碼片段,加速軟體開發。例如,當開發者寫完一個函數的定義和一部分程式碼後,FIM 可以自動補全剩餘的程式碼。
  • 程式碼修復(Code Repair):分析周圍的程式碼上下文,找出並建議修復錯誤的方法。例如,當程式碼中存在語法錯誤或邏輯錯誤時,FIM 可以根據上下文推斷出正確的程式碼。
  • 程式碼重構(Code Refactoring):產生符合現有程式碼庫的替代實作方式,提升程式碼品質和可維護性。例如,FIM 可以將一段冗長的程式碼重構成更簡潔、更易讀的形式。
  • 從自然語言產生程式碼(Text-to-Code):把想要的功能當作前綴,把任何限制或要求當作後綴,從自然語言描述產生程式碼。例如,開發者可以用自然語言描述想要實現的功能,然後 FIM 可以根據描述產生對應的程式碼。
  • 自動程式碼生成:LLM 可以根據自然語言描述產生程式碼片段、函式,甚至整個模組,減少實作常見功能所需的時間和努力。
  • 錯誤偵測和修正:LLM 可以分析程式碼模式來找出錯誤,並建議修復常見錯誤的方法,還可能和整合式開發環境(IDE)整合,提供即時協助。
  • 語言翻譯:LLM 可以在不同程式語言之間翻譯程式碼,根據涉及的語言和模型的訓練資料,通常可以達到很高的準確度。

評估中間填充的 LLM

評估 LLM 在中間填充任務上的表現需要特殊的基準測試。其中一個基準測試是『Syntax-Aware Fill-in-the-Middle(SAFIM)』。SAFIM 著重在程式結構的語法感知完成,例如程式碼區塊、條件表達式和 API 函式呼叫。它包含多種程式語言的例子,提供了一個穩健的框架來比較不同的 LLM。

除了 SAFIM,還有一些常用的基準測試也可以用於評估 FIM 模型:

  • HumanEval: 雖然 HumanEval 主要針對從左到右的程式碼生成,但也可以用於評估 FIM 模型,通過將問題轉換成 FIM 任務的形式。
  • MultiPL-E: 包含多種程式語言的評估基準,可以用於評估 FIM 模型在不同語言上的表現。
  • CRUXEval(ICLR 2024新基準),專注FIM的執行正確性評估。

不同類別的 LLM

在評估中間填充的 LLM 時,要考慮以下幾種不同類別的模型:

  • 專有模型(Proprietary Models):像是 GPT-4 和 Claude 3.5 這類模型是由私人企業開發和營運的。它們的原始碼和訓練資料不公開。這些模型通常具有較強的性能,但缺乏透明度和可控性。
  • 開放和開源模型(Open and Open-Source Models):像是 Llama 3 和 Gemma 2 這類模型比較自由取得。你可以下載並在自己的裝置上執行,甚至用自己的資料重新訓練。這類模型具有更高的透明度和可定制性,但性能可能不如專有模型。

這個區別很重要,因為 LLM 的取得和存取方式會影響它們在不同情境下的採用和使用。另外,研究顯示在中間填充任務上,預訓練方法和資料品質常常比模型大小更重要。這說明 LLM 的訓練方式和訓練資料是影響它們表現的關鍵因素。

中間填充的限制

雖然 FIM 很有前途,但也有一些限制:

  • 提示詞敏感度和幻覺(Prompt Sensitivity and Hallucinations):LLM 對提示詞的表達方式很敏感,稍微改變措辭就可能得到不同的結果。這會讓從 LLM 取得一致和可靠的輸出變得很困難。而且,LLM 有時候會產生不準確或沒有意義的程式碼,特別是在處理複雜或模糊的上下文時。這些「幻覺」可能會讓 LLM 在實際的程式設計情境中遇到重大障礙。 在 FIM 任務中,提示詞的敏感度會直接影響模型對前後綴的理解,從而影響生成的程式碼質量。
  • 推理和理解能力有限(Limited Reasoning and Understanding):LLM 在需要理解程式碼底層邏輯和語意的複雜推理任務上可能會遇到困難。例如,它們可能無法理解訓練資料中字詞之間的關係,導致錯誤的推論或結論。
  • 自我修正和根據指令修正(Limited Self-Correction and Instruction-Following Capabilities)另一個限制是 LLM 無法自我修正或根據指令修正。即使指出錯誤,它們可能也無法認識到答案的錯誤,產生的修正程式碼還是不對。這說明在程式碼生成任務中需要人工監督和介入。

未來方向

FIM 這個領域正在快速發展,研究人員正在探索幾個方向:

  • 改進訓練目標(Improving Training Objectives):開發新的訓練目標來解決目前中間填充模型的限制是很重要的。這包括像 HLP 這樣的技術和其他可以增強長期規劃的方法。研究人員希望透過提升模型考慮更廣上下文的能力,產生更準確和連貫的程式碼。例如,可以研究新的訓練目標,讓模型更好地理解程式碼的語義和邏輯關係。
  • 穩健的評估基準(Robust Evaluation Benchmarks):建立更完整和具有挑戰性的基準,正確評估 LLM 在各種中間填充任務上的表現是必要的。這會幫助研究人員找出 LLM 表現優秀和需要進一步改進的領域。例如,可以設計更複雜、更貼近實際應用的 FIM 任務來評估模型。
  • 減輕限制(Mitigating Limitations):透過像是 Prompt Engineering 和 Fine-tuning 這樣的技術,處理中間填充的限制(例如提示詞敏感度和幻覺)是很重要的。這包括仔細設計提示詞來得到想要的回應,並在特定資料集上微調模型來提升準確度和可靠性。例如,可以研究如何通過設計更清晰、更明確的提示詞來減少模型產生幻覺的可能性。
  • LLM 和它們架構的演進(Evolution of LLMs and Their Architectures):LLM 和它們架構的演進是一個持續的過程。Transformer 架構的進步,例如衡量句子中不同字詞重要性的能力,已經大幅提升了 LLM 的表現。這個領域的持續研究很可能會帶來更強大和多功能的 LLM,例如針對程式碼生成任務優化模型架構。

Recaps

LLM 中間填充是一個很有前途的技術,有可能改變程式碼生成和軟體開發的方式。雖然還有一些挑戰,但持續的研究和進步正在為更穩健和可靠的中間填充模型鋪路。隨著 LLM 持續發展,中間填充很可能會在塑造程式設計的未來上扮演越來越重要的角色。FIM 技術的發展,將進一步推動自動化程式碼生成、程式碼修復、程式碼重構等應用的發展,並最終提升軟體開發的效率和質量。

  • 中間填充可以大幅提升軟體開發速度並增強程式碼完成功能。
  • 中間填充預訓練可以同時改善中間填充能力和從左到右推理。
  • 預訓練方法和資料品質是影響 LLM 在中間填充任務表現的關鍵因素。
  • LLM 有一些限制,例如提示詞敏感度、幻覺和推理能力有限。
  • 持續的研究著重在改進訓練目標、開發穩健的評估基準,以及減輕限制。

Reference

Leave a Comment

Your email address will not be published. Required fields are marked *