Hub Python Library documentation

Tải tệp lên Hub

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Tải tệp lên Hub

Việc chia sẻ tệp và công việc của bạn là một khía cạnh quan trọng của Hub. Thư viện huggingface_hub cung cấp một số tùy chọn để tải tệp của bạn lên Hub. Bạn có thể sử dụng các hàm này một cách độc lập hoặc tích hợp chúng vào thư viện của mình, giúp người dùng tương tác với Hub thuận tiện hơn.

Mỗi khi bạn muốn tải tệp lên Hub, bạn cần đăng nhập vào tài khoản Hugging Face của mình. Để biết thêm chi tiết về xác thực, hãy xem mục này.

Tải lên một tệp

Sau khi bạn đã tạo một kho lưu trữ bằng create_repo(), bạn có thể tải lên một tệp vào kho lưu trữ của mình bằng upload_file().

Chỉ định đường dẫn của tệp cần tải lên, vị trí trong kho mà bạn muốn tải tệp lên, và tên của kho mà bạn muốn thêm tệp vào. Tùy thuộc vào loại kho của bạn, bạn có thể tùy chọn đặt loại kho là dataset, model hoặc space.

>>> from huggingface_hub import HfApi
>>> api = HfApi()
>>> api.upload_file(
...     path_or_fileobj="/path/to/local/folder/README.md",
...     path_in_repo="README.md",
...     repo_id="username/test-dataset",
...     repo_type="dataset",
... )

Tải lên một thư mục

Sử dụng hàm upload_folder() để tải lên một thư mục cục bộ vào một kho lưu trữ hiện có. Chỉ định đường dẫn của thư mục cục bộ cần tải lên, vị trí trong kho lưu trữ mà bạn muốn tải thư mục lên, và tên của kho lưu trữ mà bạn muốn thêm thư mục vào. Tùy thuộc vào loại kho lưu trữ của bạn, bạn có thể tùy chọn đặt loại kho lưu trữ là dataset, model, hoặc space.

>>> from huggingface_hub import HfApi
>>> api = HfApi()

# Upload all the content from the local folder to your remote Space.
# By default, files are uploaded at the root of the repo
>>> api.upload_folder(
...     folder_path="/path/to/local/space",
...     repo_id="username/my-cool-space",
...     repo_type="space",
... )

Mặc định, tệp .gitignore sẽ được xem xét để xác định tệp nào nên được commit hay không. Mặc định, chúng tôi kiểm tra xem có tệp .gitignore trong một commit hay không, và nếu không, chúng tôi kiểm tra xem nó có tồn tại trên Hub hay không. Vui lòng lưu ý rằng chỉ tệp .gitignore nằm ở gốc thư mục mới được sử dụng. Chúng tôi không kiểm tra các tệp .gitignore trong các thư mục con.

Nếu bạn không muốn sử dụng tệp .gitignore được hardcode, bạn có thể sử dụng các đối số allow_patterns và ignore_patterns để lọc các tệp cần tải lên. Các tham số này chấp nhận một pattern duy nhất hoặc một danh sách các pattern. Các pattern là Standard Wildcards (globbing patterns) như được tài liệu hóa tại đây. Nếu cả allow_patterns và ignore_patterns đều được cung cấp, cả hai ràng buộc đều được áp dụng.

Bên cạnh tệp .gitignore và các mẫu cho phép/bỏ qua, bất kỳ thư mục .git/ nào có mặt trong bất kỳ thư mục con nào cũng sẽ bị bỏ qua.

>>> api.upload_folder(
...     folder_path="/path/to/local/folder",
...     path_in_repo="my-dataset/train", # Upload to a specific folder
...     repo_id="username/test-dataset",
...     repo_type="dataset",
...     ignore_patterns="**/logs/*.txt", # Ignore all text logs
... )

Bạn cũng có thể sử dụng đối số delete_patterns để chỉ định các tệp bạn muốn xóa khỏi kho trong cùng một commit. Điều này có thể hữu ích nếu bạn muốn dọn dẹp một thư mục từ xa trước khi đẩy tệp vào đó và bạn không biết tệp nào đã tồn tại.

Ví dụ bên dưới tải thư mục ./logs cục bộ lên thư mục /experiment/logs/ từ xa. Chỉ các tệp txt được tải lên nhưng trước đó, tất cả các log trước đó trên repo sẽ bị xóa. Tất cả những điều này được thực hiện trong một commit duy nhất.

