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 整合並希望在我們的文件中列出,可以聯絡我們。

靈活的方法:輔助函式

將庫整合到 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 類實現了其模型。該類包含模型的屬性以及載入、執行、訓練和評估模型的方法。我們的方法是擴充套件此 क्लास 以使用 mixin 包含上傳和下載功能。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,
      proxies: Optional[Dict],
      resume_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,
            proxies=proxies,
            resume_download=resume_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 檔案。模型卡對於可發現性、可重現性和共享至關重要!請檢視模型卡指南以獲取更多詳細資訊。

半自動生成模型卡是一種很好的方式,可以確保使用您的庫推送的所有模型都共享通用元資料: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` 輸入引數帶有資料類型別註釋(例如 `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__ 簽名新增型別註釋。這對於讓混入類知道類需要哪種型別,從而知道要使用哪個解碼器非常重要。

為簡單起見,上述示例中的編碼器/解碼器函式不夠健壯。對於具體的實現,您很可能需要妥善處理邊緣情況。

快速比較

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

整合 使用輔助函式 使用 ModelHubMixin
使用者體驗 模型 = load_from_hub(...)
push_to_hub(模型, ...)
模型 = MyModel.from_pretrained(...)
模型.push_to_hub(...)
靈活性 非常靈活。
您完全控制實現。
靈活性較低。
您的框架必須有一個模型類。
維護 更多維護以新增對配置和新功能的支援。可能還需要修復使用者報告的問題。 維護較少,因為大部分與 Hub 的互動都在 huggingface_hub 中實現。
文件/型別註釋 需手動編寫。 部分由 huggingface_hub 處理。
下載計數器 需手動處理。 如果類具有 config 屬性,則預設啟用。
模型卡 需手動處理 預設生成,包含庫名稱、標籤等。
< > 在 GitHub 上更新

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