

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 `fmeval` 程式庫自訂您的工作流程
<a name="clarify-foundation-model-evaluate-auto-lib-custom"></a>

您可以自訂模型評估，以允許非 JumpStart 或 Amazon Bedrock 模型，或使用自訂工作流程進行評估。如果您使用自己的模型，則必須建立自訂 `ModelRunner`。如果您使用自己的資料集進行評估，則必須設定 `DataConfig` 物件。下一節說明如何格式化您的輸入資料集、自訂 `DataConfig` 物件以使用您的自訂資料集，以及建立自訂 `ModelRunner`。

## 使用自訂輸入資料集
<a name="clarify-foundation-model-evaluate-auto-lib-custom-input"></a>

如果您想要使用自己的資料集來評估模型，則必須使用 `DataConfig` 物件來指定要評估之資料集的 `dataset_uri` 和 `dataset_name`。如果您使用內建資料集，則 `DataConfig` 物件已設定為評估演算法的預設值。

每次使用 `evaluate` 函式時，您都可以使用一個自訂資料集。您可以調用 `evaluate` 任意次數，以使用您想要的任何數量的資料集。

使用問題欄中指定的模型請求，以及資料欄答案中指定的目標答案來設定自訂資料集，如下所示：

```
from fmeval.data_loaders.data_config import DataConfig
from fmeval.constants import MIME_TYPE_JSONLINES

config = DataConfig(
dataset_name="tiny_dataset",
dataset_uri="tiny_dataset.jsonl",
dataset_mime_type=MIME_TYPE_JSONLINES,
model_input_location="question",
target_output_location="answer",
)
```

`DataConfig` 類別包含下列參數。
+ `dataset_name` – 您要用來評估 LLM 的資料集名稱。

  `dataset_uri` – 資料集 S3 位置的本機路徑或統一資源識別碼 (URI)。
+ `dataset_mime_type` – 您要用來評估 LLM 的輸入資料格式。FMEval 程式庫可以同時支援 `MIME_TYPE_JSON` 和 `MIME_TYPE_JSONLINES`。
+ `model_input_location` – (選用) 資料集中的資料欄名稱，其中包含您要評估的模型輸入或提示。

  使用指定資料欄名稱的 `model_input_location`。資料欄必須包含對應至下列相關聯任務的下列值：
  + 對於**開放式生成**、**毒性**和**準確性**評估，指定一個資料欄，其中包含模型應回應的**提示**。
  + 對於**問答**任務，指定一個資料欄，其中包含模型應對其產生回應的**問題**。
  + 對於**文字摘要任務**，指定資料欄名稱，該資料欄包含您想要模型摘要說明的**文字**。
  + 對於**分類任務**，指定資料欄名稱，該資料欄包含您想要模型分類的**文字**。
  + 對於**事實知識**評估，指定資料欄名稱，該資料欄包含您想要模型預測其答案的**問題**。
  + 對於**語意穩健性**評估，指定資料欄名稱，該資料欄包含您想要模型擾動的**輸入**。
  + 對於**提示刻板印象**評估，使用 `sent_more_input_location` 和 ` sent_less_input_location` 而非 `model_input_location`，如下列參數所示。