>>> api.upload_folder(
...     folder_path="/path/to/local/folder/logs",
...     repo_id="username/trained-model",
...     path_in_repo="experiment/logs/",
...     allow_patterns="*.txt", # Upload all local text files
...     delete_patterns="*.txt", # Delete all remote text files before
... )

Cách các tệp được tải lên

Khi hf_xet được cài đặt (đây là mặc định), upload_folder() tải tệp lên thông qua một pipeline dạng stream: các tệp được kiểm tra đối chiếu với Hub, tải lên backend lưu trữ Xet (nơi thực hiện chia chunk, khử trùng lặp và tự động thử lại việc truyền tải bên trong), và được commit theo các lô thích ứng, tất cả đều chạy song song. Trên thực tế, điều này có nghĩa là:

  • Các thư mục có kích thước bất kỳ: các thư mục nhỏ được tải lên trong một commit duy nhất, trong khi các thư mục chứa nhiều tệp sẽ được tự động chia thành nhiều commit để không vượt quá giới hạn của máy chủ. Khi điều này xảy ra, các commit tiếp theo sẽ có hậu tố (part 2), (part 3), … trong thông điệp commit.
  • Khả năng tiếp tục: nếu quá trình tải lên bị gián đoạn vì bất kỳ lý do nào, chỉ cần chạy lại cùng một lệnh gọi. Các tệp đã được cam kết sẽ được phát hiện và bỏ qua, còn các khối đã tải lên sẽ được khử trùng lặp — việc tải lại chúng hầu như không truyền dữ liệu. Không có trạng thái cục bộ nào được liên quan: bạn thậm chí có thể tiếp tục từ một máy khác. Một ngoại lệ: với create_pr=True, việc chạy lại sẽ mở một pull request mới. Chúng tôi khuyến nghị chạy lại với revision="refs/pr/N" thay vào đó khi tiếp tục tải lên.
  • Không đọc hai lần: các tệp được băm trong khi được chia nhỏ để tải lên, chỉ trong một lần đọc duy nhất. Không có giai đoạn “băm” riêng biệt trước khi quá trình tải lên bắt đầu.

Màn hình hiển thị tiến trình trực tiếp theo dõi ba giai đoạn:

Found 5,000 files to upload
  Preparing   ████████████████████  5,000 / 5,000 ✓
  Uploading   ██████████████░░░░░░  423 / 603 files  3.8GB · 19.7MB/s
  Committing  ██████████████████░░  4,580 / 5,000  6 commits

Nếu hf_xet chưa được cài đặt, upload_folder() sẽ quay lại hành vi cũ: băm tất cả trước, tải lên qua HTTP, sau đó tạo một commit duy nhất. Chúng tôi luôn khuyến nghị giữ hf_xet được cài đặt để có độ bền vững tốt hơn

Tải lên từ CLI

Bạn có thể sử dụng lệnh hf upload từ terminal để tải trực tiếp các tệp lên Hub. Bên trong, lệnh này sử dụng các hàm trợ giúp upload_file() và upload_folder() đã được mô tả ở trên.

Bạn có thể tải lên một tệp duy nhất hoặc một thư mục hoàn chỉnh:

# Usage:  hf upload [repo_id] [local_path] [path_in_repo]
>>> hf upload Wauplin/my-cool-model ./models/model.safetensors model.safetensors
https://huggingface.co/Wauplin/my-cool-model/blob/main/model.safetensors

>>> hf upload Wauplin/my-cool-model ./models .
https://huggingface.co/Wauplin/my-cool-model/tree/main

local_path và path_in_repo là tùy chọn và có thể được suy luận ngầm. Nếu local_path không được đặt, công cụ sẽ kiểm tra xem có thư mục hoặc tệp cục bộ nào có cùng tên với repo_id không. Nếu đúng, nội dung của nó sẽ được tải lên. Ngược lại, một ngoại lệ sẽ được ném ra, yêu cầu người dùng đặt rõ local_path. Trong mọi trường hợp, nếu path_in_repo không được đặt, các tệp sẽ được tải lên ở gốc của repo.

Đích đến cũng có thể được biểu diễn dưới dạng một URI hf:// duy nhất theo ngữ pháp hf://[<TYPE>/]<ID>[@<REVISION>][/<PATH>] (xem tham chiếu HF URIs để biết cú pháp đầy đủ). Loại repo, revision và path_in_repo sau đó sẽ được đọc từ URI, và không thể kết hợp với các tùy chọn --repo-type và --revision:

