返回文章列表

微調語言模型指令遵循

本文探討如何微調語言模型以遵循指令,並使用自動化評估方法評估模型效能。文章涵蓋了模型訓練、回應生成、人工評估和自動評估等關鍵步驟,並以Llama 3模型為例,展示如何使用Ollama進行本地評估。

機器學習 自然語言處理

現今大語言模型的指令遵循能力日益重要,本文探討如何微調語言模型以提升其指令遵循效能。我們首先介紹如何使用Python程式碼生成模型回應,接著討論人工評估方法的侷限性,並提出使用另一個大語言模型(如Llama 3)進行自動評估的方案。最後,我們示範如何使用Ollama在本機執行Llama 3模型,並透過REST API與其互動,以自動評估微調模型生成的回應品質。

微調語言模型以遵循指令

在完成回應指令的步驟中,我們使用generate函式。接著,我們將模型的回應與測試集中的預期答案並列印出,以便比較前三個測試集條目:

torch.manual_seed(123)
for entry in test_data[:3]:
    input_text = format_input(entry)
    token_ids = generate(
        model=model,
        idx=text_to_token_ids(input_text, tokenizer).to(device),
        max_new_tokens=256,
        context_size=BASE_CONFIG["context_length"],
        eos_id=50256
    )
    generated_text = token_ids_to_text(token_ids, tokenizer)
    response_text = (
        generated_text[len(input_text):]
        .replace("### Response:", "")
        .strip()
    )

內容解密:

  1. 固定隨機種子:使用torch.manual_seed(123)確保實驗的可重複性。
  2. 迭代測試資料:遍歷測試集中的前三個條目。
  3. 生成模型回應:使用generate函式根據輸入文字生成模型的回應。
  4. 後處理生成的文字:從生成的文字中提取模型的回應,並進行必要的清理,如移除“### Response:”標籤。

提取和儲存回應

