创建自定义推理处理器
Hugging Face 端点支持所有 Transformers 和 Sentence-Transformers 任务,并且可以支持自定义任务,包括自定义预处理和后处理。可以通过模型存储库中 Hugging Face Hub 上的 handler.py 文件进行自定义。
该 handler.py 需要实现 EndpointHandler 类,其中包含 __init__
和 __call__
方法。
如果要使用自定义依赖项,例如 optimum,则必须在 requirements.txt
中列出这些依赖项,如上文“添加自定义依赖项”中所述。
自定义处理器示例
在 Hugging Face Hub 上已经有一些公开的示例,您可以从中获得灵感或直接使用它们。这些存储库都带有 endpoints-template
标签,可以通过此 链接 找到。
包含以下示例:
- Optimum 和 ONNX 运行时
- 使用 BLIP 的图像嵌入
- 用于 OCR 检测的 TrOCR
- 使用 Optimum 优化的句子 Transformers
- Pyannote 说话人分段
- LayoutLM
- Flair NER
- GPT-J 6B 单 GPU
- Donut 文档理解
- SetFit 分类器
教程
在创建自定义处理器之前,您需要一个包含模型权重的 Hugging Face 模型存储库,以及一个对存储库具有*写入*权限的访问令牌。要查找、创建和管理访问令牌,请点击 此处。
如果要为社区中的现有模型编写自定义处理器,可以使用 repo_duplicator 创建存储库的分支。
代码也可以在此 Notebook 中找到。
您也可以在此处搜索已存在的自定义处理器:https://huggingface.co/models?other=endpoints-template
1. 设置开发环境
开发自定义处理器的最简单方法是设置本地开发环境,以便在其中实现、测试和迭代,然后将其部署为推理端点。第一步是安装所有必需的开发依赖项。创建自定义处理器需要,推理不需要
# install git-lfs to interact with the repository
sudo apt-get update
sudo apt-get install git-lfs
# install transformers (not needed since it is installed by default in the container)
pip install transformers[sklearn,sentencepiece,audio,vision]
安装完库后,我们将把存储库克隆到我们的开发环境中。
在本教程中,我们将使用 philschmid/distilbert-base-uncased-emotion。
git lfs install
git clone https://huggingface.co/philschmid/distilbert-base-uncased-emotion
为了能够稍后推送我们的模型存储库,您需要登录到我们的 HF 账户。这可以通过使用 huggingface-cli
来完成。
注意:确保也配置 git 配置。
# setup cli with token
huggingface-cli login
git config --global credential.helper store
2. 创建 EndpointHandler
在设置好环境后,我们可以开始创建自定义处理程序。自定义处理程序是一个 Python 类(`EndpointHandler`),位于我们代码库中的 `handler.py` 文件内。`EndpointHandler` 需要实现 `__init__` 和 `__call__` 方法。
- 当启动 Endpoint 时,会调用 `__init__` 方法,并接收一个参数,该参数是一个指向模型权重的路径字符串。这允许您正确加载模型。
- `__call__` 方法会在每次请求时被调用,并接收一个字典,其中包含请求体作为 Python 字典。它将始终包含 `inputs` 键。
第一步是在我们代码库的本地克隆中创建 `handler.py` 文件。
!cd distilbert-base-uncased-emotion && touch handler.py
在其中,您定义带有 `__init__` 和 `__call__` 方法的 `EndpointHandler` 类。
from typing import Dict, List, Any
class EndpointHandler():
def __init__(self, path=""):
# Preload all the elements you are going to need at inference.
# pseudo:
# self.model= load_model(path)
def __call__(self, data: Dict[str, Any]) -> List[Dict[str, Any]]:
"""
data args:
inputs (:obj: `str` | `PIL.Image` | `np.array`)
kwargs
Return:
A :obj:`list` | `dict`: will be serialized and returned
"""
# pseudo
# self.model(input)
3. 自定义 EndpointHandler
现在,您可以将所有希望在初始化或推理期间使用的自定义逻辑添加到您的自定义 Endpoint 中。如果您需要一些灵感,您已经可以在 Hub 上找到多个 自定义处理程序。在我们的示例中,我们将根据额外的有效负载信息添加一个自定义条件。
本教程中使用的模型经过微调以检测情绪。我们将添加一个额外的有效负载字段用于日期,并使用一个外部包来检查它是否是节假日,以添加一个条件,以便当输入日期是节假日时,模型返回“happy”——因为每个人在节假日时都很开心🌴🎉😆
首先,我们需要创建一个新的 `requirements.txt` 文件并添加我们的 节假日检测包,并确保我们也在开发环境中安装了它。
!echo "holidays" >> requirements.txt
!pip install -r requirements.txt
接下来,我们必须调整我们的 `handler.py` 和 `EndpointHandler` 以匹配我们的条件。
from typing import Dict, List, Any
from transformers import pipeline
import holidays
class EndpointHandler():
def __init__(self, path=""):
self.pipeline = pipeline("text-classification",model=path)
self.holidays = holidays.US()
def __call__(self, data: Dict[str, Any]) -> List[Dict[str, Any]]:
"""
data args:
inputs (:obj: `str`)
date (:obj: `str`)
Return:
A :obj:`list` | `dict`: will be serialized and returned
"""
# get inputs
inputs = data.pop("inputs",data)
date = data.pop("date", None)
# check if date exists and if it is a holiday
if date is not None and date in self.holidays:
return [{"label": "happy", "score": 1}]
# run normal prediction
prediction = self.pipeline(inputs)
return prediction
4. 测试 EndpointHandler
为了测试我们的 EndpointHandler,我们可以简化导入、初始化和测试过程。因此,我们只需要准备一个示例有效负载。
from handler import EndpointHandler
# init handler
my_handler = EndpointHandler(path=".")
# prepare sample payload
non_holiday_payload = {"inputs": "I am quite excited how this will turn out", "date": "2022-08-08"}
holiday_payload = {"inputs": "Today is a though day", "date": "2022-07-04"}
# test the handler
non_holiday_pred=my_handler(non_holiday_payload)
holiday_payload=my_handler(holiday_payload)
# show results
print("non_holiday_pred", non_holiday_pred)
print("holiday_payload", holiday_payload)
# non_holiday_pred [{'label': 'joy', 'score': 0.9985942244529724}]
# holiday_payload [{'label': 'happy', 'score': 1}]
它起作用了!!!! 🎉
注意:如果您使用的是笔记本,当您对 `handler.py` 进行更改时,您可能需要重新启动内核,因为它不会自动重新导入。
5. 将自定义处理程序推送到您的代码库
在本地成功测试处理程序后,您可以使用基本的 git 命令将其推送到您的代码库。
# add all our new files
!git add *
# commit our files
!git commit -m "add custom handler"
# push the files to the hub
!git push
现在,您应该在 “文件和版本” 选项卡中看到代码库中的 `handler.py` 和 `requirements.txt` 文件。
6. 将您的自定义处理程序部署为推理 Endpoint
最后一步是将您的自定义处理程序部署为推理 Endpoint。您可以像部署常规推理 Endpoint 一样部署自定义处理程序。添加您的代码库,选择您的云和区域、实例和安全设置,然后部署。
创建 Endpoint 时,推理 Endpoint 服务将检查是否有可用的有效 `handler.py` 文件,并将其用于服务请求,无论您选择哪个“任务”。
注意:在您的 推理 Endpoint 仪表板 中,此 Endpoint 的任务现在应设置为自定义。
< > GitHub 更新