# Upload a single file to a dataset on a specific branch
>>> hf upload hf://datasets/Wauplin/my-cool-dataset@my-branch/data/train.csv ./train.csv
https://huggingface.co/datasets/Wauplin/my-cool-dataset/blob/my-branch/data/train.csv

Để đạt thông lượng tải lên tối đa cho các tệp lớn, hãy đặt biến môi trường HF_XET_HIGH_PERFORMANCE=1. Thao tác này kích hoạt chế độ hiệu năng cao của hf_xet, giúp bão hòa băng thông và các lõi CPU khả dụng. Lưu ý: cờ cũ HF_HUB_ENABLE_HF_TRANSFER=1 không còn được sử dụng vì hf_transfer đã bị loại bỏ để thay thế bằng hf_xet — hãy đặt HF_XET_HIGH_PERFORMANCE=1 thay vào đó.

Để biết thêm chi tiết về lệnh tải lên CLI, vui lòng tham khảo hướng dẫn CLI.

Tải lên một thư mục lớn

upload_folder() và lệnh hf upload là các giải pháp hàng đầu để tải tệp lên Hub, kể cả với các thư mục rất lớn. Các tệp được truyền trực tiếp lên Hub qua nhiều lần commit và quá trình sẽ tự động tiếp tục nếu bị gián đoạn. Chỉ cần chạy lại cùng một lệnh và các tệp đã được tải lên sẽ được bỏ qua.

>>> api.upload_folder(
...     repo_id="HuggingFaceM4/Docmatix",
...     repo_type="dataset",
...     folder_path="/path/to/local/docmatix",
... )

hoặc từ terminal:

hf upload HuggingFaceM4/Docmatix --repo-type=dataset /path/to/local/docmatix

Mẹo và thủ thuật cho các lần tải lên lớn

Có một số hạn chế cần lưu ý khi làm việc với một lượng lớn dữ liệu trong repo của bạn. Do thời gian cần thiết để stream dữ liệu, việc upload/push thất bại ở cuối quy trình hoặc trải nghiệm bị giảm chất lượng, dù là trên hf.co hay khi làm việc cục bộ, có thể gây rất nhiều phiền toái.

Xem hướng dẫn Hạn chế và khuyến nghị về kho lưu trữ của chúng tôi để biết các thực hành tốt nhất về cách tổ chức kho lưu trữ trên Hub. Hãy tiếp tục với một số mẹo thực tế để quá trình tải lên của bạn diễn ra suôn sẻ nhất có thể.

  • Bắt đầu từ nhỏ: Chúng tôi khuyên bạn nên bắt đầu với một lượng dữ liệu nhỏ để kiểm tra script tải lên của mình. Việc lặp lại và điều chỉnh script sẽ dễ dàng hơn khi mỗi lần thất bại chỉ mất một ít thời gian.
  • Chấp nhận sự cố: Việc stream một lượng lớn dữ liệu là đầy thách thức. Bạn không thể biết trước điều gì sẽ xảy ra, nhưng luôn nên giả định rằng sẽ có ít nhất một sự cố xảy ra - dù nguyên nhân đến từ máy của bạn, kết nối, hay máy chủ của chúng tôi. Ví dụ, nếu bạn dự định tải lên một số lượng lớn tệp, tốt nhất nên theo dõi cục bộ những tệp đã được tải lên trước khi tải lên lô tiếp theo. Bạn được đảm bảo rằng một tệp LFS đã được commit sẽ không bao giờ bị tải lên hai lần, nhưng việc kiểm tra phía client vẫn có thể tiết kiệm được một ít thời gian. Đây chính là điều mà upload_folder() thực hiện cho bạn.
  • Sử dụng hf_xet: công cụ này tận dụng backend lưu trữ mới của Hub, được viết bằng Rust và hiện đã có sẵn cho mọi người sử dụng. Thực tế, hf_xet đã được bật mặc định khi sử dụng huggingface_hub! Để đạt hiệu suất tối đa, hãy đặt HF_XET_HIGH_PERFORMANCE=1 dưới dạng biến môi trường. Lưu ý rằng khi chế độ hiệu suất cao được bật, công cụ sẽ cố gắng sử dụng toàn bộ băng thông và lõi CPU khả dụng.

Tính năng nâng cao

