Hub Python Library documentation

Hub에 모든 ML 프레임워크 통합

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Hub에 모든 ML 프레임워크 통합

Hugging Face Hub를 사용하면 모델을 호스팅하고 커뮤니티와 공유하는 것이 쉬워집니다. 오픈 소스 생태계의 수십 개의 라이브러리를 지원합니다. 우리는 협력적 Machine Learning을 발전시키기 위해 이러한 지원을 지속적으로 확장하고 있습니다. huggingface_hub 라이브러리는 이 과정에서 핵심적인 역할을 하여, 모든 Python 스크립트가 파일을 쉽게 push하고 load할 수 있도록 합니다.

Hub에 라이브러리를 통합하는 주요 방법은 네 가지입니다:

  1. Hub에 푸시: 모델을 Hub에 업로드하는 메서드를 구현합니다. 여기에는 모델 가중치, 모델 카드 및 모델을 실행하는 데 필요한 기타 관련 정보 또는 데이터(예: 학습 로그)가 포함됩니다. 이 메서드는 일반적으로 push_to_hub()라고 불립니다.
  2. Hub에서 다운로드: Hub에서 모델을 로드하는 메서드를 구현합니다. 이 메서드는 모델의 구성/가중치를 다운로드하고 모델을 로드해야 합니다. 이 메서드는 보통 from_pretrained 또는 load_from_hub()라고 불립니다.
  3. Widgets: Hub의 모델 랜딩 페이지에 위젯을 표시합니다. 이를 통해 사용자는 브라우저에서 모델을 바로 사용해 볼 수 있습니다.

이 가이드에서는 처음 두 가지 주제에 초점을 맞춥니다. 라이브러리를 통합할 때 사용할 수 있는 두 가지 주요 접근 방식과 각각의 장점 및 단점을 소개합니다. 두 가지 중 선택을 돕기 위해 가이드 말미에 모든 내용을 요약했습니다. 이는 요구 사항에 맞게 자유롭게 조정할 수 있는 지침임을 유념해 주세요.

Inference와 Widgets에 관심이 있으시다면 이 가이드를 따라가실 수 있습니다. 두 경우 모두, Hub에 라이브러리를 통합하여 문서에 등재되기를 원하시면 저희에게 연락해 주세요.

유연한 접근법: 헬퍼

The first approach to integrate a library to the Hub is to actually implement the push_to_hub and from_pretrained methods by yourself. This gives you full flexibility on which files you need to upload/download and how to handle inputs specific to your framework. You can refer to the two upload files and download files guides to learn more about how to do that. This is, for example how the FastAI integration is implemented (see push_to_hub_fastai() and from_pretrained_fastai()).

라이브러리에 따라 구현 방식이 다를 수 있지만, 워크플로우는 종종 유사합니다.

from_pretrained

from_pretrained 메서드는 보통 다음과 같은 형태를 가집니다:

def from_pretrained(model_id: str) -> MyModelClass:
    # Download model from Hub
    cached_model = hf_hub_download(
        repo_id=model_id,
        filename="model.pkl",
        library_name="fastai",
        library_version=get_fastai_version(),
    )

    # Load model
    return load_model(cached_model)

push_to_hub

push_to_hub 메서드는 리포지토리 생성, 모델 카드 생성 및 가중치 저장을 처리하기 위해 다소 복잡한 로직이 필요합니다. 일반적인 접근 방식은 이러한 모든 파일을 임시 폴더에 저장한 후 업로드하고 삭제하는 것입니다.

def push_to_hub(model: MyModelClass, repo_name: str) -> None:
   api = HfApi()

   # Create repo if not existing yet and get the associated repo_id
   repo_id = api.create_repo(repo_name, exist_ok=True)

   # Save all files in a temporary directory and push them in a single commit
   with TemporaryDirectory() as tmpdir:
      tmpdir = Path(tmpdir)

      # Save weights
      save_model(model, tmpdir / "model.safetensors")

      # Generate model card
      card = generate_model_card(model)
      (tmpdir / "README.md").write_text(card)

      # Save logs
      # Save figures
      # Save evaluation metrics
      # ...

      # Push to hub
      return api.upload_folder(repo_id=repo_id, folder_path=tmpdir)

