Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Hugging Face 모델 가져오기

AIP에서 기본 제공하는 언어 모델 외에 Hugging Face나 spaCy 같은 언어 모델 프레임워크를 Conda 또는 PyPI 패키지로 사용할 수 있습니다. 프레임워크가 사전 학습 가중치나 말뭉치를 인터넷에서 받는 경우에는 별도 준비가 필요합니다. 사용자 Python 코드는 기본적으로 공개 인터넷에 접근할 수 없습니다.

과거 Import an open source model 기능의 기본 어댑터는 더 이상 지원하거나 기능을 추가하지 않는 참조 구현입니다. 새 연결은 자신의 모델 어댑터 저장소에서 게시하고 유지합니다. Hugging Face 직렬화기를 사용하면 모델과 토크나이저의 저장 및 로드를 구성할 수 있습니다.

파일 데이터셋과 직접 다운로드

네트워크를 열지 않는 경로는 외부에서 모델 파일을 내려받아 비정형 데이터셋으로 가져오는 방식입니다. 직접 다운로드하려면 승인된 네트워크 송신 정책과 저장소의 외부 시스템 설정을 준비합니다. 두 경로 모두 모델을 로드한 뒤 어댑터로 감싸 게시합니다.

직접 관리하는 임베딩 어댑터

아래는 bert-base-cased 같은 AutoModel과 토크나이저를 사용하는 어댑터입니다. palantir_models, transformers, torch와 pandas가 필요합니다. Model Training 저장소의 src/main/model_adapters/embedding_adapter.py에 둡니다.

입력 inference_data는 text 문자열 열을 가진 표이고 output_data는 text와 embedding 벡터를 반환합니다. 한 번에 128개 문장을 토큰화하고 attention_mask로 패딩을 제외한 평균을 계산한 뒤 L2 정규화합니다.

모델의 장치 이동은 첫 predict에서 처리합니다. load와 추론이 서로 다른 프로세스에서 실행될 수 있으므로 load에서 CUDA 컨텍스트를 초기화하지 않습니다. GPU가 있으면 cuda:0, 없으면 CPU를 사용합니다.

import pandas as pd
import torch
import torch.nn.functional as F
import palantir_models as pm
from palantir_models.serializers import HfAutoModelSerializer, HfAutoTokenizerSerializer

class EmbeddingAdapter(pm.ModelAdapter):
    SENTENCE_BATCH_SIZE = 128

    @pm.auto_serialize(
        tokenizer=HfAutoTokenizerSerializer(),
        model=HfAutoModelSerializer(),
    )
    def __init__(self, tokenizer, model):
        self.tokenizer = tokenizer
        self.model = model
        self._device = None

    @classmethod
    def api(cls):
        return (
            {"inference_data": pm.Pandas([("text", str)])},
            {"output_data": pm.Pandas([("text", str), ("embedding", list[float])])},
        )

    def predict(self, inference_data: pd.DataFrame):
        if self._device is None:
            self._device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
            self.model.to(self._device)
            self.model.eval()
        sentences = inference_data["text"].tolist()
        embeddings = []
        for start in range(0, len(sentences), self.SENTENCE_BATCH_SIZE):
            encoded = self.tokenizer(
                sentences[start:start + self.SENTENCE_BATCH_SIZE],
                padding=True, truncation=True, return_tensors="pt",
            ).to(self._device)
            with torch.no_grad():
                token_embeddings = self.model(**encoded)[0]
                mask = encoded["attention_mask"].unsqueeze(-1).float()
                pooled = (token_embeddings * mask).sum(dim=1) / mask.sum(dim=1).clamp(min=1e-9)
                normalized = F.normalize(pooled, p=2, dim=1)
            embeddings.extend(normalized.cpu().tolist())
        inference_data["embedding"] = embeddings
        return inference_data

모델 파일을 데이터셋으로 가져오기

Hugging Face에서 모델 파일을 내려받고 New > Dataset > Import > Select all files로 업로드합니다. 사설 네트워크의 공유 드라이브에 파일을 두었다면 Data Connection 동기화로 가져올 수도 있습니다. 생성한 데이터셋은 표 스키마가 없는 파일 데이터셋입니다.

모델의 Files and versions에 있는 설정, 토크나이저와 필요한 가중치 파일을 포함합니다. 같은 모델의 PyTorch용 pytorch_model.bin과 TensorFlow용 tf_model.h5 같은 대체 가중치를 모두 가져올 필요는 없으며 보통 PyTorch 형식을 권장합니다. 가중치가 여러 파일로 나뉜 모델은 필요한 파일 묶음을 모두 유지합니다.

