程式碼生成最佳化:微調Falcon40b

發表於2023-09-27

Falcon40b是當前最大的開源大語言模型之一,且採用商業友好的Apache 2.0許可證。這使得對於希望將NLP產品推向市場的開發者來說,它具有相當大的吸引力。

Falcon-40b-Instruct模型基於Falcon40b模型進行微調,用於指令接收和對話任務,在Hugging Face的LLM基準測試中名列前茅,僅次於基於Meta的非開源Llama系列的模型。Falcon40b的效能遠優於其他開源模型。

作為最新一波開源大語言模型,Falcon系列模型受到Llama系列啟發,核心思想是使用更多資料(在本例中超過一萬億代幣)更長時間(更多時期)訓練較小的模型。LLM相關的經驗文獻表明,模型規模、訓練計算和訓練資料集規模應該同步增加,但該模型系列使用的計算和訓練資料遠遠超出預期。

使用CodeAlpaca進行微調

Falcon40b是一個預訓練模型,但並未針對任何特定任務進行訓練。它的零樣本效能並不出色,需要透過訓練才能用作聊天機器人或按照指令執行任務。
當我們希望它按照指令執行任務時,我們使用如Alpaca資料集的指令-響應對進行訓練。
下面是來自Alpaca的一對指令-響應示例:

以下是一個描述任務的指令。請提供一個響應正確完成該請求。  

### 指令:
建立一個包含1到10之間所有偶數的長度為5的陣列。  

### 響應:
arr = [2, 4, 6, 8, 10]  

Falcon-40b-Instruct模型已經被訓練成一個通用的指令跟蹤模型,因此我們決定不循規蹈矩。
最近,對訓練大型語言模型來編寫程式碼的興趣越來越濃,這個領域有許多開源專案,特別是Starcoder、Replit3b、CodeGen和CodeGen2。因此,我們決定嘗試使用CodeAlpaca資料集對Falcon40b進行微調,使其能夠根據自然語言提示編寫程式碼。

CodeAlpaca是一組包含20,000個指令-輸入-程式碼三元組的資料集,與Alpaca資料集一樣,它們是由閉源語言模型生成的。示例如下:

以下是一個描述任務的指令,與提供了更多上下文的輸入配對。請提供一個響應,正確完成請求。  
### 指令:生成一段程式碼片段,提取給定字串中的所有URL。  
### 輸入:該字串包含一些網址,如<https://www.google.com>和<https://www.facebook.com>。  
### 響應:import re  
string = "該字串包含一些網址,如<https://www.google.com>和<https://www.facebook.com>。"urls = re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\\\(\\\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', string)print(urls)  

與通用指令跟蹤任務相比,專用於程式碼構建訓練Falcon40b在這些任務上表現更好。

微調超引數

我們使用LoRA進行微調,採用8位量化,使用了四個NVIDIA A100 Tensor Core GPU,每個GPU有80GB的VRAM。微調花費了約4小時,在runpod.io上花費了約25歐元。
我們使用了以下超引數:

  • Epochs:2
  • 新增LoRA的層:全注意層(QKV)
  • LoRA等級:8
  • 學習率:3.0e-4
  • Batch size:128

    ?我們注意到將epochs增加到2有助於模型“學習”何時停止。否則,它將重複指令模板,永不停止。  

    結果

    我們選擇了45條編碼指令,用於評估模型遵循指令的能力。經過微調,模型能夠根據自然語言指令生成程式碼,回答關於程式碼段的問題,以及回答一般的計算機程式設計問題。
    例如:
    通用程式設計問題

    問題:
    解釋Python中迭代器和生成器的區別並舉例。  
    響應:
    迭代器是一種可用於遍歷序列項(如列表或字串)的物件。它提供了一種逐個訪問序列中每個項的方法。生成器是一種可用於生成序列項(如列表或字串)的函式。它提供了一種逐個生成序列中每個項的方法。迭代器和生成器的主要區別在於,迭代器是一種可用於遍歷序列的物件,而生成器是一種可用於生成序列的函式。

根據自然語言提示生成程式碼

問題:
編寫一個Python函式:接受一個單詞列表,並返回一個字典,其中鍵是列表中的單詞,值是列表中單詞的頻率。在解決方案中使用for迴圈、if條件和字典。
響應:
def word_frequency(words):
    frequencies = {}    
    for word in words:        
        if word in frequencies:            
            frequencies[word] += 1        
        else:            
            frequencies[word] = 1    
    return frequencies  

回答關於特定程式碼段的問題

問題:
解釋以下Python指令碼,該指令碼使用FastAPI建立一個基本的'Hello World' API。  
from fastapi import FastAPI  

app = FastAPI()  

@app.get("/")
def read_root():    
    return {"Hello": "World"}  
響應:  
這個Python指令碼使用FastAPI建立一個基本的'Hello World' API。FastAPI是一個能夠輕鬆在Python中建立API的Web框架。@app.get("/")裝飾器定義了API的路由,當訪問該路由時將呼叫read_root()函式。該函式返回一個包含鍵"Hello"和值"World"的字典。 

編寫處理AI模型的程式碼

問題:
編寫一個使用transformers庫對輸入文字進行標記化並生成模型輸出的Python指令碼。  
響應:
import transformers

tokenizer = transformers.AutoTokenizer.from_pretrained("bert-base-uncased")
model = transformers.AutoModel.from_pretrained("bert-base-uncased")  

input_text = "This is an example text."  

tokenized_text = tokenizer.tokenize(input_text)model_output = model.generate(input_text)  

print(tokenized_text)
print(model_output)  

定量來看,使用了這個程式碼庫進行評分,HumanEval基準測試的第一輪得分為22%。儘管這是一個不錯的結果,但遠沒有達到專門用於編寫程式碼的AI模型的最佳記錄效能。

Falcon-40b-Instruct在相同任務上得分為18%。我們認為這是因為在更大資料集上的訓練使其更好地遵循指令,即使它不擅長編寫程式碼或解決程式設計問題。它的大部分知識似乎是在預訓練階段獲得的。

簡而言之

我們透過HuggingFace釋出了兩個模型:完整權重模型和我們微調的Falcon40b的LoRA介面卡權重
儘管Falcon40b並非專門用於編碼,但它在編碼問題上表現出色。透過使用我們微調的LoRA掩碼,您只需將少量額外的資料載入到記憶體中即可將任何Falcon40b安裝轉變為編碼助手。

下載我們的程式碼並復現結果

您可以透過從GitHub檢視我們的程式碼庫並復現。程式碼包含對HuggingFace的transformers模組的透明封裝。
首先,從GitHub獲取我們的程式碼:

git clone <https://github.com/jina-ai/jerboa.git> 

然後,進入git庫的根目錄,並執行以下命令:

cd jerboa  
finetune.py --base-model tiiuae/falcon-40b --lora-target-modules query_key_value --data-path sahil2801/CodeAlpaca-20k --output-dir ./lora-alpaca-code --batch-size 128 --micro-batch-size 4 --eval-limit 45 --eval-file code_eval.jsonl --wandb-project jerboa --wandb-log-model --wandb-watch gradients --num-epochs 2

如果遇到問題,您可以恢復到我們在本文中使用版本的checkpoint:

git checkout abe1a23a4e9f5e141e19be0336ca8a4c888dd024  

您還可以嘗試使用LLM Foundry或其他最佳化低訓練成本的工具來減少計算和訓練時間。

參與其中

訪問Jina AI官網GitHub庫Discord,探索人工智慧能為您做些什麼。

相關文章