물론 이것은 예시일 뿐입니다. 더 복잡한 조작(원격 파일 삭제, 가중치 실시간 업로드, 가중치 로컬 영속화 등)에 관심이 있으시다면 파일 업로드 가이드를 참고하세요.

한계

유연한 접근 방식이지만, 특히 유지보수 측면에서 몇 가지 단점이 있습니다. Hugging Face 사용자는 huggingface_hub를 사용할 때 추가 기능을 기대하는 경우가 많습니다. 예를 들어, Hub에서 파일을 로드할 때 다음과 같은 매개변수를 제공하는 것이 일반적입니다:

  • token: 비공개 저장소에서 다운로드하기 위해
  • revision: 특정 branch에서 다운로드
  • cache_dir: 특정 디렉터리에 파일을 캐시합니다
  • force_download/local_files_only: 캐시를 재사용할지 여부
  • proxies: HTTP 세션 구성

모델을 푸시할 때, 유사한 파라미터가 지원됩니다:

  • commit_message: 커스텀 커밋 메시지
  • private: 저장소가 없으면 비공개 저장소를 생성
  • create_pr: main에 푸시하는 대신 PR을 생성합니다
  • branch: main 브랜치가 아닌 브랜치에 push
  • allow_patterns/ignore_patterns: 업로드할 파일을 필터링
  • token
  • …

이 모든 매개변수는 위에서 살펴본 구현에 추가하여 huggingface_hub 메서드에 전달할 수 있습니다. 그러나 매개변수가 변경되거나 새로운 기능이 추가되면 패키지를 업데이트해야 합니다. 이러한 매개변수를 지원하는 것은 또한 사용자 측에서 유지보수해야 하는 문서가 더 많아진다는 것을 의미합니다. 이러한 한계를 완화하는 방법을 확인하려면 다음 섹션인 클래스 상속으로 넘어가 보겠습니다.

더 복잡한 접근 방법: 클래스 상속

위에서 확인했듯이, 라이브러리를 Hub와 통합하려면 파일 업로드(push_to_hub)와 파일 다운로드(from_pretrained)라는 두 가지 주요 메서드를 포함해야 합니다. 이 메서드를 직접 구현할 수 있지만, 주의할 점이 있습니다. 이를 해결하기 위해 huggingface_hub는 클래스 상속을 사용하는 도구를 제공합니다. 어떻게 작동하는지 살펴보겠습니다!

많은 경우, 라이브러리는 이미 Python 클래스를 사용하여 모델을 구현하고 있습니다. 이 클래스에는 모델의 속성과 로드, 실행, 학습, 평가에 필요한 메서드가 포함되어 있습니다. 우리의 접근 방식은 믹스인을 사용하여 업로드 및 다운로드 기능을 포함하도록 이 클래스를 확장하는 것입니다. Mixin은 다중 상속을 통해 특정 기능 집합으로 기존 클래스를 확장하도록 설계된 클래스입니다. huggingface_hub는 자체 믹스인인 ModelHubMixin을 제공합니다. 여기서 핵심은 이 믹스인의 동작 방식을 이해하고 어떻게 커스터마이징하는지 아는 것입니다.

