Webhook 가이드: 데이터셋이 바뀌면 모델을 자동 재학습하는 시스템
Webhook 가이드: 데이터셋이 바뀌면 모델을 자동 재학습하는 시스템
HF Datasets, Webhooks, Spaces, AutoTrain을 사용해 Hugging Face 플랫폼에서 자동 학습 파이프라인을 설정하는 방법을 안내하는 가이드예요.
출처: 문서
본문
이미지 분류 데이터셋의 변경을 듣고, AutoTrain으로 microsoft/resnet-50의 파인튜닝을 트리거하는 Webhook을 만들 거예요.
전제: 데이터셋을 Hub에 업로드
예시를 위해 간단한 이미지 분류 데이터셋을 사용할게요. Hub에 데이터 업로드 방법은 여기에서 자세히 확인할 수 있어요.

데이터셋 변경에 반응하는 Webhook 만들기
먼저 설정에서 Webhook을 만들어요.
- 대상 저장소로 데이터셋을 선택해요. 이 예시에서는 huggingface-projects/input-dataset을 대상으로 해요.
- 지금은 더미 Webhook URL을 넣어도 돼요. Webhook을 정의하면 전송될 이벤트를 볼 수 있어요. 디버깅에 유용한 재생(replay)도 가능해요!
- 더 안전하게 만들기 위해 시크릿을 입력해요.
- 데이터 변경에 반응하려고 하니 "Repo update" 이벤트를 구독해요.
Webhook은 이렇게 생겼어요.

Webhook에 반응하는 Space 만들기
이제 Webhook 이벤트에 반응하는 방법이 필요해요. 쉬운 방법은 Space를 사용하는 거예요!
예시 Space는 여기에서 찾을 수 있어요.
이 Space는 Docker, Python, FastAPI, uvicorn으로 간단한 HTTP 서버를 실행해요. Docker Spaces에 대해 더 자세히 알아보려면 여기를 읽어보세요.
진입점은 src/main.py예요. 이 파일을 살펴보며 무슨 일을 하는지 자세히 볼게요.
/webhook에서 HTTPPOST요청을 수신하는 FastAPI 앱을 생성해요.
from fastapi import FastAPI
# [...]
@app.post("/webhook")
async def post_webhook(
# ...
):
# ...
- 이 라우트는
X-Webhook-Secret헤더가 존재하고 그 값이 Webhook 설정에 지정한 값과 같은지 확인해요.WEBHOOK_SECRET시크릿은 Space 설정에 설정되어 있어야 하고 Webhook에 설정한 시크릿과 같아야 해요.
# [...]
WEBHOOK_SECRET = os.getenv("WEBHOOK_SECRET")
# [...]
@app.post("/webhook")
async def post_webhook(
# [...]
x_webhook_secret: Optional[str] = Header(default=None),
# ^ checks for the X-Webhook-Secret HTTP header
):
if x_webhook_secret is None:
raise HTTPException(401)
if x_webhook_secret != WEBHOOK_SECRET:
raise HTTPException(403)
# [...]
- 이벤트의 페이로드는 JSON으로 인코딩돼요. 여기서는 pydantic 모델로 이벤트 페이로드를 파싱할 거예요. Webhook을 다음 조건에서만 실행하도록 지정해요.
- 이벤트가 입력 데이터셋에 관한 것
- 이벤트가 저장소 콘텐츠의 업데이트, 즉 새 커밋이 있는 것
# defined in src/models.py
class WebhookPayloadEvent(BaseModel):
action: Literal["create", "update", "delete", "move"]
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 model defining the payload format
):
# [...]
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"
):
# no-op if the payload does not match our expectations
return {"processed": False}
#[...]
- 페이로드가 유효하면 다음 단계는 AutoTrain에 프로젝트를 만들고, 입력 데이터셋에서 입력 모델(
microsoft/resnet-50)의 파인튜닝을 예약하고, 완료되면 데이터셋에 discussion을 만드는 거예요!
def schedule_retrain(payload: WebhookPayload):
# Create the autotrain project
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 in the community tab
notify_success(project["id"])
코멘트 안의 링크를 방문해 학습 비용 견적을 확인하고 모델 파인튜닝을 시작하세요!

이 예시에서는 Hugging Face AutoTrain으로 모델을 빠르게 파인튜닝했지만, 당연히 자신의 학습 인프라를 연결할 수도 있어요!
마음껏 Space를 개인 네임스페이스에 복제하고 가지고 놀아보세요. 두 가지 시크릿을 제공해야 해요.
WEBHOOK_SECRET: Webhook의 시크릿HF_ACCESS_TOKEN:write권한이 있는 사용자 액세스 토큰. 설정에서 만들 수 있어요
또한 원하는 데이터셋과 모델을 쓰려면 config.json 파일을 조정해야 해요.
{
"target_namespace": "the namespace where the trained model should end up",
"input_dataset": "the dataset on which the model will be trained",
"input_model": "the base model to re-train",
"autotrain_project_prefix": "A prefix for the AutoTrain project"
}
Webhook이 이벤트를 Space로 보내도록 설정
마지막으로 Webhook이 Space에 POST 요청을 보내도록 구성해야 해요.
먼저 컨텍스트 메뉴에서 Space의 "direct URL"을 가져와요. "Embed this Space"를 클릭하고 "Direct URL"을 복사하세요.


Webhook을 업데이트해 그 URL로 요청을 보내게 하세요.

이제 끝이에요! 이제 입력 데이터셋에 커밋이 생길 때마다 AutoTrain으로 ResNet-50의 파인튜닝이 트리거돼요 🎉
더 알아보기 (Learn more)
Webhook으로 데이터셋의 repo.content 업데이트를 감지하고, Space의 FastAPI 서버가 X-Webhook-Secret을 검증한 뒤 AutoTrain 프로젝트를 만들어 파인튜닝을 예약해요. Space를 복제할 때는 WEBHOOK_SECRET과 HF_ACCESS_TOKEN(write 권한) 두 시크릿과 config.json만 맞춰주면 나만의 자동 재학습 파이프라인이 완성돼요.