# Webhook 가이드: 데이터셋이 변경되면 모델을 자동으로 재학습하는 시스템 설정

이 가이드는 HF Datasets, Webhooks, Spaces, AutoTrain을 사용하여 Hugging Face 플랫폼에서 자동 학습 파이프라인을 설정하는 과정을 안내해 드립니다.

이미지 분류 데이터셋의 변경 사항을 감지하고 [AutoTrain](https://huggingface.co/autotrain)을 사용하여 [microsoft/resnet-50](https://huggingface.co/microsoft/resnet-50)의 fine-tuning을 트리거하는 Webhook을 구축하겠습니다.

## 사전 요구 사항: 데이터셋을 Hub에 업로드

예시를 위해 [간단한 이미지 분류 데이터셋](https://huggingface.co/datasets/huggingface-projects/auto-retrain-input-dataset)을 사용합니다. Hub에 데이터를 업로드하는 방법에 대해서는 [여기](https://huggingface.co/docs/datasets/upload_dataset)에서 자세히 알아보세요.

![dataset](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/hub/webhooks-guides/002-auto-retrain/dataset.png)

## dataset의 변경 사항에 반응하기 위해 Webhook을 생성합니다

먼저 [설정]( https://huggingface.co/settings/webhooks)에서 Webhook을 생성해 보겠습니다.

- 대상 저장소로 데이터셋을 선택합니다. 이 예시에서는 [huggingface-projects/input-dataset](https://huggingface.co/datasets/huggingface-projects/input-dataset)를 대상으로 합니다.
- Webhook URL에는 임시로 더미 값을 입력해도 됩니다. Webhook을 정의하면 해당 Webhook으로 전송될 이벤트를 확인할 수 있습니다. 또한 이벤트를 재생할 수도 있으며, 이는 디버깅에 유용합니다!
- 더 안전하게 만들려면 시크릿을 입력하세요.
- 데이터 변경에 반응하려면 "Repo update" 이벤트에 구독합니다

Webhook은 다음과 같은 형태를 가집니다:

![webhook-creation](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/hub/webhooks-guides/002-auto-retrain/webhook-creation.png)

## Webhook에 반응하기 위해 Space를 만듭니다

이제 Webhook 이벤트에 반응하는 방법이 필요합니다. 이를 위한 간단한 방법은 [Space](https://huggingface.co/docs/hub/spaces-overview)를 사용하는 것입니다!

예제 Space를 [여기](https://huggingface.co/spaces/huggingface-projects/auto-retrain/tree/main)에서 찾을 수 있습니다.

이 Space는 Docker, Python, [FastAPI](https://fastapi.tiangolo.com/), [uvicorn](https://uvicorn.dev)를 사용하여 간단한 HTTP 서버를 실행합니다. Docker Spaces에 대한 자세한 내용은 [여기](https://huggingface.co/docs/hub/spaces-sdks-docker)에서 확인하세요.

엔트리 포인트는 [src/main.py](https://huggingface.co/spaces/huggingface-projects/auto-retrain/blob/main/src/main.py)입니다. 이 파일을 살펴보고 어떤 역할을 하는지 자세히 살펴보겠습니다:

1. HTTP `POST` 요청을 `/webhook`에서 수신하는 FastAPI 앱을 생성합니다:

```python
from fastapi import FastAPI

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

# ...
```

2.  2. 이 경로는 `X-Webhook-Secret` 헤더가 존재하는지, 그리고 그 값이 Webhook 설정에서 설정한 값과 동일한지 확인합니다. `WEBHOOK_SECRET` 시크릿은 Space 설정에 설정되어 있어야 하며, Webhook에 설정된 시크릿과 동일해야 합니다.

```python
# [...]

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)
	# [...]
```

3. 이벤트의 페이로드(payload)는 JSON으로 인코딩됩니다. 여기서는 pydantic 모델을 사용하여 이벤트 페이로드를 파싱합니다. 또한 다음 조건에서만 Webhook을 실행하도록 지정합니다:
- 이 이벤트는 입력 데이터셋과 관련이 있습니다
- 이벤트는 저장소 콘텐츠의 업데이트, 즉 새로운 커밋이 생성되었음을 의미합니다

```python
# 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}
	#[...]
```

4. payload가 유효하면 다음 단계는 AutoTrain에서 프로젝트를 생성하고, 입력 데이터셋으로 입력 모델(`microsoft/resnet-50`은 예시입니다)의 fine-tuning을 예약한 후, 완료 시 데이터셋에 discussion을 생성하는 것입니다!

```python
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"])
```

주석 안의 링크를 방문하여 학습 비용 추정을 검토하고, 모델의 파인튜닝을 시작하세요!

![community tab notification](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/hub/webhooks-guides/002-auto-retrain/notification.png)

이 예시에서는 Hugging Face AutoTrain을 사용하여 모델을 빠르게 fine-tuning했지만, 물론 사용자 자신의 training 인프라를 사용할 수도 있습니다!

Space를 개인 네임스페이스로 복제하여 자유롭게 실험해 보세요. 두 개의 시크릿을 제공해야 합니다:
- `WEBHOOK_SECRET` : Webhook의 시크릿입니다.
- `HF_ACCESS_TOKEN`: `write` 권한이 있는 User Access Token입니다. [설정](https://huggingface.co/settings/tokens)에서 생성할 수 있습니다.

원하는 데이터셋과 모델을 사용하려면 [`config.json` 파일](https://huggingface.co/spaces/huggingface-projects/auto-retrain/blob/main/config.json)도 조정해야 합니다:

```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로 이벤트를 보내도록 설정하세요

마지막으로, 웹훅을 설정하여 Space로 POST 요청을 보내도록 구성해야 합니다.

먼저 컨텍스트 메뉴에서 Space의 "direct URL"을 가져오겠습니다. "Embed this Space"를 클릭하고 "Direct URL"을 복사하세요.

![embed this Space](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/hub/webhooks-guides/002-auto-retrain/duplicate-space.png)

![direct URL](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/hub/webhooks-guides/002-auto-retrain/direct-url.png)

해당 URL로 요청을 보내도록 Webhook을 업데이트하세요:

![webhook settings](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/hub/webhooks-guides/002-auto-retrain/update-webhook.png)

그리고 끝입니다! 이제 입력 데이터셋에 커밋할 때마다 AutoTrain으로 ResNet-50을 파인튜닝합니다 🎉