ModelHubMixin 클래스는 3개의 public 메서드(push_to_hub, save_pretrained, from_pretrained)를 구현합니다. 이 메서드들은 사용자가 라이브러리를 통해 모델을 로드/저장할 때 호출하는 메서드입니다. ModelHubMixin은 또한 2개의 private 메서드(_save_pretrained와 _from_pretrained)를 정의합니다. 이 메서드들은 사용자가 직접 구현해야 하는 메서드입니다. 따라서 라이브러리를 통합하려면 다음을 수행해야 합니다:

  1. Model 클래스가 ModelHubMixin을 상속하도록 만드세요.
  2. 프라이빗 메서드를 구현합니다:
    • _save_pretrained(): 디렉터리 경로를 입력으로 받아 모델을 해당 경로에 저장하는 메서드입니다. 모델 카드, 모델 가중치, 구성 파일, 학습 로그, 도표 등 모델을 덤프하는 모든 로직을 이 메서드에 작성해야 합니다. 이 모델에 관련 있는 모든 정보는 이 메서드로 처리되어야 합니다. 모델 카드는 모델을 설명하는 데 특히 중요합니다. 자세한 내용은 구현 가이드를 참고하세요.
    • _from_pretrained(): model_id를 입력으로 받아 인스턴스화된 모델을 반환하는 클래스 메서드입니다. 이 메서드는 관련 파일을 다운로드하고 로드해야 합니다.
  3. 완료되었습니다!

ModelHubMixin을 사용하는 장점은 파일의 직렬화/로드 처리를 완료하면 바로 사용할 수 있다는 것입니다. 리포지토리 생성, 커밋, PR, 리비전과 같은 사항은 신경 쓸 필요가 없습니다. ModelHubMixin은 공개 메서드가 문서화되고 타입 어노테이션이 적용되도록 보장하며, Hub에서 모델의 다운로드 횟수를 확인할 수 있습니다. 이 모든 것은 ModelHubMixin에 의해 처리되며 사용자에게 제공됩니다.

구체적인 예시: PyTorch

위에서 살펴본 것의 좋은 예는 PyTorch 프레임워크용 통합인 PyTorchModelHubMixin입니다. 이는 바로 사용할 수 있는 통합입니다.

사용 방법은 무엇인가요?

모든 사용자가 Hub에서 PyTorch 모델을 로드/저장하는 방법은 다음과 같습니다:

>>> import torch
>>> import torch.nn as nn
>>> from huggingface_hub import PyTorchModelHubMixin


# Define your Pytorch model exactly the same way you are used to
>>> class MyModel(
...         nn.Module,
...         PyTorchModelHubMixin, # multiple inheritance
...         library_name="keras-nlp",
...         tags=["keras"],
...         repo_url="https://github.com/keras-team/keras-nlp",
...         docs_url="https://keras.io/keras_nlp/",
...         # ^ optional metadata to generate model card
...     ):
...     def __init__(self, hidden_size: int = 512, vocab_size: int = 30000, output_size: int = 4):
...         super().__init__()
...         self.param = nn.Parameter(torch.rand(hidden_size, vocab_size))
...         self.linear = nn.Linear(output_size, vocab_size)

...     def forward(self, x):
...         return self.linear(x + self.param)

# 1. Create model
>>> model = MyModel(hidden_size=128)

# Config is automatically created based on input + default values
>>> model.param.shape[0]
128

# 2. (optional) Save model to local directory
>>> model.save_pretrained("path/to/my-awesome-model")

# 3. Push model weights to the Hub
>>> model.push_to_hub("my-awesome-model")

# 4. Initialize model from the Hub => config has been preserved
>>> model = MyModel.from_pretrained("username/my-awesome-model")
>>> model.param.shape[0]
128

# Model card has been correctly populated
>>> from huggingface_hub import ModelCard
>>> card = ModelCard.load("username/my-awesome-model")
>>> card.data.tags
["keras", "pytorch_model_hub_mixin", "model_hub_mixin"]
>>> card.data.library_name
"keras-nlp"

구현

구현은 실제로 매우 직관적이며, 전체 구현은 여기에서 확인할 수 있습니다.

  1. 먼저, 클래스를 ModelHubMixin에서 상속하세요:
from huggingface_hub import ModelHubMixin

class PyTorchModelHubMixin(ModelHubMixin):
   (...)
  1. _save_pretrained 메서드를 구현합니다:
from huggingface_hub import ModelHubMixin

