Hub Python 庫文件

將任何機器學習框架與 Hub 整合

Hugging Face's logo
加入 Hugging Face 社群

並獲得增強的文件體驗

開始使用

將任何機器學習框架與 Hub 整合

Hugging Face Hub 使得與社群共享和託管模型變得容易。它支援開源生態系統中的數十種庫。我們一直在努力擴充套件這些支援,以推動機器學習的協作。huggingface_hub 庫在此過程中發揮著關鍵作用,它允許任何 Python 指令碼輕鬆上傳和載入檔案。

整合庫與 Hub 主要有四種方式

  1. 上傳到 Hub:實現一個方法將模型上傳到 Hub。這包括模型權重,以及模型卡以及執行模型所需的任何其他相關資訊或資料(例如,訓練日誌)。這個方法通常稱為 push_to_hub()
  2. 從 Hub 下載:實現一個方法從 Hub 載入模型。該方法應下載模型配置/權重並載入模型。這個方法通常稱為 from_pretrainedload_from_hub()
  3. 小部件:在 Hub 上您模型的著陸頁上顯示一個小部件。它允許使用者透過瀏覽器快速試用模型。

在本指南中,我們將重點關注前兩個主題。我們將介紹整合庫的兩種主要方法,並分析它們的優缺點。所有內容將在指南結尾進行總結,以幫助您在這兩者之間做出選擇。請記住,這些只是您可以根據自己的要求自由調整的指南。

如果您對推理和小部件感興趣,可以遵循本指南。在這兩種情況下,如果您正在整合一個庫並希望在我們的文件中被列出,都可以聯絡我們。

靈活的方法:助手

整合庫到 Hub 的第一種方法是自己實現 push_to_hubfrom_pretrained 方法。這讓您能夠完全靈活地決定需要上傳/下載哪些檔案以及如何處理特定於您框架的輸入。您可以參考上傳檔案下載檔案這兩個指南來了解更多資訊。例如,FastAI 整合就是這樣實現的(參見push_to_hub_fastai()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=repo_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:建立 PR 而不是推送到 main
  • branch:推送到某個分支而不是 main 分支
  • allow_patterns/ignore_patterns:過濾要上傳的檔案
  • token
  • ...

所有這些引數都可以新增到我們上面看到的實現中,並傳遞給 huggingface_hub 方法。但是,如果一個引數發生更改或添加了新功能,您將需要更新您的包。支援這些引數也意味著您需要維護更多的文件。要了解如何緩解這些限制,讓我們進入下一節類繼承

更復雜的方法:類繼承

正如我們在上面看到的,為了將庫整合到 Hub,您需要包含兩個主要方法:上傳檔案(push_to_hub)和下載檔案(from_pretrained)。您可以自己實現這些方法,但這也有其缺點。為了解決這個問題,huggingface_hub 提供了一個使用類繼承的工具。讓我們看看它是如何工作的!

在很多情況下,一個庫已經使用 Python 類來實現其模型。該類包含模型的屬性以及載入、執行、訓練和評估它的方法。我們的方法是擴充套件此類,透過 Mixins 新增上傳和下載功能。一個Mixin 是一個類,它旨在透過使用多重繼承將一組特定功能擴充套件到現有類中。huggingface_hub 提供了自己的 Mixin,即ModelHubMixin。這裡的關鍵是理解它的行為以及如何自定義它。

ModelHubMixin 類實現了 3 個*公共*方法(push_to_hubsave_pretrainedfrom_pretrained)。這些是您的使用者將呼叫以使用您的庫載入/儲存模型的方法。ModelHubMixin 還定義了 2 個*私有*方法(_save_pretrained_from_pretrained)。這些是您必須實現的。因此,要整合您的庫,您應該

  1. 使您的模型類繼承自 ModelHubMixin
  2. 實現私有方法
    • _save_pretrained():該方法接收一個目錄路徑作為輸入,並將模型儲存到其中。您必須在此方法中編寫所有邏輯來轉儲您的模型:模型卡、模型權重、配置檔案、訓練日誌和圖表。與此模型相關的任何相關資訊都必須由此方法處理。 模型卡尤其重要。請參閱我們的實現指南瞭解更多詳情。
    • _from_pretrained():一個*類方法*,接收一個 model_id 作為輸入並返回一個已例項化的模型。該方法必須下載相關檔案並載入它們。
  3. 您就完成了!

使用 ModelHubMixin 的優勢在於,一旦您處理了檔案的序列化/載入,您就可以開始工作了。您無需擔心倉庫建立、提交、PR 或修訂版等問題。ModelHubMixin 還確保公共方法已文件化並帶有型別註釋,您將能夠在 Hub 上檢視模型的下載次數。所有這些都由 ModelHubMixin 處理,並可供您的使用者使用。

具體示例:PyTorch

一個很好的例子就是我們上面看到的 PyTorchModelHubMixin,這是我們為 PyTorch 框架提供的整合。這是一個即用型整合。

如何使用它?

任何使用者都可以這樣從 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 和從 Hub 下載了。

高階用法

在上面的部分,我們簡要討論了 ModelHubMixin 的工作原理。在本節中,我們將瞭解它的一些高階功能,以改進您的庫與 Hugging Face Hub 的整合。

模型卡

ModelHubMixin 會為您生成模型卡。模型卡是伴隨模型的檔案,提供有關模型的重要資訊。在底層,模型卡是簡單的 Markdown 檔案,帶有額外的元資料。模型卡對於可發現性、可復現性和共享至關重要!請參閱模型卡指南瞭解更多詳情。

半自動生成模型卡是一種好方法,可以確保所有使用您的庫推送的模型都共享通用元資料:library_nametagslicensepipeline_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_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. 繼承 Mixin(在本例中是 PytorchModelHubMixin)。
  2. 在繼承時傳遞一個 coders 引數。這是一個字典,其中鍵是您想要處理的自定義型別。值是一個元組 (encoder, decoder)
    • 編碼器接收指定型別的物件作為輸入,並返回一個可 JSON 的值。這將在使用 save_pretrained 儲存模型時使用。
    • 解碼器接收原始資料(通常是字典)作為輸入,並重建初始物件。這將在使用 from_pretrained 載入模型時使用。
  3. __init__ 簽名新增型別註解。這很重要,可以告訴 Mixin 類期望的型別,因此,應該使用哪個解碼器。

為了簡單起見,上面示例中的編碼器/解碼器函式並不健壯。對於具體的實現,您很可能需要正確處理邊界情況。

快速比較

讓我們快速總結一下我們看到的兩種方法及其優缺點。下表僅供參考。您的框架可能有一些需要解決的特定問題。本指南僅用於提供有關如何處理整合的指導和想法。在任何情況下,如果您有任何疑問,請隨時與我們聯絡!

整合 使用助手 使用 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 等預設生成。
在 GitHub 上更新

© . This site is unofficial and not affiliated with Hugging Face, Inc.