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 的第一種方法是自己實現 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 而不是推送到mainbranch:推送到某個分支而不是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_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,
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_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輸入引數被註解為 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__ 簽名都沒有改變。這意味著您庫的所有現有程式碼片段將繼續工作。為了實現這一點,我們不得不
- 繼承 Mixin(在本例中是
PytorchModelHubMixin)。 - 在繼承時傳遞一個
coders引數。這是一個字典,其中鍵是您想要處理的自定義型別。值是一個元組(encoder, decoder)。- 編碼器接收指定型別的物件作為輸入,並返回一個可 JSON 的值。這將在使用
save_pretrained儲存模型時使用。 - 解碼器接收原始資料(通常是字典)作為輸入,並重建初始物件。這將在使用
from_pretrained載入模型時使用。
- 編碼器接收指定型別的物件作為輸入,並返回一個可 JSON 的值。這將在使用
- 為
__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 等預設生成。 |