class PyTorchModelHubMixin(ModelHubMixin):
   (...)

    def _save_pretrained(self, save_directory: Path) -> None:
        """Save weights from a Pytorch model to a local directory."""
        save_model_as_safetensor(self.module, str(save_directory / SAFETENSORS_SINGLE_FILE))
  1. _from_pretrained 메서드를 구현합니다:
class PyTorchModelHubMixin(ModelHubMixin):
   (...)

   @classmethod # Must be a classmethod!
   def _from_pretrained(
      cls,
      *,
      model_id: str,
      revision: str,
      cache_dir: str,
      force_download: bool,
      local_files_only: bool,
      token: Union[str, bool, None],
      map_location: str = "cpu", # additional argument
      strict: bool = False, # additional argument
      **model_kwargs,
   ):
      """Load Pytorch pretrained weights and return the loaded model."""
        model = cls(**model_kwargs)
        if os.path.isdir(model_id):
            print("Loading weights from local directory")
            model_file = os.path.join(model_id, SAFETENSORS_SINGLE_FILE)
            return cls._load_as_safetensor(model, model_file, map_location, strict)

         model_file = hf_hub_download(
            repo_id=model_id,
            filename=SAFETENSORS_SINGLE_FILE,
            revision=revision,
            cache_dir=cache_dir,
            force_download=force_download,
            token=token,
            local_files_only=local_files_only,
            )
         return cls._load_as_safetensor(model, model_file, map_location, strict)

그리고 끝입니다! 이제 라이브러리를 통해 사용자가 Hub에 파일을 업로드하고 다운로드할 수 있습니다.

고급 사용

위 섹션에서는 ModelHubMixin의 작동 방식을 간략히 살펴보았습니다. 이 섹션에서는 Hugging Face Hub와의 라이브러리 통합을 개선하기 위한 보다 고급 기능을 살펴봅니다.

모델 카드

ModelHubMixin은 모델 카드를 자동으로 생성합니다. 모델 카드는 모델과 함께 제공되며 모델에 대한 중요한 정보를 담고 있는 파일입니다. 내부적으로 모델 카드는 추가 메타데이터가 포함된 단순한 Markdown 파일입니다. 모델 카드는 검색 가능성, 재현성, 공유에 필수적입니다. 자세한 내용은 Model Cards 가이드를 참고하세요.

모델 카드를 반자동으로 생성하는 것은 라이브러리를 통해 업로드되는 모든 모델이 library_name, tags, license, pipeline_tag 등 공통 메타데이터를 공유하도록 보장하는 좋은 방법입니다. 이를 통해 Hub에서 라이브러리가 뒷받침하는 모든 모델을 쉽게 검색할 수 있으며, Hub에 접속한 사용자에게 몇 가지 리소스 링크를 제공합니다. ModelHubMixin을 상속할 때 메타데이터를 직접 정의할 수 있습니다:

class UniDepthV1(
   nn.Module,
   PyTorchModelHubMixin,
   library_name="unidepth",
   repo_url="https://github.com/lpiccinelli-eth/UniDepth",
   docs_url=...,
   pipeline_tag="depth-estimation",
   license="cc-by-nc-4.0",
   tags=["monocular-metric-depth-estimation", "arxiv:1234.56789"]
):
   ...

기본적으로 제공한 정보로 일반적인 모델 카드가 생성됩니다(예: pyp1/VoiceCraft_giga830M). 하지만 사용자 정의 모델 카드 템플릿을 정의할 수도 있습니다!

이 예시에서 VoiceCraft 클래스로 push된 모든 모델에는 인용 섹션과 라이선스 세부 정보가 자동으로 포함됩니다. 모델 카드 템플릿을 정의하는 방법에 대한 자세한 내용은 Model Cards 가이드를 참고하세요.