모델이 크면 DRIVER_MEMORY_MEDIUM 같은 Spark 프로필로 드라이버 메모리를 늘려야 할 수 있습니다. 아래 경로는 실제 모델 파일 데이터셋과 출력 모델로 바꿉니다. CBAC 환경에서는 출력 모델을 미리 생성합니다.

from palantir_models.transforms import ModelOutput, copy_model_to_driver
from transforms.api import transform, Input
from transformers import AutoTokenizer, AutoModel
from main.model_adapters.embedding_adapter import EmbeddingAdapter

@transform(
    model_output=ModelOutput("/Models/published/embedding_model"),
    hugging_face_raw=Input("/Models/imported/hugging_face_files"),
)
def compute(model_output, hugging_face_raw):
    model_dir = copy_model_to_driver(hugging_face_raw.filesystem())
    tokenizer = AutoTokenizer.from_pretrained(model_dir)
    model = AutoModel.from_pretrained(model_dir)
    model_output.publish(model_adapter=EmbeddingAdapter(tokenizer, model))

버전 변경 종류를 명시하는 publish의 change_type에는 ModelVersionChangeType.MINOR 같은 SDK의 변경 유형 값을 지정할 수 있습니다. 위의 파일 가져오기 예제는 기본 게시 호출을 사용합니다.

직접 다운로드를 위한 도메인

Hugging Face에서 직접 내려받으려면 플랫폼 인스턴스의 네트워크 송신 정책에서 필요한 도메인을 허용합니다.

https://huggingface.co
https://hf.co
https://cas-bridge.xethub.hf.co
https://cas-server.xethub.hf.co
https://transfer.xethub.hf.co
https://cdn-lfs.hf.co
https://cdn-lfs-us-1.hf.co
https://cdn-lfs-eu-1.hf.co
https://us.gcp.cdn.hf.co
https://us.aws.cdn.hf.co

다운로드 도메인은 사전 안내 없이 바뀔 수 있습니다. 위 목록을 허용해도 실패하면 요청 로그에서 여전히 차단되는 대상 도메인을 확인합니다. 진단 로그에 인증 헤더나 토큰을 남기지 않도록 필요한 대상 정보만 확인합니다.

저장소에 transforms-external-systems를 추가하고 승인한 송신 정책을 사용하도록 외부 시스템 접근을 구성합니다. 아래는 EgressPolicy와 ExportControl을 사용하는 경로입니다. EGRESS_POLICY_RID와 EXPORT_MARKING_IDS는 관리자가 승인한 실제 정책 RID 및 Marking ID 목록으로 바꿉니다. 출력 모델 경로도 실제 값으로 설정합니다.

import tempfile
from palantir_models.transforms import ModelOutput
from transforms.api import transform
from transforms.external.systems import use_external_systems, EgressPolicy, ExportControl
from transformers import AutoTokenizer, AutoModel
from main.model_adapters.embedding_adapter import EmbeddingAdapter

EGRESS_POLICY_RID = "YOUR_APPROVED_EGRESS_POLICY_RID"
EXPORT_MARKING_IDS = ["YOUR_APPROVED_EXPORT_MARKING_ID"]

@use_external_systems(
    export_control=ExportControl(markings=EXPORT_MARKING_IDS),
    egress=EgressPolicy(EGRESS_POLICY_RID),
)
@transform(model_output=ModelOutput("/Models/published/embedding_model"))
def compute(export_control, egress, model_output):
    with tempfile.TemporaryDirectory() as cache_dir:
        tokenizer = AutoTokenizer.from_pretrained("bert-base-cased", cache_dir=cache_dir)
        model = AutoModel.from_pretrained("bert-base-cased", cache_dir=cache_dir)
        model_output.publish(model_adapter=EmbeddingAdapter(tokenizer, model))

PermissionError: [Errno 13] Permission denied: '/.cache'가 발생하면 읽기 전용 기본 캐시 대신 쓰기 가능한 디렉터리를 cache_dir로 지정합니다. 위 코드는 임시 캐시를 사용하여 모델 게시가 끝난 뒤 정리합니다.

게시한 모델 소비

게시한 모델 버전은 ModelInput으로 하위 변환에 로드합니다. 위 어댑터는 output_data를 반환하므로 model.transform(input_data).output_data를 사용합니다. 다른 어댑터의 출력 이름은 모델 버전의 API에서 확인합니다. 저장소 추론의 sidecar 및 의존성 조건을 따릅니다.