Trong hầu hết các trường hợp, bạn sẽ không cần gì ngoài upload_file() và upload_folder() để tải tệp của bạn lên Hub. Tuy nhiên, huggingface_hub có các tính năng nâng cao hơn để việc này trở nên dễ dàng hơn. Hãy cùng xem qua chúng!

Tải lên nhanh hơn

Tận dụng tốc độ tải lên nhanh hơn thông qua hf_xet, bản liên kết Python của thư viện xet-core cho phép khử trùng lặp dựa trên chunk để tải lên và tải xuống nhanh hơn. hf_xet tích hợp liền mạch với huggingface_hub, nhưng sử dụng thư viện Rust xet-core và bộ nhớ Xet thay vì LFS.

hf_xet sử dụng hệ thống lưu trữ Xet, hệ thống này chia nhỏ các tệp thành các khối (chunks) bất biến, lưu trữ các tập hợp của những khối này (gọi là blocks hoặc xorbs) trên xa và truy xuất chúng để lắp ráp lại tệp khi có yêu cầu. Khi tải lên, sau khi xác nhận người dùng được ủy quyền ghi vào kho này, hf_xet sẽ quét các tệp, chia chúng thành các khối và gom các khối đó vào các xorb (đồng thời khử trùng lặp giữa các khối đã biết), sau đó sẽ tải các xorb này lên dịch vụ định danh theo nội dung (CAS) của Xet, nơi sẽ xác minh tính toàn vẹn của các xorb, đăng ký metadata của xorb cùng với hash SHA256 của LFS (để hỗ trợ tra cứu/tải xuống), và ghi các xorb vào bộ nhớ lưu trữ từ xa.

Để bật tính năng này, chỉ cần cài đặt phiên bản mới nhất của huggingface_hub:

pip install -U "huggingface_hub"

Bắt đầu từ huggingface_hub 0.32.0, điều này cũng sẽ cài đặt hf_xet.

Tất cả các API khác của huggingface_hub sẽ tiếp tục hoạt động mà không cần bất kỳ thay đổi nào. Để tìm hiểu thêm về các lợi ích của lưu trữ Xet và hf_xet, hãy tham khảo phần này.

Các cân nhắc khi tải lên hệ thống tệp phân tán / cụm

Khi tải lên từ một cụm, các tệp được tải lên thường nằm trên hệ thống tệp phân tán hoặc mạng (NFS, EBS, Lustre, Fsx, v.v.). Xet storage sẽ chia các tệp đó thành các khối (còn gọi là xorbs) và ghi chúng cục bộ, sau đó tải lên khi khối hoàn tất. Để có hiệu suất tốt hơn khi tải lên từ hệ thống tệp phân tán, hãy đảm bảo đặt HF_XET_CACHE thành một thư mục nằm trên ổ đĩa cục bộ (ví dụ: ổ NVMe hoặc SSD cục bộ). Vị trí mặc định cho bộ nhớ đệm Xet nằm dưới HF_HOME tại (~/.cache/huggingface/xet) và việc thư mục này nằm trong thư mục home của người dùng thường cũng nằm trên hệ thống tệp phân tán.

Tải lên không chặn

Trong một số trường hợp, bạn muốn đẩy dữ liệu mà không chặn luồng chính. Điều này đặc biệt hữu ích để tải lên nhật ký và các sản phẩm (artifacts) trong khi vẫn tiếp tục quá trình huấn luyện. Để làm điều này, bạn có thể sử dụng đối số run_as_future trong cả upload_file() và upload_folder(). Thao tác này sẽ trả về một đối tượng concurrent.futures.Future mà bạn có thể dùng để kiểm tra trạng thái của việc tải lên.

>>> from huggingface_hub import HfApi
>>> api = HfApi()
>>> future = api.upload_folder( # Upload in the background (non-blocking action)
...     repo_id="username/my-model",
...     folder_path="checkpoints-001",
...     run_as_future=True,
... )
>>> future
Future(...)
>>> future.done()
False
>>> future.result() # Wait for the upload to complete (blocking action)
...

Các tác vụ nền được đưa vào hàng đợi khi sử dụng run_as_future=True. Điều này có nghĩa là bạn được đảm bảo rằng các tác vụ sẽ được thực thi theo đúng thứ tự.