MODEL_CARD_TEMPLATE = """
---
# For reference on model card metadata, see the spec: https://github.com/huggingface/hub-docs/blob/main/modelcard.md?plain=1
# Doc / guide: https://huggingface.co/docs/hub/model-cards
{{ card_data }}
---

This is a VoiceCraft model. For more details, please check out the official Github repo: https://github.com/jasonppy/VoiceCraft. This model is shared under a Attribution-NonCommercial-ShareAlike 4.0 International license.

## Citation

@article{peng2024voicecraft,
  author    = {Peng, Puyuan and Huang, Po-Yao and Li, Daniel and Mohamed, Abdelrahman and Harwath, David},
  title     = {VoiceCraft: Zero-Shot Speech Editing and Text-to-Speech in the Wild},
  journal   = {arXiv},
  year      = {2024},
}
"""

class VoiceCraft(
   nn.Module,
   PyTorchModelHubMixin,
   library_name="voicecraft",
   model_card_template=MODEL_CARD_TEMPLATE,
   ...
):
   ...

마지막으로, 동적 값으로 모델 카드 생성 과정을 확장하려면 generate_model_card() 메서드를 오버라이드할 수 있습니다:

from huggingface_hub import ModelCard, PyTorchModelHubMixin

class UniDepthV1(nn.Module, PyTorchModelHubMixin, ...):
   (...)

   def generate_model_card(self, *args, **kwargs) -> ModelCard:
      card = super().generate_model_card(*args, **kwargs)
      card.data.metrics = ...  # add metrics to the metadata
      card.text += ... # append section to the modelcard
      return card

설정

ModelHubMixin은 모델 구성을 대신 처리합니다. 모델을 인스턴스화할 때 입력 값을 자동으로 확인하고 config.json 파일로 직렬화합니다. 이를 통해 두 가지 이점을 얻을 수 있습니다:

  1. 사용자는 사용자와 동일한 매개변수로 모델을 다시 로드할 수 있습니다.
  2. config.json 파일이 있으면 Hub에서 분석(즉, “다운로드” 수)이 자동으로 활성화됩니다.

그렇다면 실제로는 어떻게 작동할까요? 사용자 관점에서 프로세스를 최대한 매끄럽게 만들기 위해 몇 가지 규칙이 적용됩니다:

  • __init__ 메서드가 config 입력을 기대하는 경우, 자동으로 config.json으로 저장됩니다.
  • config 입력 매개변수가 dataclass 타입으로 주석 처리된 경우(예: config: Optional[MyConfigClass] = None), config 값은 자동으로 올바르게 역직렬화됩니다.
  • 초기화 시 전달된 모든 값은 config 파일에도 저장됩니다. 따라서 config 입력을 반드시 기대하지 않아도 이 기능을 활용할 수 있습니다.

예:

class MyModel(ModelHubMixin):
   def __init__(value: str, size: int = 3):
      self.value = value
      self.size = size

   (...) # implement _save_pretrained / _from_pretrained

model = MyModel(value="my_value")
model.save_pretrained(...)

# config.json contains passed and default values
{"value": "my_value", "size": 3}

그렇다면 JSON으로 직렬화할 수 없는 값은 어떻게 처리해야 할까요? 기본적으로 설정 파일을 저장할 때 해당 값은 무시됩니다. 그러나 일부 경우, 라이브러리가 이미 직렬화할 수 없는 커스텀 객체를 입력으로 기대하고 있으며, 내부 로직의 타입을 업데이트하기 위해 내부 로직을 수정하고 싶지 않을 수 있습니다. 걱정하지 마세요! ModelHubMixin을 상속할 때 모든 타입에 대해 커스텀 인코더/디코더를 전달할 수 있습니다. 이는 다소 많은 작업이 필요하지만, 라이브러리를 Hub에 통합할 때 내부 로직이 그대로 유지되도록 보장합니다.

argparse.Namespace 설정을 입력으로 기대하는 클래스에 대한 구체적인 예시는 다음과 같습니다:

class VoiceCraft(nn.Module):
    def __init__(self, args):
      self.pattern = self.args.pattern
      self.hidden_size = self.args.hidden_size
      ...

