Hub Python 庫文件
將任何機器學習框架與 Hub 整合
並獲得增強的文件體驗
開始使用
將任何機器學習框架與 Hub 整合
Hugging Face Hub 使模型託管和社群共享變得容易。它支援開源生態系統中的數十個庫。我們一直在努力擴充套件這種支援,以推動協作機器學習向前發展。huggingface_hub
庫在此過程中發揮著關鍵作用,允許任何 Python 指令碼輕鬆推送和載入檔案。
將庫與 Hub 整合有四種主要方式
- 推送到 Hub: 實現將模型上傳到 Hub 的方法。這包括模型權重、模型卡以及執行模型所需的任何其他相關資訊或資料(例如,訓練日誌)。此方法通常稱為
push_to_hub()
。 - 從 Hub 下載: 實現從 Hub 載入模型的方法。該方法應下載模型配置/權重並載入模型。此方法通常稱為
from_pretrained
或load_from_hub()
。 - 小部件: 在 Hub 上您的模型登陸頁面上顯示一個小部件。它允許使用者從瀏覽器快速試用模型。
在本指南中,我們將重點關注前兩個主題。我們將介紹用於整合庫的兩種主要方法,以及它們的優缺點。本指南末尾總結了所有內容,以幫助您在兩者之間進行選擇。請記住,這些只是指導原則,您可以根據自己的需求自由調整。
如果您對推理和小部件感興趣,可以遵循本指南。在這兩種情況下,如果您正在將庫與 Hub 整合並希望在我們的文件中列出,可以聯絡我們。
靈活的方法:輔助函式
將庫整合到 Hub 的第一種方法是自己實現 push_to_hub
和 from_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_hub
、save_pretrained
和 from_pretrained
)。這些是您的使用者將呼叫以使用您的庫載入/儲存模型的方法。ModelHubMixin 還定義了 2 個私有方法(_save_pretrained
和 _from_pretrained
)。這些是您必須實現的方法。因此,要整合您的庫,您應該
- 使您的模型類繼承自ModelHubMixin。
- 實現私有方法
- _save_pretrained():該方法接受目錄路徑作為輸入,並將模型儲存到該目錄。您必須編寫所有邏輯,在此方法中轉儲您的模型:模型卡、模型權重、配置檔案、訓練日誌和圖表。此模型的任何相關資訊都必須由此方法處理。模型卡對於描述您的模型尤為重要。有關更多詳細資訊,請檢視我們的實現指南。
- _from_pretrained():類方法,接受
model_id
作為輸入並返回一個例項化的模型。該方法必須下載相關檔案並載入它們。
- 大功告成!
使用 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"
實現
實現起來其實非常簡單,完整的實現可以在這裡找到。
- 首先,讓您的類繼承自
ModelHubMixin
from huggingface_hub import ModelHubMixin
class PyTorchModelHubMixin(ModelHubMixin):
(...)
- 實現
_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))
- 實現
_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_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_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 個好處
- 使用者將能夠以與您完全相同的引數重新載入模型。
- 擁有
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__
簽名都沒有改變。這意味著您庫的所有現有程式碼片段將繼續工作。為了實現這一點,我們必須
- 繼承混入類(本例中為
PytorchModelHubMixin
)。 - 在繼承中傳遞
coders
引數。這是一個字典,其中鍵是要處理的自定義型別。值為一個元組(encoder, decoder)
。- 編碼器接受指定型別的物件作為輸入,並返回一個可 JSON 化的值。這將在使用
save_pretrained
儲存模型時使用。 - 解碼器接受原始資料(通常是字典)作為輸入,並重構初始物件。這將在使用
from_pretrained
載入模型時使用。
- 編碼器接受指定型別的物件作為輸入,並返回一個可 JSON 化的值。這將在使用
- 向
__init__
簽名新增型別註釋。這對於讓混入類知道類需要哪種型別,從而知道要使用哪個解碼器非常重要。
為簡單起見,上述示例中的編碼器/解碼器函式不夠健壯。對於具體的實現,您很可能需要妥善處理邊緣情況。
快速比較
讓我們快速總結一下我們看到的兩種方法及其優缺點。下表僅供參考。您的框架可能有一些需要解決的特殊性。本指南僅在此處提供關於如何處理整合的指導和想法。無論如何,如果您有任何問題,請隨時聯絡我們!
整合 | 使用輔助函式 | 使用 ModelHubMixin |
---|---|---|
使用者體驗 | 模型 = load_from_hub(...) push_to_hub(模型, ...) | 模型 = MyModel.from_pretrained(...) 模型.push_to_hub(...) |
靈活性 | 非常靈活。 您完全控制實現。 | 靈活性較低。 您的框架必須有一個模型類。 |
維護 | 更多維護以新增對配置和新功能的支援。可能還需要修復使用者報告的問題。 | 維護較少,因為大部分與 Hub 的互動都在 huggingface_hub 中實現。 |
文件/型別註釋 | 需手動編寫。 | 部分由 huggingface_hub 處理。 |
下載計數器 | 需手動處理。 | 如果類具有 config 屬性,則預設啟用。 |
模型卡 | 需手動處理 | 預設生成,包含庫名稱、標籤等。 |