Mặc dù các tác vụ nền chủ yếu hữu ích để tải lên dữ liệu/tạo các commit, bạn có thể xếp hàng bất kỳ phương thức nào bạn muốn bằng cách sử dụng run_as_future(). Ví dụ, bạn có thể dùng nó để tạo một repo và sau đó tải dữ liệu lên repo đó ở chế độ nền. Tham số run_as_future tích hợp sẵn trong các phương thức tải lên chỉ là một alias bao quanh nó.

>>> from huggingface_hub import HfApi
>>> api = HfApi()
>>> api.run_as_future(api.create_repo, "username/my-model", exists_ok=True)
Future(...)
>>> api.upload_file(
...     repo_id="username/my-model",
...     path_in_repo="file.txt",
...     path_or_fileobj=b"file content",
...     run_as_future=True,
... )
Future(...)

Sao chép tệp giữa các kho

Sử dụng copy_files() để sao chép các tệp hoặc thư mục giữa các kho trên Hub mà không cần tải xuống hoặc tải lên lại dữ liệu lớn. Điều này hữu ích khi bạn muốn nhân bản trọng số giữa các biến thể mô hình, sao chép tệp dữ liệu giữa các kho, hoặc sắp xếp lại tệp giữa các kho của bạn. Bên trong, nó tạo một commit với các thao tác CommitOperationCopy.

>>> from huggingface_hub import HfApi
>>> api = HfApi()

# Copy a single file between repos
>>> api.copy_files(
...     "hf://username/source-model/weights.safetensors",
...     "hf://username/target-model/weights.safetensors",
... )

# Copy an entire folder
>>> api.copy_files(
...     "hf://datasets/username/source-dataset/data/",
...     "hf://datasets/username/target-dataset/data/",
... )

Bạn cũng có thể sao chép trong cùng một kho lưu trữ:

# Duplicate a file in the same repo
>>> api.copy_files(
...     "hf://username/my-model/config.json",
...     "hf://username/my-model/backup/config.json",
... )

Khi sao chép một thư mục, ký tự / ở cuối nguồn sử dụng ngữ nghĩa kiểu rsync, có nghĩa là nội dung của thư mục được sao chép, không lồng ghép chính thư mục đó. Nếu không có ký tự / ở cuối, chính thư mục sẽ được lồng ghép tại đích.

copy_files() cũng hỗ trợ sao chép tệp vào Buckets. Xem hướng dẫn về Buckets để biết thêm chi tiết.

Tải lên theo lịch

Hugging Face Hub giúp việc lưu trữ và quản lý phiên bản dữ liệu trở nên dễ dàng. Tuy nhiên, có một số hạn chế khi cập nhật cùng một tệp hàng nghìn lần. Ví dụ, bạn có thể muốn lưu nhật ký của một quá trình huấn luyện hoặc phản hồi của người dùng trên một Space đã triển khai. Trong những trường hợp này, việc tải dữ liệu lên Hub dưới dạng một dataset là hợp lý, nhưng có thể khó thực hiện đúng cách. Lý do chính là bạn không muốn tạo phiên bản cho mỗi lần cập nhật dữ liệu vì điều đó sẽ khiến kho git trở nên không thể sử dụng được. Lớp CommitScheduler cung cấp một giải pháp cho vấn đề này.

Ý tưởng là chạy một tác vụ nền thường xuyên đẩy một thư mục cục bộ lên Hub. Giả sử bạn có một Gradio Space nhận một số văn bản làm đầu vào và tạo ra hai bản dịch của nó. Sau đó, người dùng có thể chọn bản dịch họ thích. Với mỗi lần chạy, bạn muốn lưu đầu vào, đầu ra và sự lựa chọn của người dùng để phân tích kết quả. Đây là một trường hợp sử dụng hoàn hảo cho CommitScheduler; bạn muốn lưu dữ liệu lên Hub (có thể là hàng triệu phản hồi từ người dùng), nhưng bạn không cần phải lưu đầu vào của từng người dùng theo thời gian thực. Thay vào đó, bạn có thể lưu dữ liệu cục bộ trong một tệp JSON và tải lên mỗi 10 phút. Ví dụ:

>>> import json
>>> import uuid
>>> from pathlib import Path
>>> import gradio as gr
>>> from huggingface_hub import CommitScheduler

# Define the file where to save the data. Use UUID to make sure not to overwrite existing data from a previous run.
>>> feedback_file = Path("user_feedback/") / f"data_{uuid.uuid4()}.json"
>>> feedback_folder = feedback_file.parent