해결 방법 중 하나는 __init__ 시그니처를 def __init__(self, pattern: str, hidden_size: int)으로 변경하고, 해당 클래스를 인스턴스화하는 모든 스니펫을 업데이트하는 것입니다. 이는 유효한 수정 방법이지만, 해당 라이브러리를 사용하는 하위 애플리케이션이 깨질 수 있습니다.

또 다른 해결책은 argparse.Namespace를 사전으로 변환하는 간단한 인코더/디코더를 제공하는 것입니다.

from argparse import Namespace

class VoiceCraft(
   nn.Module,
   PyTorchModelHubMixin,  # inherit from mixin
   coders={
      Namespace : (
         lambda x: vars(x),  # Encoder: how to convert a `Namespace` to a valid jsonable value?
         lambda data: Namespace(**data),  # Decoder: how to reconstruct a `Namespace` from a dictionary?
      )
   }
):
    def __init__(self, args: Namespace): # annotate `args`
      self.pattern = self.args.pattern
      self.hidden_size = self.args.hidden_size
      ...

위 스니펫에서 클래스의 내부 로직과 __init__ 시그니처가 모두 변경되지 않았습니다. 이는 라이브러리를 위한 기존 모든 코드 스니펫이 계속 작동한다는 것을 의미합니다. 이를 위해 다음을 수행해야 했습니다:

  1. 믹스인(PytorchModelHubMixin)을 상속합니다.
  2. 상속 시 coders 파라미터를 전달합니다. 이 딕셔너리의 키는 처리하려는 사용자 정의 유형이며, 값은 튜플입니다. (encoder, decoder).
    • 인코더는 지정된 유형의 객체를 입력으로 받아 jsonable 값을 반환합니다. 이는 save_pretrained를 사용하여 모델을 저장할 때 사용됩니다.
    • 디코더는 원시 데이터(일반적으로 딕셔너리)를 입력으로 받아 초기 객체를 재구성합니다. 이는 from_pretrained로 모델을 로드할 때 사용됩니다.
  3. __init__ 시그니처에 타입 주석을 추가하세요. 이는 믹스인이 해당 클래스에서 어떤 타입이 기대되는지, 따라서 어떤 디코더를 사용해야 하는지를 파악하는 데 중요합니다.

간결성을 위해 위의 예시에서 인코더/디코더 함수는 견고하지 않습니다. 구체적인 구현을 위해서는 가장 가능성이 높은 코너 케이스를 적절히 처리해야 합니다.

빠른 비교

두 가지 접근 방식의 장점과 단점을 간단히 요약해 보겠습니다. 아래 표는 참고용입니다. 사용 중인 프레임워크에는 처리해야 할 고유한 특성이 있을 수 있습니다. 이 가이드는 통합을 처리하는 방법에 대한 지침과 아이디어를 제공하기 위한 것입니다. 궁금한 점이 있으시면 언제든지 문의해 주세요!

통합헬퍼 사용ModelHubMixin 사용
사용자 경험model = load_from_hub(...)
push_to_hub(model, ...)
model = MyModel.from_pretrained(...)
model.push_to_hub(...)
유연성매우 유연합니다.
구현을 완전히 제어할 수 있습니다.
유연성이 낮습니다.
프레임워크에 모델 클래스가 있어야 합니다.
유지 관리설정 지원 및 새로운 기능 추가를 위한 추가 유지보수 작업이 필요합니다. 사용자가 보고한 문제를 수정해야 할 수도 있습니다.대부분의 Hub 상호작용이 huggingface_hub에 구현되어 있어 유지보수가 적습니다.
Documentation / Type annotation수동으로 작성할 예정입니다.huggingface_hub에 의해 부분적으로 처리됩니다.
다운로드 횟수수동으로 처리해야 합니다.클래스에 config 속성이 있으면 기본적으로 활성화됩니다.
모델 카드수동으로 처리해야 합니다기본적으로 library_name, tags 등으로 생성됩니다.
Update on GitHub