跳到主要内容

Webhook 指南:当数据集发生变更时自动重新训练模型

提示

Webhook 现已对所有用户开放!

本指南将带你在 Hugging Face 平台上完成自动训练流水线的搭建,串联 HF Datasets、Webhooks、Spaces 与 AutoTrain。

我们将构建一个 Webhook,用于监听图像分类数据集的变动,并在触发时通过 AutoTrainmicrosoft/resnet-50 进行微调。

前置条件:将数据集上传到 Hub

示例中使用的是一个简单的图像分类数据集。关于如何将数据上传至 Hub,可参阅此文档

dataset

创建监听数据集变更的 Webhook

首先,在Webhook 设置页面创建一个 Webhook。

  • 选择要监听的目标数据集(示例中为 huggingface-projects/input-dataset)。
  • 目标 URL 暂时可填写一个占位地址。创建后即可查看将要发送的事件,并可重放这些事件,方便调试!
  • 设置一个密钥以提升安全性。
  • 勾选 “Repo update” 事件,因为我们需要对数据变更做出反应。

Webhook 设置完成后如下所示:

webhook-creation

创建 Space 来响应 Webhook

接下来需要一个实体来处理 Webhook 事件,最简单的方式是使用一个 Space

示例 Space 位于此处

该 Space 使用 Docker、Python、FastAPIuvicorn 运行一个简单的 HTTP 服务器。想了解 Docker Space 的更多信息,请查看相关文档

入口代码在 src/main.py 中,我们逐步讲解其功能:

  1. 启动一个 FastAPI 应用,监听 /webhook 路径的 HTTP POST 请求:
from fastapi import FastAPI

# [...]
@app.post("/webhook")
async def post_webhook(
# ...
):

# ...
  1. 该路由会校验 X-Webhook-Secret 头是否存在,并与 Webhook 设置中配置的密钥一致。Space 中需设置 WEBHOOK_SECRET,其值与 Webhook 中的密钥相同。
# [...]

WEBHOOK_SECRET = os.getenv("WEBHOOK_SECRET")

# [...]

@app.post("/webhook")
async def post_webhook(
# [...]
x_webhook_secret: Optional[str] = Header(default=None),
# ^ 检查 X-Webhook-Secret HTTP 头
):
if x_webhook_secret is None:
raise HTTPException(401)
if x_webhook_secret != WEBHOOK_SECRET:
raise HTTPException(403)
# [...]
  1. 事件负载为 JSON 编码。我们使用 pydantic 模型解析负载,并指定仅在以下条件时触发逻辑:
  • 事件关联的仓库为指定数据集
  • 事件类型为仓库内容更新,即产生了新提交
# 定义于 src/models.py
class WebhookPayloadEvent(BaseModel):
action: Literal["create", "update", "delete"]
scope: str

class WebhookPayloadRepo(BaseModel):
type: Literal["dataset", "model", "space"]
name: str
id: str
private: bool
headSha: str

class WebhookPayload(BaseModel):
event: WebhookPayloadEvent
repo: WebhookPayloadRepo

# [...]

@app.post("/webhook")
async def post_webhook(
# [...]
payload: WebhookPayload,
# ^ Pydantic 模型定义负载格式
):
# [...]
if not (
payload.event.action == "update"
and payload.event.scope.startswith("repo.content")
and payload.repo.name == config.input_dataset
and payload.repo.type == "dataset"
):
# 若负载不符合预期则直接返回
return {"processed": False}
#[...]
  1. 若负载有效,下一步即在 AutoTrain 创建项目、针对输入数据集微调基础模型(示例中为 microsoft/resnet-50),并在任务完成后于数据集页面发布讨论提醒!
def schedule_retrain(payload: WebhookPayload):
# 创建 AutoTrain 项目
try:
project = AutoTrain.create_project(payload)
AutoTrain.add_data(project_id=project["id"])
AutoTrain.start_processing(project_id=project["id"])
except requests.HTTPError as err:
print("ERROR while requesting AutoTrain API:")
print(f" code: {err.response.status_code}")
print(f" {err.response.json()}")
raise
# 在社区标签页通知
notify_success(project["id"])

在通知中点击链接,可查看训练成本预估并启动模型微调!

community tab notification

本示例使用 Hugging Face AutoTrain 快速完成微调,你当然也可以接入自有训练基础设施。

欢迎将该 Space 复制到你自己的命名空间中玩一玩。需要提供两个密钥:

  • WEBHOOK_SECRET:Webhook 的密钥。
  • HF_ACCESS_TOKEN:具备 write 权限的用户访问令牌,可在个人设置中创建。

此外,还需修改 config.json,以使用你指定的数据集与模型:

{
"target_namespace": "训练完成后模型要放入的命名空间",
"input_dataset": "用于训练的目标数据集",
"input_model": "需要重新训练的基础模型",
"autotrain_project_prefix": "AutoTrain 项目的前缀"
}

配置 Webhook 将事件发送至 Space

最后,需要将 Webhook 配置为向你的 Space 发送 POST 请求。

先从 Space 的上下文菜单中获取 “Direct URL”。点击 “Embed this Space”,然后复制 “Direct URL”。

embed this Space

direct URL

将 Webhook 的目标 URL 更新为该地址:

webhook settings

搞定!现在每次向输入数据集提交新 commit,都会触发 AutoTrain 对 ResNet-50 的微调 🎉