# Schedule regular uploads. Remote repo and local folder are created if they don't already exist.
>>> scheduler = CommitScheduler(
...     repo_id="report-translation-feedback",
...     repo_type="dataset",
...     folder_path=feedback_folder,
...     path_in_repo="data",
...     every=10,
... )

# Define the function that will be called when the user submits its feedback (to be called in Gradio)
>>> def save_feedback(input_text:str, output_1: str, output_2:str, user_choice: int) -> None:
...     """
...     Append input/outputs and user feedback to a JSON Lines file using a thread lock to avoid concurrent writes from different users.
...     """
...     with scheduler.lock:
...         with feedback_file.open("a") as f:
...             f.write(json.dumps({"input": input_text, "output_1": output_1, "output_2": output_2, "user_choice": user_choice}))
...             f.write("\n")

# Start Gradio
>>> with gr.Blocks() as demo:
>>>     ... # define Gradio demo + use `save_feedback`
>>> demo.launch()

Và như vậy là xong! Đầu vào/đầu ra của người dùng và phản hồi sẽ có sẵn dưới dạng một dataset trên Hub. Bằng cách sử dụng tên tệp JSON duy nhất, bạn được đảm bảo sẽ không ghi đè lên dữ liệu từ một lần chạy trước đó hoặc dữ liệu từ các Spaces/replicas khác đang đẩy đồng thời vào cùng một repository.

Để biết thêm chi tiết về CommitScheduler, đây là những gì bạn cần biết:

  • chỉ thêm (append-only): Giả định rằng bạn chỉ thêm nội dung vào thư mục. Bạn chỉ được phép thêm dữ liệu vào các tệp hiện có hoặc tạo tệp mới. Xóa hoặc ghi đè lên một tệp có thể làm hỏng kho lưu trữ của bạn.
  • git history: Trình lập lịch sẽ commit thư mục mỗi every phút. Để tránh làm ô nhiễm kho git quá nhiều, nên đặt giá trị tối thiểu là 5 phút. Ngoài ra, trình lập lịch được thiết kế để tránh các commit rỗng. Nếu không phát hiện nội dung mới trong thư mục, commit được lên lịch sẽ bị bỏ qua.
  • errors: Trình điều phối chạy dưới dạng luồng nền. Nó được khởi động khi bạn khởi tạo lớp và chạy cho đến khi stop() được gọi hoặc tiến trình thoát. Nếu xảy ra lỗi trong quá trình tải lên (ví dụ: sự cố kết nối), lỗi sẽ được ghi log và trình điều phối sẽ thử lại ở lần commit được lên lịch tiếp theo.
  • scripts: Trong một script có vòng đời hữu hạn (ví dụ: huấn luyện), hãy dùng scheduler như một context manager. Khi thoát khỏi khối with, hệ thống sẽ thực hiện lần upload cuối cùng, chờ nó hoàn tất và dừng scheduler.
  • an toàn luồng: Trong hầu hết các trường hợp, bạn có thể an tâm ghi vào tệp mà không cần lo lắng về tệp khóa. Trình lập lịch sẽ không bị sập hoặc hỏng nếu bạn ghi nội dung vào thư mục trong khi nó đang tải lên. Trên thực tế, có thể xảy ra các vấn đề về đồng thời đối với các ứng dụng có tải nặng. Trong trường hợp này, chúng tôi khuyên bạn nên sử dụng khóa scheduler.lock để đảm bảo an toàn luồng. Khóa chỉ bị chặn khi trình lập lịch quét thư mục để tìm các thay đổi, chứ không phải khi nó tải dữ liệu lên. Bạn có thể an tâm rằng điều này sẽ không ảnh hưởng đến trải nghiệm người dùng trên Space của bạn.

Demo về tính năng lưu trữ không gian

Việc lưu trữ dữ liệu từ một Space sang một Dataset trên Hub là trường hợp sử dụng chính của CommitScheduler. Tùy thuộc vào trường hợp sử dụng, bạn có thể muốn cấu trúc dữ liệu của mình theo những cách khác nhau. Cấu trúc phải đủ vững chắc để xử lý người dùng đồng thời và các lần khởi động lại, điều này thường đồng nghĩa với việc tạo ra các UUID. Ngoài độ vững chắc, bạn nên tải lên dữ liệu ở định dạng có thể đọc được bởi thư viện 🤗 Datasets để tái sử dụng sau này. Chúng tôi đã tạo một Space minh họa cách lưu trữ nhiều định dạng dữ liệu khác nhau (bạn có thể cần điều chỉnh nó cho phù hợp với nhu cầu cụ thể của mình).

