Hub Python Library documentation
Tích hợp bất kỳ framework ML nào với Hub
Tích hợp bất kỳ framework ML nào với Hub
Hugging Face Hub giúp việc lưu trữ và chia sẻ mô hình với cộng đồng trở nên dễ dàng. Nền tảng hỗ trợ hàng chục thư viện trong hệ sinh thái Mã nguồn mở. Chúng tôi luôn nỗ lực mở rộng sự hỗ trợ này để thúc đẩy Machine Learning hợp tác phát triển. Thư viện huggingface_hub đóng vai trò then chốt trong quy trình này, cho phép bất kỳ script Python nào dễ dàng đẩy và tải tệp.
Có bốn cách chính để tích hợp một thư viện với Hub:
- Đẩy lên Hub: triển khai một phương thức để tải lên Hub một mô hình. Điều này bao gồm trọng số của mô hình, cũng như thẻ mô hình và bất kỳ thông tin hoặc dữ liệu liên quan nào khác cần thiết để chạy mô hình (ví dụ: nhật ký huấn luyện). Phương thức này thường được gọi là
push_to_hub(). - Tải từ Hub: triển khai một phương thức để nạp mô hình từ Hub. Phương thức này cần tải cấu hình/trọng số của mô hình và nạp mô hình. Phương thức này thường được gọi là
from_pretrainedhoặcload_from_hub(). - Widgets: hiển thị một widget trên trang đích của các model của bạn trên Hub. Nó cho phép người dùng nhanh chóng thử một model từ trình duyệt.
Trong hướng dẫn này, chúng ta sẽ tập trung vào hai chủ đề đầu tiên. Chúng tôi sẽ trình bày hai cách tiếp cận chính mà bạn có thể sử dụng để tích hợp một thư viện, cùng với những ưu điểm và nhược điểm của chúng. Mọi thứ được tóm tắt ở cuối hướng dẫn để giúp bạn lựa chọn giữa hai cách. Vui lòng lưu ý rằng đây chỉ là các nguyên tắc chung mà bạn có thể tự do điều chỉnh cho phù hợp với yêu cầu của mình.
Nếu bạn quan tâm đến Inference và Widgets, bạn có thể làm theo hướng dẫn này. Trong cả hai trường hợp, bạn có thể liên hệ với chúng tôi nếu bạn đang tích hợp một thư viện với Hub và muốn được liệt kê trong tài liệu của chúng tôi.
Một cách tiếp cận linh hoạt: các hàm trợ giúp
Cách tiếp cận đầu tiên để tích hợp một thư viện vào Hub là tự triển khai các phương thức push_to_hub và from_pretrained. Cách này cho bạn sự linh hoạt hoàn toàn về việc cần tải lên/tải xuống những tệp nào và cách xử lý các đầu vào đặc thù cho framework của bạn. Bạn có thể tham khảo hai hướng dẫn tải lên tệp và tải xuống tệp để tìm hiểu thêm về cách thực hiện. Ví dụ, tích hợp FastAI được triển khai theo cách này (xem push_to_hub_fastai() và from_pretrained_fastai()).
Cách triển khai có thể khác nhau giữa các thư viện, nhưng quy trình làm việc thường tương tự nhau.
from_pretrained
Đây là cách một phương thức from_pretrained thường trông như thế nào:
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
Phương thức push_to_hub thường đòi hỏi một chút phức tạp hơn để xử lý việc tạo kho, tạo thẻ mô hình và lưu trọng số.
Một cách tiếp cận phổ biến là lưu tất cả các tệp này vào một thư mục tạm thời, tải lên và sau đó xóa nó.
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)Tất nhiên, đây chỉ là một ví dụ. Nếu bạn quan tâm đến các thao tác phức tạp hơn (xóa tệp từ xa, tải trọng số lên trực tiếp, lưu trữ trọng số cục bộ, v.v.), vui lòng tham khảo hướng dẫn tải tệp lên.
Hạn chế
Mặc dù linh hoạt, cách tiếp cận này có một số nhược điểm, đặc biệt là về mặt bảo trì. Người dùng Hugging Face thường quen với các tính năng bổ sung khi làm việc với huggingface_hub. Ví dụ, khi tải tệp từ Hub, việc cung cấp các tham số như sau là phổ biến:
token: để tải xuống từ kho riêngrevision: để tải xuống từ một nhánh cụ thểcache_dir: để lưu các tệp vào một thư mục cụ thểforce_download/local_files_only: để tái sử dụng bộ nhớ đệm hay khôngproxies: cấu hình phiên HTTP
Khi đẩy các mô hình, các tham số tương tự được hỗ trợ:
commit_message: thông báo commit tùy chỉnhprivate: tạo kho riêng tư nếu chưa cócreate_pr: tạo một PR thay vì đẩy lênmainbranch: đẩy lên một nhánh thay vì nhánhmainallow_patterns/ignore_patterns: lọc các tệp cần tải lêntoken- …
Tất cả các tham số này có thể được thêm vào các cài đặt mà chúng ta đã xem ở trên và truyền vào các phương thức của huggingface_hub.
Tuy nhiên, nếu một tham số thay đổi hoặc một tính năng mới được thêm vào, bạn sẽ cần cập nhật gói của mình. Việc hỗ trợ những
tham số đó cũng đồng nghĩa với việc bạn phải duy trì thêm tài liệu. Để xem cách giảm thiểu những hạn chế này, hãy chuyển
sang phần tiếp theo của chúng ta kế thừa lớp.
Một cách tiếp cận phức tạp hơn: kế thừa lớp
Như đã thấy ở trên, có hai phương pháp chính cần đưa vào thư viện của bạn để tích hợp với Hub: tải tệp lên (push_to_hub) và tải tệp xuống (from_pretrained). Bạn có thể tự triển khai các phương pháp đó nhưng sẽ đi kèm với những lưu ý nhất định. Để giải quyết vấn đề này, huggingface_hub cung cấp một công cụ sử dụng kế thừa lớp. Hãy cùng xem cách nó hoạt động!
Trong nhiều trường hợp, một thư viện đã triển khai mô hình của nó bằng một lớp Python. Lớp này chứa các thuộc tính của mô hình và các phương thức để tải, chạy, huấn luyện và đánh giá nó. Cách tiếp cận của chúng tôi là mở rộng lớp này để bao gồm các tính năng tải lên và tải xuống bằng cách sử dụng mixins. Một Mixin là một lớp được thiết kế để mở rộng một lớp hiện có bằng một tập hợp các tính năng cụ thể thông qua kế thừa đa lớp. huggingface_hub cung cấp mixin riêng của nó, đó là ModelHubMixin. Điểm mấu chốt ở đây là hiểu hành vi của nó và cách tùy chỉnh nó.
Lớp ModelHubMixin triển khai 3 phương thức công khai (push_to_hub, save_pretrained và from_pretrained). Đây là các phương thức mà người dùng của bạn sẽ gọi để tải/lưu mô hình bằng thư viện của bạn. ModelHubMixin cũng định nghĩa 2 phương thức riêng tư (_save_pretrained và _from_pretrained). Đây là những phương thức mà bạn phải triển khai. Vì vậy, để tích hợp thư viện của bạn, bạn nên:
- Khai báo lớp Model của bạn kế thừa từ ModelHubMixin.
- Thực hiện các phương thức riêng tư:
- _save_pretrained(): phương thức nhận vào một đường dẫn đến thư mục và lưu mô hình vào đó. Bạn phải viết toàn bộ logic để xuất mô hình của mình trong phương thức này: model card, trọng số mô hình, tệp cấu hình, nhật ký huấn luyện và hình ảnh. Mọi thông tin liên quan đến mô hình này đều phải được xử lý bởi phương thức này. Model Cards đặc biệt quan trọng để mô tả mô hình của bạn. Xem hướng dẫn triển khai của chúng tôi để biết thêm chi tiết.
- _from_pretrained(): phương thức lớp nhận vào một
model_idvà trả về một mô hình đã được khởi tạo. Phương thức này phải tải xuống các tệp liên quan và nạp chúng.
- Bạn đã hoàn tất!
Ưu điểm của việc sử dụng ModelHubMixin là một khi bạn đã xử lý xong việc serialize/load các tệp, bạn đã sẵn sàng để bắt đầu. Bạn không cần phải lo lắng về những thứ như tạo repo, commits, PRs hay revisions. ModelHubMixin cũng đảm bảo các phương thức công khai được tài liệu hóa và chú thích kiểu, và bạn sẽ có thể xem số lượt tải xuống mô hình của mình trên Hub. Tất cả những điều này đều được xử lý bởi ModelHubMixin và có sẵn cho người dùng của bạn.
Một ví dụ cụ thể: PyTorch
Một ví dụ tốt cho những gì chúng ta đã xem ở trên là PyTorchModelHubMixin, tích hợp của chúng tôi cho framework PyTorch. Đây là một tích hợp sẵn sàng để sử dụng.
Cách sử dụng?
Dưới đây là cách bất kỳ người dùng nào có thể tải/lưu một mô hình PyTorch từ/vào 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"Thực hiện
Việc triển khai thực tế rất đơn giản, và bạn có thể tìm thấy mã nguồn đầy đủ tại đây.
- Đầu tiên, kế thừa lớp của bạn từ
ModelHubMixin:
from huggingface_hub import ModelHubMixin
class PyTorchModelHubMixin(ModelHubMixin):
(...)- Thực hiện phương thức
_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))
- Thực hiện phương thức
_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)Và như vậy là xong! Thư viện của bạn giờ đây cho phép người dùng tải lên và tải xuống tệp từ Hub.
Cách sử dụng nâng cao
Trong phần ở trên, chúng ta đã nhanh chóng thảo luận về cách ModelHubMixin hoạt động. Trong phần này, chúng ta sẽ xem xét một số tính năng nâng cao hơn của nó để cải thiện việc tích hợp thư viện của bạn với Hugging Face Hub.
Thẻ mô hình
ModelHubMixin tự động tạo model card cho bạn. Model card là các tệp đi kèm với mô hình, cung cấp thông tin quan trọng về chúng. Về cơ bản, model card là các tệp Markdown đơn giản kèm theo metadata bổ sung. Model card rất cần thiết cho khả năng tìm kiếm, tái lập và chia sẻ! Xem hướng dẫn về Model Cards để biết thêm chi tiết.
Việc tạo thẻ mô hình (model card) bán tự động là một cách tốt để đảm bảo rằng tất cả các mô hình được đẩy lên bằng thư viện của bạn sẽ chia sẻ chung các siêu dữ liệu: library_name, tags, license, pipeline_tag, v.v. Điều này giúp tất cả các mô hình do thư viện của bạn hỗ trợ dễ dàng được tìm kiếm trên Hub và cung cấp một số liên kết tài nguyên cho người dùng khi truy cập Hub. Bạn có thể định nghĩa trực tiếp siêu dữ liệu khi kế thừa từ 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"]
):
...Mặc định, một thẻ mô tả mô hình chung sẽ được tạo ra với thông tin bạn đã cung cấp (ví dụ: pyp1/VoiceCraft_giga830M). Tuy nhiên, bạn cũng có thể tự định nghĩa mẫu thẻ mô tả mô hình của riêng mình!
Trong ví dụ này, tất cả các model được đẩy lên bằng lớp VoiceCraft sẽ tự động bao gồm phần trích dẫn và chi tiết giấy phép. Để biết thêm chi tiết về cách định nghĩa mẫu model card, vui lòng xem hướng dẫn 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,
...
):
...Cuối cùng, nếu bạn muốn mở rộng quy trình tạo thẻ mô hình bằng các giá trị động, bạn có thể ghi đè phương thức 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 cardCấu hình
ModelHubMixin xử lý cấu hình mô hình cho bạn. Nó tự động kiểm tra các giá trị đầu vào khi bạn khởi tạo mô hình và xuất chúng ra tệp config.json. Điều này mang lại 2 lợi ích:
- Người dùng sẽ có thể tải lại mô hình với chính xác các tham số như bạn.
- Việc có tệp
config.jsonsẽ tự động bật tính năng phân tích trên Hub (tức là số lượng “downloads”).
Nhưng trên thực tế, nó hoạt động như thế nào? Một số quy tắc giúp quy trình diễn ra suôn sẻ nhất có thể từ góc nhìn của người dùng:
- nếu phương thức
__init__của bạn kỳ vọng một đầu vàoconfig, nó sẽ được tự động lưu trong repo dưới dạngconfig.json. - nếu tham số đầu vào
configđược chú thích với kiểu dataclass (ví dụconfig: Optional[MyConfigClass] = None), thì giá trịconfigsẽ được tách chuỗi hóa (deserialized) chính xác cho bạn. - tất cả các giá trị được truyền vào khi khởi tạo cũng sẽ được lưu trong tệp cấu hình. Điều này có nghĩa là bạn không nhất thiết phải mong đợi một đầu vào
configđể có thể tận dụng lợi ích từ nó.
Ví dụ:
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}Nhưng nếu một giá trị không thể được serialize thành JSON thì sao? Mặc định, giá trị đó sẽ bị bỏ qua khi lưu file cấu hình. Tuy nhiên, trong một số trường hợp, thư viện của bạn đã kỳ vọng một đối tượng tùy chỉnh làm đầu vào mà không thể serialize được, và bạn không muốn cập nhật logic nội bộ để thay đổi kiểu của nó. Đừng lo! Bạn có thể truyền các encoder/decoder tùy chỉnh cho bất kỳ kiểu nào khi kế thừa từ ModelHubMixin. Cách này đòi hỏi thêm một chút công sức nhưng đảm bảo logic nội bộ của bạn không bị thay đổi khi tích hợp thư viện của bạn với Hub.
Dưới đây là một ví dụ cụ thể trong đó một class kỳ vọng nhận cấu hình argparse.Namespace làm đầu vào:
class VoiceCraft(nn.Module):
def __init__(self, args):
self.pattern = self.args.pattern
self.hidden_size = self.args.hidden_size
...Một giải pháp có thể là cập nhật chữ ký __init__ thành def __init__(self, pattern: str, hidden_size: int) và cập nhật tất cả các đoạn mã khởi tạo lớp của bạn. Đây là một cách hoàn toàn hợp lệ để khắc phục nhưng có thể làm hỏng các ứng dụng hạ nguồn đang sử dụng thư viện của bạn.
Một giải pháp khác là cung cấp một bộ mã hóa/giải mã đơn giản để chuyển đổi argparse.Namespace sang một từ điển.
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
...Trong đoạn mã trên, cả logic bên trong và chữ ký __init__ của lớp đều không thay đổi. Điều này có nghĩa là tất cả các đoạn mã hiện có cho thư viện của bạn sẽ tiếp tục hoạt động. Để đạt được điều này, chúng tôi đã phải:
- Kế thừa từ mixin (
PytorchModelHubMixintrong trường hợp này). - Truyền tham số
coderstrong kế thừa. Đây là một từ điển mà các khóa là các kiểu dữ liệu tùy chỉnh bạn muốn xử lý. Các giá trị là một bộ(encoder, decoder).- Bộ mã hóa (encoder) kỳ vọng nhận một đối tượng có kiểu được chỉ định làm đầu vào và trả về một giá trị có thể chuyển đổi sang JSON. Giá trị này sẽ được sử dụng khi lưu mô hình bằng
save_pretrained. - Bộ giải mã (decoder) kỳ vọng dữ liệu thô (thường là một từ điển) làm đầu vào và tái tạo đối tượng ban đầu. Điều này sẽ được sử dụng khi tải mô hình bằng
from_pretrained.
- Bộ mã hóa (encoder) kỳ vọng nhận một đối tượng có kiểu được chỉ định làm đầu vào và trả về một giá trị có thể chuyển đổi sang JSON. Giá trị này sẽ được sử dụng khi lưu mô hình bằng
- Thêm chú thích kiểu cho chữ ký
__init__. Điều này quan trọng để mixin biết kiểu nào được mong đợi bởi lớp và do đó, bộ giải mã nào cần được sử dụng.
Vì mục đích đơn giản hóa, các hàm encoder/decoder trong ví dụ trên không có độ bền cao. Đối với một triển khai cụ thể, bạn rất có thể phải xử lý đúng các trường hợp biên.
So sánh nhanh
Hãy nhanh chóng tóm tắt hai cách tiếp cận mà chúng ta đã xem xét cùng với những ưu điểm và nhược điểm của chúng. Bảng dưới đây chỉ mang tính tham khảo. Khung làm việc của bạn có thể có một số đặc thù riêng mà bạn cần xử lý. Hướng dẫn này chỉ nhằm cung cấp các nguyên tắc và ý tưởng về cách xử lý tích hợp. Trong mọi trường hợp, đừng ngần ngại liên hệ với chúng tôi nếu bạn có bất kỳ câu hỏi nào!
| Tích hợp | Sử dụng các hàm trợ giúp | Sử dụng ModelHubMixin |
|---|---|---|
| Trải nghiệm người dùng | model = load_from_hub(...)push_to_hub(model, ...) | model = MyModel.from_pretrained(...)model.push_to_hub(...) |
| Tính linh hoạt | Rất linh hoạt. Bạn hoàn toàn kiểm soát việc triển khai. | Ít linh hoạt hơn. Khung của bạn phải có một lớp mô hình. |
| Bảo trì | Nhiều công việc bảo trì hơn để thêm hỗ trợ cho cấu hình và các tính năng mới. Có thể cũng cần khắc phục các vấn đề do người dùng báo cáo. | Ít phải bảo trì hơn vì hầu hết các tương tác với Hub đều được triển khai trong huggingface_hub. |
| Tài liệu / Ghi chú kiểu | Chưa được viết thủ công. | Được xử lý một phần bởi huggingface_hub. |
| Bộ đếm lượt tải xuống | Cần được xử lý thủ công. | Bật mặc định nếu class có thuộc tính config. |
| Thẻ mô hình | Cần được xử lý thủ công | Được tạo mặc định với library_name, tags, v.v. |