Hub Python Library documentation

Hubに任意のMLフレームワークを統合する

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v2.4.0).
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 は、モデルのホスティングとコミュニティでの共有を容易にします。オープンソースエコシステムにおける数十のライブラリをサポートしています。私たちは常にこのサポートを拡大し、協働型機械学習の発展を推進するために取り組んでいます。huggingface_hubライブラリはこのプロセスにおいて重要な役割を果たし、任意の Python スクリプトからファイルを簡単にプッシュおよびロードできるようにします。

Hubとライブラリを統合するには、主に4つの方法があります。

  1. Push to Hub: モデルを Hub にアップロードするためのメソッドを実装します。これには、モデルの重みのほか、モデルカードや、モデルを実行するために必要な関連情報やデータ(例えば、トレーニングログなど)が含まれます。このメソッドは通常、push_to_hub()と呼ばれます。
  2. Hubからのダウンロード: Hubからモデルを読み込むためのメソッドを実装します。このメソッドは、モデルの設定/重みをダウンロードし、モデルを読み込む必要があります。このメソッドは、from_pretrainedまたはload_from_hub()と呼ばれることがよくあります。
  3. ウィジェット: Hub上のモデルのランディングページにウィジェットを表示します。これにより、ユーザーはブラウザからモデルをすばやく試すことができます。

このガイドでは、最初の2つのトピックに焦点を当てます。ライブラリを統合するために使用できる2つの主要なアプローチを、それぞれの利点と欠点とともに紹介します。2つのアプローチの選択を支援するために、ガイドの末尾にすべてを要約しています。これらは単なるガイドラインであり、ご自身の要件に合わせて自由に調整して問題ありません。

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: 特定のブランチからダウンロード
  • cache_dir: 特定のディレクトリにファイルをキャッシュするためのオプション
  • force_download/local_files_only: キャッシュを再利用するかどうか
  • proxies: HTTPセッションを設定

モデルをプッシュする際、同様のパラメータがサポートされています:

  • commit_message: カスタムコミットメッセージ
  • private: リポジトリが存在しない場合は、プライベートリポジトリを作成します
  • create_pr: main にプッシュする代わりに PR を作成します
  • branch: main ブランチではなく、ブランチにプッシュします
  • allow_patterns/ignore_patterns: アップロードするファイルをフィルタリング
  • token
  • …

これらのパラメータはすべて、上記で確認した実装に追加し、huggingface_hub のメソッドに渡すことができます。 ただし、パラメータが変更されたり、新しい機能が追加されたりした場合、パッケージの更新が必要になります。これらのパラメータをサポートすることは、ご自身でメンテナンスするドキュメントが増えることを意味します。これらの制約を軽減する方法を見るために、次のセクション クラスの継承 へ進みましょう。

より複雑なアプローチ: クラスの継承

上記で確認したように、Hubと統合するためにライブラリに含めるべき主なメソッドは2つあります。ファイルのアップロード(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です。これはすぐに使用できる統合です。

どのように使用しますか?

PyTorchモデルをHubから読み込む/Hubに保存する方法は、以下の通りです。

>>> 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クラスでプッシュされたすべてのモデルに、引用セクションとライセンスの詳細が自動的に含まれます。モデルカードのテンプレートの定義方法の詳細については、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ファイルにシリアライズします。これにより、2つの利点があります。

  1. ユーザーは、あなたと完全に同じパラメータでモデルを再読み込みできます。
  2. config.json ファイルが存在すると、Hub でのアナリティクス(つまり「ダウンロード数」)が自動的に有効になります。

では、実際にはどのように動作するのでしょうか。ユーザーの視点からプロセスをできるだけスムーズにするために、いくつかのルールがあります。

  • __init__ メソッドが config 入力を期待している場合、リポジトリに config.json として自動的に保存されます。
  • config 入力パラメータが dataclass 型でアノテーションされている場合(例: config: Optional[MyConfigClass] = None)、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).
    • エンコーダーは、指定された型のオブジェクトを入力として受け取り、JSON 形式でシリアライズ可能な値を返します。これは、save_pretrained を使用してモデルを保存する際に使用されます。
    • デコーダーは生データ(通常は辞書)を入力として受け取り、元のオブジェクトを再構築します。これはfrom_pretrainedでモデルを読み込む際に使用されます。
  3. __init__ シグネチャに型アノテーションを追加します。これにより、mixin がクラスが期待する型を把握し、どのデコーダーを使用すべきかを判断できるようになるため、重要です。

簡便さのため、上記の例におけるエンコーダー/デコーダー関数は堅牢ではありません。具体的な実装では、ほとんどの場合、エッジケースを適切に処理する必要があります。

簡単な比較

見てきた2つのアプローチの長所と短所を簡単にまとめましょう。以下の表はあくまで参考情報です。 お使いのフレームワークには、対応が必要な固有の特性がある場合があります。このガイドは、統合をどのように処理するかに関する指針やアイデアを提供するためにあります。ご質問があれば、お気軽にお問い合わせください!

統合ヘルパーの使用ModelHubMixinの使用
ユーザー体験model = load_from_hub(...)
push_to_hub(model, ...)
model = MyModel.from_pretrained(...)
model.push_to_hub(...)
柔軟性非常に柔軟です。
実装を完全に制御できます。
柔軟性が低い。
フレームワークにはモデルクラスが必要です。
メンテナンス設定のサポート追加や新機能の追加など、さらなるメンテナンスが必要です。ユーザーから報告された問題の修正も必要になる場合があります。Hubとのほとんどのインタラクションがhuggingface_hubで実装されているため、メンテナンスが少なくなります。
ドキュメント / 型アノテーション手動で記述する必要があります。huggingface_hubによって部分的に処理されます。
ダウンロードカウンター手動で処理する必要があります。クラスにconfig属性がある場合、デフォルトで有効になります。
モデルカード手動で処理するデフォルトでは、library_name、tags などが生成されます。
Update on GitHub