+ `model_output_location` – (選用) 資料集中的資料欄名稱，該資料欄包含您想要用以與 `target_output_location` 中所含參考輸出進行比較的預測輸出。如果您提供 `model_output_location`，則 FMEval 不會將請求傳送至您的模型以進行推論。反之，它會使用指定欄中包含的輸出來評估您的模型。
+ `target_output_location` - 參考資料集中的資料欄名稱，該資料欄包含要與 `model_output_location` 中包含的預測值進行比較的真實值。僅事實知識、準確性和語意穩健性才需要。對於事實知識，此欄中的每一列都應包含以分隔符號分隔的所有可能答案。例如，如果問題的答案是 [“UK”,“England”]，則資料欄應該包含 “UK<OR>England”。如果模型預測包含以分隔符號分隔的任何答案，則模型預測為正確的。
+ `category_location` – 包含類別名稱的資料欄名稱。如果您為 `category_location` 提供一值，則會彙總並報告每個類別的分數。
+ `sent_more_input_location` – 包含較多偏差提示的資料欄名稱。僅提示刻板印象需要。避免無意識的偏差。如需偏差範例，請參閱 [CrowS-Pairs 資料集](https://paperswithcode.com/dataset/crows-pairs)。
+ `sent_less_input_location` – 包含較少偏差提示的資料欄名稱。僅提示刻板印象需要。避免無意識的偏差。如需偏差範例，請參閱 [CrowS-Pairs 資料集](https://paperswithcode.com/dataset/crows-pairs)。
+ `sent_more_output_location` – (選用) 資料欄名稱，該資料欄包含您模型產生的回應將包含較多偏差的預測機率。此參數僅用於提示刻板印象任務。
+ `sent_less_output_location` – (選用) 資料欄名稱，該資料欄包含您模型產生的回應將包含較少偏差的預測機率。此參數僅用於提示刻板印象任務。

如果您想要將對應至資料集欄的新屬性新增至 `DataConfig` 類別，則必須將 `suffix _location` 新增至屬性名稱的結尾。

## 使用自訂 `ModelRunner`
<a name="clarify-foundation-model-evaluate-auto-lib-custom-mr"></a>

若要評估自訂模型，請使用基礎資料類別來設定您的模型並建立自訂 `ModelRunner`。然後，您可以使用此 `ModelRunner` 來評估任何語言模型。使用下列步驟來定義模型組態、建立自訂 `ModelRunner` 並進行測試。

`ModelRunner` 介面有一個抽象方法，如下所示：

```
def predict(self, prompt: str) → Tuple[Optional[str], Optional[float]]
```

此方法採用提示做為字串輸入，並傳回一個元組，其中包含模型文字回應和輸入對數機率。每個 `ModelRunner` 必須實作 `predict` 方法。

**建立自訂 `ModelRunner`**

1. 定義模型組態。

   下列程式碼範例展示如何將 `dataclass` 裝飾項目套用至自訂 `HFModelConfig` 類別，以便您可以定義 **Hugging Face** 模型的模型組態：

   ```
   from dataclasses import dataclass
   
   @dataclass
   class HFModelConfig:
   model_name: str
   max_new_tokens: int
   seed: int = 0
   remove_prompt_from_generated_text: bool = True
   ```

   在先前的程式碼範例中，下列適用：
   + 參數 `max_new_tokens` 用來限制回應的長度，方法是限制 LLM 傳回的字符數量。模型類型是透過在類別執行個體化時傳遞 `model_name` 的值來設定。在此範例中，模型名稱設定為 `gpt2`，如本節結尾所示。參數 `max_new_tokens` 是一個選項，使用預先訓練 OpenAI GPT `gpt2` 模型的模型組態來設定文字生成策略。如需其他模型類型，請參閱 [AutoConfig](https://huggingface.co/transformers/v3.5.1/model_doc/auto.html)。
   + 如果參數 `remove_prompt_from_generated_text` 設定為 `True`，則產生的回應不會包含請求中傳送的原始提示。

   如需其他文字生成參數，請參閱 [GenerationConfig 的 Hugging Face 文件](https://huggingface.co/docs/transformers/v4.34.1/en/main_classes/text_generation#transformers.GenerationConfig)。

1. 建立自訂 `ModelRunner` 並實作預測方法。下列程式碼範例展示如何使用先前程式碼範例中建立的 `ModelRunner` 類別，為 Hugging Face 模型建立自訂 `HFModelConfig`。

   ```
   from typing import Tuple, Optional
   import torch
   from transformers import AutoModelForCausalLM, AutoTokenizer
   from fmeval.model_runners.model_runner import ModelRunner
   
   class HuggingFaceCausalLLMModelRunner(ModelRunner):
   def __init__(self, model_config: HFModelConfig):
       self.config = model_config
       self.model = AutoModelForCausalLM.from_pretrained(self.config.model_name)
       self.tokenizer = AutoTokenizer.from_pretrained(self.config.model_name)
   
   def predict(self, prompt: str) -> Tuple[Optional[str], Optional[float]]:
       input_ids = self.tokenizer(prompt, return_tensors="pt").to(self.model.device)
       generations = self.model.generate(
           **input_ids,
           max_new_tokens=self.config.max_new_tokens,
           pad_token_id=self.tokenizer.eos_token_id,
       )
       generation_contains_input = (
           input_ids["input_ids"][0] == generations[0][: input_ids["input_ids"].shape[1]]
       ).all()
       if self.config.remove_prompt_from_generated_text and not generation_contains_input:
           warnings.warn(
               "Your model does not return the prompt as part of its generations. "
               "`remove_prompt_from_generated_text` does nothing."
           )
       if self.config.remove_prompt_from_generated_text and generation_contains_input:
           output = self.tokenizer.batch_decode(generations[:, input_ids["input_ids"].shape[1] :])[0]
       else:
           output = self.tokenizer.batch_decode(generations, skip_special_tokens=True)[0]
   
       with torch.inference_mode():
           input_ids = self.tokenizer(self.tokenizer.bos_token + prompt, return_tensors="pt")["input_ids"]
           model_output = self.model(input_ids, labels=input_ids)
           probability = -model_output[0].item()
   
       return output, probability
   ```

   先前的程式碼使用自 FMEval `ModelRunner` 類別繼承屬性的自訂 `HuggingFaceCausalLLMModelRunner` 類別。自訂類別包含建構函數以及預測函數的定義，這會傳回 `Tuple`。

   如需更多 `ModelRunner` 範例，請參閱 `fmeval` 程式庫的 [model\$1runner](https://github.com/aws/fmeval/tree/main/src/fmeval/model_runners) 區段。

   `HuggingFaceCausalLLMModelRunner` 建構函數包含下列定義：
   + 組態設定為 `HFModelConfig`，定義在此區段開頭。
   + 模型設定為來自 Hugging Face [Auto Class](https://huggingface.co/transformers/v3.5.1/model_doc/auto.html) 的預先訓練模型，在執行個體化時使用 model\$1name 參數指定。
   + 字符化工具設定為來自 [Hugging Face 字符化工具程式庫](https://huggingface.co/docs/transformers/model_doc/auto#transformers.AutoTokenizer)的類別，其符合 `model_name` 指定的預先訓練模型。

   `HuggingFaceCausalLLMModelRunner` 類別中的 `predict` 方法使用下列定義。
   + `input_ids` – 包含模型輸入的變數。模型會產生輸入，如下所示。
     + `tokenizer` 會將 `prompt` 中包含的請求轉換為字符識別碼 (ID)。這些字符 ID 是代表特定字符 (單字、子單字或字元) 的數值，可供您的模型直接用作輸入。字符 ID 會以 PyTorch 張量物件的形式傳回，如 `return_tensors="pt"` 所指定。如需其他類型的傳回張量類型，請參閱 [apply\$1chat\$1template](https://huggingface.co/docs/transformers/main_classes/tokenizer#transformers.PreTrainedTokenizer.apply_chat_template) 的 Hugging Face 文件。
     + 字符 ID 會傳送到模型所在的裝置，以便模型可以使用它們。
   + `generations` – 包含 LLM 產生之回應的變數。模型的 generate 函式會使用下列輸入來產生回應：
     + 來自上一個步驟的 `input_ids`。
     + `HFModelConfig` 中指定的參數 `max_new_tokens`。
     + `pad_token_id` 會將句子結尾 (eos) 字符新增至回應。如需您可以使用的其他字符，請參閱 [PreTrainedTokenizer](https://huggingface.co/docs/transformers/main_classes/tokenizer#transformers.PreTrainedTokenizer) 的 Hugging Face 文件。
   + `generation_contains_input` – 布林值變數，其會在產生的回應在其回應中包含輸入提示時傳回 `True`，否則傳回 `False`。傳回值是使用下列項目之間的元素比較來計算。
     + 輸入提示中包含在 `input_ids["input_ids"][0]` 的所有字符 ID。
     + 包含在 `generations[0][: input_ids["input_ids"].shape[1]]` 的所產生內容開頭。

     如果您在組態中將 LLM 導向至 `remove_prompt_from_generated_text`，但產生的回應未包含輸入提示，則 `predict` 方法會傳回警告。

     `predict` 方法的輸出包含 `batch_decode` 方法傳回的字串，這會將回應中傳回的字符 ID 轉換為人類可讀文字。如果已將 `remove_prompt_from_generated_text` 指定為 `True`，則會從產生的文字中移除輸入提示。如果已將 `remove_prompt_from_generated_text` 指定為 `False`，將傳回產生的文字，而不會傳回您在字典 `special_token_dict` 中包含的任何特殊字符，如 `skip_special_tokens=True` 所指定。

1. 測試您的 `ModelRunner`。將範例請求傳送至您的模型。

   下列範例展示如何使用來自 Hugging Face `AutoConfig` 類別的 `gpt2` 預先訓練模型來測試模型：

   ```
   hf_config = HFModelConfig(model_name="gpt2", max_new_tokens=32)
   model = HuggingFaceCausalLLMModelRunner(model_config=hf_config)
   ```

   在先前的程式碼範例中，`model_name` 指定預先訓練模型的名稱。`HFModelConfig` 類別會執行個體化為具有參數 `max_new_tokens` 值的 hf\$1config，並用來初始化 `ModelRunner`。

   如果您想要使用來自 Hugging Face 的另一個預先訓練模型，請在 [AutoClass](https://huggingface.co/transformers/v3.5.1/model_doc/auto.html) 下的 `from_pretrained` 選擇 `pretrained_model_name_or_path`。

   最後，測試您的 `ModelRunner`。將範例請求傳送至您的模型，如下列程式碼範例所示：

   ```
   model_output = model.predict("London is the capital of?")[0]
   print(model_output)
   eval_algo.evaluate_sample()
   ```