print(input_text)
print(f"\n正確回應:\n>> {entry['output']}")
print(f"\n模型回應:\n>> {response_text.strip()}")
print("
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
--")

內容解密:

  1. 印出輸入文字:顯示輸入模型的指令和文字。
  2. 印出正確與模型回應:並列印出測試集中的正確回應和模型的回應,以便比較。
  3. 分隔線:使用分隔線來區分不同的測試案例。

比較模型的回應與正確回應

以下是模型的回應與測試集中的正確回應的例子:

指令:使用比喻重寫句子。
輸入:這輛車非常快。
正確回應:>> 這輛車像閃電一樣快。
模型回應:>> 這輛車像子彈一樣快。

指令:什麼型別的雲通常與雷暴有關?
正確回應:>> 與雷暴相關的雲型別是積雨雲。
模型回應:>> 與雷暴相關的雲是積雲。

指令:‘傲慢與偏見’的作者是誰?
正確回應:>> 簡·奧斯汀。
模型回應:>> ‘傲慢與偏見’的作者是簡·奧斯汀。

內容解密:

  1. 評估模型表現:透過比較模型的回應和正確回應,可以評估模型的表現。
  2. 多種評估方法:由於指令微調的LLM評估不像簡單的分類別任務那樣直接,實踐中會使用多種評估方法,包括多選題、人工評估和自動對話評估等。

對話效能評估

對話效能是指LLM能夠進行類別人溝通的能力,包括理解上下文、細微差別和意圖。它涵蓋了提供相關且連貫的回應、保持一致性以及適應不同話題和互動風格的能力。

圖示說明

此圖示展示了指令微調LLM的三階段過程,包括準備資料集、微調LLM和評估LLM。在評估階段,會提取模型的回應並進行人工和自動對話評估。

7.7 自動生成與儲存模型回應

人工評估雖然能提供寶貴的洞察,但處理大量回應時卻相當耗時耗力。例如,要閱讀並評分全部1,100個回應需要投入大量的精力。

因此,為了更有效地評估模型效能,我們採用了一種類別似於自動化對話基準測試的方法,利用另一個大語言模型(LLM)自動評估回應。這種方法使我們能夠在無需大量人工參與的情況下,高效地評估生成的回應品質,從而節省時間和資源,同時獲得有意義的效能指標。

我們採用了一種受AlpacaEval啟發的方法,利用另一個LLM來評估我們微調後的模型的回應。然而,我們並未依賴公開可用的基準測試資料集,而是使用了自定義的測試集。這種自定義使我們能夠在預定的使用案例中,更有針對性地評估模型的效能。

生成測試集回應

為了準備評估過程所需的回應,我們將生成的模型回應附加到test_set字典中,並將更新後的資料儲存為"instruction-data-with-response.json"檔案,以便於記錄。此外,透過儲存此檔案,我們可以在稍後的Python會話中輕鬆載入和分析回應。

程式碼 7.9:生成測試集回應

from tqdm import tqdm
for i, entry in tqdm(enumerate(test_data), total=len(test_data)):
    input_text = format_input(entry)
    token_ids = generate(
        model=model,
        idx=text_to_token_ids(input_text, tokenizer).to(device),
        max_new_tokens=256,
        context_size=BASE_CONFIG["context_length"],
        eos_id=50256
    )
    generated_text = token_ids_to_text(token_ids, tokenizer)
    response_text = (
        generated_text[len(input_text):]
        .replace("### Response:", "")
        .strip()
    )
    test_data[i]["model_response"] = response_text

with open("instruction-data-with-response.json", "w") as file:
    json.dump(test_data, file, indent=4)

內容解密:

  1. 迴圈處理測試資料: 使用tqdm函式庫顯示進度條,遍歷test_data中的每個條目。
  2. 格式化輸入文字: 使用format_input函式將每個條目格式化為輸入文字。
  3. 生成模型回應: 呼叫generate函式生成模型的回應,並將其轉換為文字。
  4. 處理生成的回應文字: 去除不必要的字首和空白字元,將處理後的回應儲存在test_data字典中。
  5. 儲存更新後的測試資料: 將包含模型回應的test_data儲存為JSON檔案。

處理資料集在A100 GPU上大約需要1分鐘,在M3 MacBook Air上需要6分鐘。

驗證和儲存模型

透過檢查test_data[0],我們可以驗證模型回應是否已正確新增。最後,我們將模型儲存為"gpt2-medium355M-sft.pth"檔案,以便於在未來專案中重複使用。

7.8 評估微調後的LLM

之前,我們透過觀察模型在測試集中的三個範例上的表現來判斷其效能。雖然這給了我們一個粗略的概念,但這種方法並不能很好地擴充套件到大量的回應。因此,我們實施了一種方法,利用另一個更大的LLM自動評估微調後的LLM的回應,如圖7.19所示。

自動評估測試集回應

為了自動評估測試集回應,我們使用了Meta AI開發的指令微調後的8億引數Llama 3模型。該模型可以使用開源的Ollama應用程式在本機執行。

使用Ollama執行Llama 3模型

  1. 安裝Ollama: 存取https://ollama.com,按照指示為您的作業系統安裝Ollama。
  2. 下載Llama 3模型: 在命令列終端中使用Ollama下載Llama 3模型,並驗證其是否正確運作。

圖7.19 指令微調LLM的三階段過程

在指令微調流程的最後一步,我們實施了一種方法,透過對微調後的模型生成的測試集回應進行評分,量化其效能。

未來改進方向

除了使用本地執行的Llama 3模型,還可以透過OpenAI API利用GPT-4等大型專有LLM來評估生成的模型回應。相關的可選程式碼筆記本可在本文的配套材料中找到。

使用Ollama執行Llama 3模型

要使用Ollama執行8億引數的Llama 3模型,首先需要在另一個終端機中執行Ollama應用程式或ollama serve命令。接著,在命令列中(而不是在Python會話中)執行以下命令:

ollama run llama3

第一次執行此命令時,模型將自動下載,佔用4.7 GB的儲存空間。輸出結果如下:

pulling manifest
pulling 6a0746a1ec1a... 100% |████████████████| 4.7 GB
pulling 4fa551d4f938... 100% |████████████████| 12 KB
pulling 8ab4849b038c... 100% |████████████████| 254 B
pulling 577073ffcc6c... 100% |████████████████| 110 B
pulling 3f8eb4da87fa... 100% |████████████████| 485 B
verifying sha256 digest
writing manifest
removing any unused layers
success

下載完成後,將進入一個命令列介面,可以與模型互動。例如,詢問模型「What do llamas eat?」:

>>> What do llamas eat?
Llamas are ruminant animals, which means they have a four-chambered stomach and eat plants that are high in fiber. In the wild, llamas typically feed on:
1. Grasses: They love to graze on various types of grasses, including tall grasses, wheat, oats, and barley.

可以使用/bye指令結束此次會話。

驗證Ollama是否正在執行

在評估測試集回應之前,需要驗證Ollama是否正在執行:

import psutil

def check_if_running(process_name):
    running = False
    for proc in psutil.process_iter(["name"]):
        if process_name in proc.info["name"]:
            running = True
            break
    return running

ollama_running = check_if_running("ollama")
if not ollama_running:
    raise RuntimeError("Ollama not running. Launch ollama before proceeding.")
print("Ollama running:", check_if_running("ollama"))

程式碼解密:

  • psutil函式庫用於檢查系統中正在執行的行程。
  • check_if_running函式遍歷所有正在執行的行程,檢查是否包含指定的行程名稱(此例中為"ollama")。
  • 若未發現Ollama正在執行,則引發RuntimeError

使用REST API與Ollama互動

除了使用命令列介面外,也可以使用Python透過REST API與Ollama互動。以下為範例函式:

import urllib.request
import json

def query_model(prompt, model="llama3", url="http://localhost:11434/api/chat"):
    data = {
        "model": model,
        "messages": [{"role": "user", "content": prompt}],
        "options": {"seed": 123, "temperature": 0, "num_ctx": 2048}
    }
    payload = json.dumps(data).encode("utf-8")
    request = urllib.request.Request(url, data=payload, method="POST")
    request.add_header("Content-Type", "application/json")
    response_data = ""
    with urllib.request.urlopen(request) as response:
        while True:
            line = response.readline().decode("utf-8")
            if not line:
                break
            response_json = json.loads(line)
            response_data += response_json["message"]["content"]
    return response_data

result = query_model("What do Llamas eat?", "llama3")
print(result)

程式碼解密:

  • query_model函式使用指定的提示(prompt)和模型(預設為"llama3")向Ollama的REST API傳送請求。
  • 請求資料包含模型名稱、使用者訊息和選項(種子值、溫度、上下文長度)。
  • 請求成功後,回應資料被解碼並傳回。

評估微調後的LLM

使用query_model函式,可以評估由微調模型生成的回應。透過提示Llama 3模型根據給定的測試集回應對微調模型的回應進行評分(0至100分)。

Plantuml圖示:評估流程圖

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title 微調語言模型指令遵循

package "指令微調流程" {
    package "訓練階段" {
        component [指令資料集] as dataset
        component [格式化輸入] as format
        component [模型微調] as finetune
    }

    package "生成階段" {
        component [generate 函式] as generate
        component [回應提取] as extract
        component [後處理] as postprocess
    }
}

package "評估方法" {
    component [人工評估] as manual
    component [Llama 3 自動評估] as llama
    component [Ollama 本地執行] as ollama
    component [AlpacaEval] as alpaca
}

dataset --> format : 指令+輸入
format --> finetune : 訓練樣本
finetune --> generate : 微調模型
generate --> extract : Token IDs
extract --> postprocess : 清理回應
postprocess --> llama : 品質評分
llama --> ollama : REST API
ollama --> alpaca : 基準測試

note right of llama
  評估流程:
  - 特徵選擇
  - 特徵轉換
  - 降維處理
end note

note right of eval
  評估指標:
  - 準確率/召回率
  - F1 Score
  - AUC-ROC
end note

@enduml

此圖示描述了評估微調後LLM的流程,從載入測試資料到收集Llama 3模型的評分結果。