Tải lên tùy chỉnh

CommitScheduler giả định dữ liệu của bạn chỉ được thêm vào (append-only) và nên được tải lên “nguyên trạng”. Tuy nhiên, bạn có thể muốn tùy chỉnh cách dữ liệu được tải lên. Bạn có thể làm điều đó bằng cách tạo một class kế thừa từ CommitScheduler và ghi đè phương thức push_to_hub (bạn có thể ghi đè theo bất kỳ cách nào bạn muốn). Bạn được đảm bảo rằng phương thức này sẽ được gọi mỗi every phút trong một thread nền. Bạn không cần lo lắng về sự đồng thời và lỗi, nhưng bạn phải cẩn thận với các khía cạnh khác, chẳng hạn như đẩy các commit rỗng hoặc dữ liệu trùng lặp.

Trong ví dụ (đơn giản hóa) bên dưới, chúng ta ghi đè push_to_hub để nén tất cả các tệp PNG vào một tệp lưu trữ duy nhất nhằm tránh quá tải kho trên Hub:

class ZipScheduler(CommitScheduler):
    def push_to_hub(self):
        # 1. List PNG files
        png_files = list(self.folder_path.glob("*.png"))
        if len(png_files) == 0:
            return None  # return early if nothing to commit

        # 2. Zip png files in a single archive
        with tempfile.TemporaryDirectory() as tmpdir:
            archive_path = Path(tmpdir) / "train.zip"
            with zipfile.ZipFile(archive_path, "w", zipfile.ZIP_DEFLATED) as zip:
                for png_file in png_files:
                    zip.write(filename=png_file, arcname=png_file.name)

            # 3. Upload archive
            self.api.upload_file(..., path_or_fileobj=archive_path)

        # 4. Delete local png files to avoid re-uploading them later
        for png_file in png_files:
            png_file.unlink()

Khi bạn ghi đè push_to_hub, bạn có quyền truy cập vào các thuộc tính của CommitScheduler và đặc biệt là:

  • client HfApi: api
  • Tham số thư mục: folder_path và path_in_repo
  • Tham số kho: repo_id, repo_type, revision
  • Khóa luồng: lock

Để xem thêm các ví dụ về trình lập lịch tùy chỉnh, hãy xem không gian demo của chúng tôi, bao gồm các cài đặt khác nhau tùy thuộc vào trường hợp sử dụng của bạn.

create_commit

Các hàm upload_file() và upload_folder() là các API cấp cao, thường rất tiện lợi khi sử dụng. Chúng tôi khuyên bạn nên thử các hàm này trước nếu bạn không cần làm việc ở cấp độ thấp hơn. Tuy nhiên, nếu bạn muốn làm việc ở cấp độ commit, bạn có thể sử dụng trực tiếp hàm create_commit().

Có ba loại thao tác được hỗ trợ bởi create_commit():

  • CommitOperationAdd tải một tệp lên Hub. Nếu tệp đã tồn tại, nội dung tệp sẽ bị ghi đè. Thao tác này nhận hai đối số:

    • path_in_repo: đường dẫn trong kho để tải tệp lên.
    • path_or_fileobj: đường dẫn đến một tệp trên hệ thống tệp của bạn hoặc một đối tượng dạng tệp. Đây là nội dung của tệp cần tải lên Hub.
  • CommitOperationDelete xóa một tệp hoặc thư mục khỏi kho. Thao tác này nhận path_in_repo làm đối số.

  • CommitOperationCopy sao chép một tệp trong cùng một kho hoặc giữa các kho. Thao tác này nhận các đối số sau:

    • src_path_in_repo: đường dẫn kho của tệp cần sao chép.
    • path_in_repo: đường dẫn trong kho nơi tệp sẽ được sao chép.
    • src_revision: tùy chọn - phiên bản của tệp cần sao chép nếu bạn muốn sao chép tệp từ một nhánh/phiên bản khác.
    • src_repo_id: tùy chọn - kho nguồn để sao chép (ví dụ: "username/source-model"). Mặc định là kho đích.
    • src_repo_type: tùy chọn - loại của kho lưu trữ nguồn ("model", "dataset" hoặc "space"). Bắt buộc khi src_repo_id được đặt.

Ví dụ, nếu bạn muốn tải lên hai tệp và xóa một tệp trong kho Hub:

  1. Sử dụng CommitOperation phù hợp để thêm hoặc xóa một tệp và để xóa một thư mục:
>>> from huggingface_hub import HfApi, CommitOperationAdd, CommitOperationDelete
>>> api = HfApi()
>>> operations = [
...     CommitOperationAdd(path_in_repo="LICENSE.md", path_or_fileobj="~/repo/LICENSE.md"),
...     CommitOperationAdd(path_in_repo="weights.h5", path_or_fileobj="~/repo/weights-final.h5"),
...     CommitOperationDelete(path_in_repo="old-weights.h5"),
...     CommitOperationDelete(path_in_repo="logs/"),
...     CommitOperationCopy(src_path_in_repo="image.png", path_in_repo="duplicate_image.png"),
... ]
  1. Truyền các thao tác của bạn vào create_commit():
>>> api.create_commit(
...     repo_id="lysandre/test-model",
...     operations=operations,
...     commit_message="Upload my model weights and license",
... )

Ngoài upload_file() và upload_folder(), các hàm sau đây cũng sử dụng create_commit() bên trong:

Để biết thêm thông tin chi tiết, hãy xem tài liệu tham khảo HfApi.

Tải trước các tệp LFS trước khi commit

Trong một số trường hợp, bạn có thể muốn tải các tệp lớn lên S3 trước khi thực hiện lệnh gọi commit. Ví dụ, nếu bạn đang commit một dataset gồm nhiều shard được tạo trong bộ nhớ, bạn sẽ cần tải từng shard lên một cách tuần tự để tránh vấn đề hết bộ nhớ. Một giải pháp là tải mỗi shard lên như một commit riêng biệt trên repo. Mặc dù hoàn toàn hợp lệ, giải pháp này có nhược điểm là có thể làm rối lịch sử git do tạo ra hàng chục commit. Để khắc phục vấn đề này, bạn có thể tải các tệp lên S3 một cách tuần tự và sau đó tạo một commit duy nhất ở cuối. Điều này có thể thực hiện bằng cách kết hợp preupload_lfs_files() với create_commit().

Đây là phương pháp dành cho người dùng nâng cao. Trong phần lớn các trường hợp, cách tiếp cận đúng là sử dụng trực tiếp upload_file(), upload_folder() hoặc create_commit() thay vì xử lý logic cấp thấp của việc tải trước tệp. Lưu ý chính của preupload_lfs_files() là cho đến khi commit thực sự được tạo, các tệp đã tải lên sẽ không thể truy cập được trên kho ở Hub. Nếu bạn có câu hỏi, hãy liên hệ với chúng tôi qua Discord hoặc trong một issue trên GitHub.

Dưới đây là một ví dụ đơn giản minh họa cách tải trước các tệp:

>>> from huggingface_hub import CommitOperationAdd, preupload_lfs_files, create_commit, create_repo

>>> repo_id = create_repo("test_preupload").repo_id

>>> operations = [] # List of all `CommitOperationAdd` objects that will be generated
>>> for i in range(5):
...     content = ... # generate binary content
...     addition = CommitOperationAdd(path_in_repo=f"shard_{i}_of_5.bin", path_or_fileobj=content)
...     preupload_lfs_files(repo_id, additions=[addition])
...     operations.append(addition)

>>> # Create commit
>>> create_commit(repo_id, operations=operations, commit_message="Commit all shards")

Đầu tiên, chúng ta tạo các đối tượng CommitOperationAdd lần lượt từng cái một. Trong một ví dụ thực tế, các đối tượng này sẽ chứa các shard đã được tạo ra. Mỗi tệp được tải lên trước khi tạo tệp tiếp theo. Trong bước preupload_lfs_files(), đối tượng CommitOperationAdd sẽ bị thay đổi. Bạn chỉ nên sử dụng nó để truyền trực tiếp vào create_commit(). Thay đổi chính của đối tượng là nội dung nhị phân bị loại bỏ khỏi nó, điều này có nghĩa là nó sẽ bị thu gom rác nếu bạn không lưu một tham chiếu khác đến nó. Điều này là dự kiến vì chúng ta không muốn giữ trong bộ nhớ nội dung đã được tải lên. Cuối cùng, chúng ta tạo commit bằng cách truyền tất cả các thao tác vào create_commit(). Bạn có thể truyền thêm các thao tác khác (thêm, xóa hoặc sao chép) chưa được xử lý và chúng sẽ được xử lý chính xác.

Update on GitHub