Hub Python Library documentation

Hiểu về bộ nhớ đệm

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Hiểu về bộ nhớ đệm

huggingface_hub sử dụng bộ nhớ đệm dựa trên tệp cục bộ để lưu trữ các tệp riêng lẻ đã tải xuống từ Hub và tránh tải lại các tệp không thay đổi khi một kho được cập nhật. Ngoài ra, hf_xet lưu trữ bộ nhớ đệm shard và dữ liệu staging để tối ưu hóa việc tải lên (xem Bộ nhớ đệm Xet).

Hướng dẫn này bao gồm các công cụ quản lý bộ nhớ đệm dành riêng cho Python do huggingface_hub cung cấp. Để có cái nhìn tổng quan không phụ thuộc ngôn ngữ về cách hệ thống bộ nhớ đệm của Hugging Face Hub hoạt động, hãy xem tài liệu Hub về bộ nhớ đệm cục bộ.

Caching dựa trên tệp

Hệ thống cache của Hugging Face Hub được thiết kế để là cache trung tâm được chia sẻ giữa các thư viện phụ thuộc vào Hub. Nó đã được cập nhật trong v0.8.0 để ngăn việc tải lại các tệp giống nhau giữa các phiên bản.

Hệ thống bộ nhớ đệm được thiết kế như sau:

<CACHE_DIR>
├─ <MODELS>
├─ <DATASETS>
├─ <SPACES>
├─ <KERNELS>

<CACHE_DIR> mặc định là ~/.cache/huggingface/hub. Tuy nhiên, bạn có thể tùy chỉnh bằng đối số cache_dir trong tất cả các phương thức, hoặc bằng cách chỉ định biến môi trường HF_HOME hoặc HF_HUB_CACHE.

Các mô hình, bộ dữ liệu, spaces và kernels chia sẻ một gốc chung. Mỗi kho lưu trữ này chứa loại kho lưu trữ, namespace (tổ chức hoặc tên người dùng) nếu có và tên kho lưu trữ:

<CACHE_DIR>
├─ models--julien-c--EsperBERTo-small
├─ models--lysandrejik--arxiv-nlp
├─ models--bert-base-cased
├─ datasets--glue
├─ datasets--huggingface--DataMeasurementsFiles
├─ spaces--dalle-mini--dalle-mini

Chính trong các thư mục này mà tất cả các tệp sẽ được tải xuống từ Hub. Cơ chế lưu trữ tạm thời đảm bảo rằng một tệp sẽ không bị tải xuống hai lần nếu nó đã tồn tại và chưa được cập nhật; nhưng nếu tệp đã được cập nhật và bạn yêu cầu phiên bản mới nhất, hệ thống sẽ tải xuống tệp mới nhất (đồng thời giữ nguyên tệp trước đó trong trường hợp bạn cần sử dụng lại).

Để đạt được điều này, tất cả các thư mục đều chứa cùng một cấu trúc:

<CACHE_DIR>
├─ datasets--glue
│  ├─ refs
│  ├─ blobs
│  ├─ snapshots
│  ├─ trees
...

Mỗi thư mục được thiết kế để chứa các thành phần sau:

Tham chiếu

Thư mục refs chứa các tệp chỉ ra phiên bản mới nhất của tham chiếu được chỉ định. Ví dụ, nếu trước đó chúng ta đã tải một tệp từ nhánh main của một kho lưu trữ, thư mục refs sẽ chứa một tệp có tên main, tệp này sẽ chứa định danh commit của head hiện tại.

Nếu commit mới nhất của main có aaaaaa làm định danh, thì nó sẽ chứa aaaaaa.

Nếu cùng một nhánh đó được cập nhật với một commit mới, có bbbbbb làm định danh, thì việc tải lại một tệp từ tham chiếu đó sẽ cập nhật tệp refs/main để chứa bbbbbb.

Blobs

Thư mục blobs chứa các tệp thực tế mà chúng ta đã tải xuống. Tên của mỗi tệp chính là băm (hash) của nó.

Bản sao lưu

Thư mục snapshots chứa các symlink trỏ đến các blob được đề cập ở trên. Bản thân nó bao gồm một số thư mục: một thư mục cho mỗi revision đã biết!

Trong phần giải thích ở trên, ban đầu chúng ta đã tải một tệp từ bản sửa đổi aaaaaa, trước khi tải một tệp từ bản sửa đổi bbbbbb. Trong tình huống này, hiện tại chúng ta sẽ có hai thư mục trong thư mục snapshots: aaaaaa và bbbbbb.

Trong mỗi thư mục này, có các symlink trực tiếp mang tên của các tệp mà chúng ta đã tải xuống. Ví dụ, nếu chúng ta đã tải tệp README.md tại revision aaaaaa, chúng ta sẽ có đường dẫn sau:

<CACHE_DIR>/<REPO_NAME>/snapshots/aaaaaa/README.md

File README.md đó thực chất là một symlink trỏ đến blob chứa hash của file.

Bằng cách tạo bộ khung theo cách này, chúng ta mở ra cơ chế chia sẻ tệp: nếu cùng một tệp đã được tải về trong phiên bản bbbbbb, tệp đó sẽ có cùng giá trị băm và không cần phải tải lại.

Cây

Thư mục trees lưu bộ nhớ đệm danh sách các tệp mà một kho chứa tại một commit nhất định. Vì một commit là bất biến nên danh sách tệp của nó không bao giờ thay đổi. Điều này có nghĩa là danh sách có thể được lưu bộ nhớ đệm vĩnh viễn mà không cần kiểm tra lại với Hub.

Mỗi danh sách được lưu cache được đặt tên theo một hash commit và lưu dưới dạng tệp JSON, ví dụ trees/aaaaaa.json. Đối với mỗi tệp trong kho tại commit đó, nó ghi lại những gì cần thiết để tải tệp xuống: đường dẫn, kích thước và hash của tệp. Đây là cùng thông tin mà Hub sẽ trả về, nhưng thông thường việc lấy thông tin này tốn một lượt gọi mạng cho mỗi tệp.

Bộ nhớ đệm này được ghi bởi snapshot_download(). Lần đầu tiên bạn tải xuống một commit, danh sách tệp sẽ được lấy một lần và lưu tại đây. Lần tiếp theo bạn tải xuống cùng commit đó, danh sách sẽ được đọc từ đĩa thay vì được lấy lại. Kết quả là, chạy lại thao tác tải xuống khi mọi thứ đã được lưu trong bộ nhớ đệm chỉ tốn một lần gọi mạng: lần gọi cần thiết để phân giải tên nhánh hoặc thẻ thành mã băm commit.

Cả snapshot_download() và hf_hub_download() đều đọc bộ nhớ đệm này để tránh các cuộc gọi mạng. Khi bạn tải xuống một tệp với revision là commit hash (đây chính xác là điều mà snapshot_download() thực hiện bên trong cho mỗi tệp), metadata tải xuống được đọc từ danh sách tệp được lưu trong bộ nhớ đệm và cuộc gọi mạng cho từng tệp sẽ bị bỏ qua. Điều này có nghĩa là một cuộc gọi hf_hub_download() cho một tệp đơn lẻ cũng được hưởng lợi từ danh sách tệp mà một cuộc gọi snapshot_download() trước đó đã lưu cho cùng một commit.

Vì danh sách tệp được lưu trong bộ nhớ đệm mô tả chính xác những gì một commit phải chứa, snapshot_download() cũng có thể xác định xem một snapshot cục bộ có đầy đủ hay không. Nếu không thể kết nối đến Hub (bạn đang ở chế độ ngoại tuyến, kết nối thất bại, hoặc bạn đã truyền local_files_only=True) và một số tệp dự kiến bị thiếu trong snapshot cục bộ, snapshot_download() sẽ ném ra IncompleteSnapshotError thay vì trả về một thư mục không đầy đủ. Trước đây, một snapshot không đầy đủ được trả về một cách im lặng, điều này có thể khiến bạn làm việc với các tệp bị thiếu mà không hề hay biết. Các tệp bị loại trừ bởi allow_patterns hoặc ignore_patterns không được tính là bị thiếu. Ngoại lệ này phơi bày đường dẫn đến snapshot không đầy đủ thông qua thuộc tính snapshot_path của nó, vì vậy bạn vẫn có thể xác định vị trí các tệp được lưu trong bộ nhớ đệm một phần nếu cần.

.no_exist (nâng cao)

Ngoài các thư mục blobs, refs và snapshots, bạn cũng có thể tìm thấy thư mục .no_exist trong bộ nhớ đệm của mình. Thư mục này theo dõi các tệp mà bạn đã thử tải xuống một lần nhưng không tồn tại trên Hub. Cấu trúc của nó giống với thư mục snapshots với 1 thư mục con cho mỗi phiên bản đã biết:

<CACHE_DIR>/<REPO_NAME>/.no_exist/aaaaaa/config_that_does_not_exist.json

Khác với thư mục snapshots, các tệp ở đây là những tệp rỗng đơn giản (không có symlink). Trong ví dụ này, tệp "config_that_does_not_exist.json" không tồn tại trên Hub cho revision "aaaaaa". Vì thư mục này chỉ lưu trữ các tệp rỗng, nên nó có thể bỏ qua về mặt dung lượng ổ đĩa.

Vậy nên bạn có thể tự hỏi, tại sao thông tin này lại liên quan? Trong một số trường hợp, một framework sẽ cố gắng tải các tệp tùy chọn cho một model. Việc lưu trữ thông tin về sự vắng mặt của các tệp tùy chọn giúp việc tải model nhanh hơn, vì nó tiết kiệm được 1 cuộc gọi HTTP cho mỗi tệp tùy chọn có thể có. Đây là trường hợp trong transformers, nơi mỗi tokenizer có thể hỗ trợ các tệp bổ sung. Lần đầu tiên bạn tải tokenizer trên máy của mình, nó sẽ cache các tệp tùy chọn nào tồn tại (và tệp nào không tồn tại) để rút ngắn thời gian tải cho các lần khởi tạo tiếp theo.

Để kiểm tra xem một tệp có được lưu trong bộ nhớ đệm cục bộ hay không (mà không thực hiện bất kỳ yêu cầu HTTP nào), bạn có thể sử dụng tiện ích try_to_load_from_cache(). Hàm này sẽ trả về đường dẫn tệp (nếu tệp tồn tại và đã được lưu trong bộ nhớ đệm), đối tượng _CACHED_NO_EXIST (nếu việc không tồn tại của tệp đã được lưu trong bộ nhớ đệm) hoặc None (nếu chúng ta không biết).

from huggingface_hub import try_to_load_from_cache, _CACHED_NO_EXIST

filepath = try_to_load_from_cache()
if isinstance(filepath, str):
    # file exists and is cached
    ...
elif filepath is _CACHED_NO_EXIST:
    # non-existence of file is cached
    ...
else:
    # file is not cached
    ...

Trong thực tế

Trong thực tế, bộ đệm của bạn nên có cấu trúc cây như sau:

    [  96]  .
    └── [ 160]  models--julien-c--EsperBERTo-small
        ├── [ 160]  blobs
        │   ├── [321M]  403450e234d65943a7dcf7e05a771ce3c92faa84dd07db4ac20f592037a1e4bd
        │   ├── [ 398]  7cb18dc9bafbfcf74629a4b760af1b160957a83e
        │   └── [1.4K]  d7edf6bd2a681fb0175f7735299831ee1b22b812
        ├── [  96]  refs
        │   └── [  40]  main
        ├── [ 128]  snapshots
        │   ├── [ 128]  2439f60ef33a0d46d85da5001d52aeda5b00ce9f
        │   │   ├── [  52]  README.md -> ../../blobs/d7edf6bd2a681fb0175f7735299831ee1b22b812
        │   │   └── [  76]  pytorch_model.bin -> ../../blobs/403450e234d65943a7dcf7e05a771ce3c92faa84dd07db4ac20f592037a1e4bd
        │   └── [ 128]  bbc77c8132af1cc5cf678da3f1ddf2de43606d48
        │       ├── [  52]  README.md -> ../../blobs/7cb18dc9bafbfcf74629a4b760af1b160957a83e
        │       └── [  76]  pytorch_model.bin -> ../../blobs/403450e234d65943a7dcf7e05a771ce3c92faa84dd07db4ac20f592037a1e4bd
        └── [  96]  trees
            ├── [ 521]  2439f60ef33a0d46d85da5001d52aeda5b00ce9f.json
            └── [ 521]  bbc77c8132af1cc5cf678da3f1ddf2de43606d48.json

CACHEDIR.TAG

huggingface_hub tự động tạo một tệp CACHEDIR.TAG bên trong thư mục cache. Tệp này tuân theo Cache Directory Tagging Standard và thông báo cho các công cụ sao lưu (ví dụ: Borg, restic, rsync) rằng thư mục chứa dữ liệu cache có thể tải lại được và có thể được loại trừ khỏi các bản sao lưu một cách an toàn.

Hạn chế

Để có hệ thống cache hiệu quả, huggingface-hub sử dụng symlink. Tuy nhiên, symlink không được hỗ trợ trên tất cả các máy. Đây là một hạn chế đã biết, đặc biệt là trên Windows. Trong trường hợp này, huggingface_hub không sử dụng thư mục blobs/ mà lưu trực tiếp các tệp vào thư mục snapshots/. Cách xử lý này cho phép người dùng tải xuống và cache tệp từ Hub theo đúng cách như bình thường. Các công cụ để kiểm tra và xóa cache (xem bên dưới) cũng được hỗ trợ. Tuy nhiên, hệ thống cache kém hiệu quả hơn vì một tệp có thể được tải xuống nhiều lần nếu nhiều phiên bản của cùng một repo được tải xuống.

Nếu bạn muốn tận dụng hệ thống cache dựa trên symlink trên máy Windows, bạn cần bật Developer Mode hoặc chạy Python với quyền quản trị viên.

Nếu bạn muốn chủ động sử dụng chế độ cache không dùng symlink (ví dụ trên hệ thống tệp dùng chung không xử lý symlink tốt), bạn có thể đặt biến môi trường HF_HUB_DISABLE_SYMLINKS thành 1. Các tệp sẽ được sao chép trực tiếp vào snapshots/ thay vì tạo symlink trỏ đến blobs/.

Khi symlink không được hỗ trợ, một thông báo cảnh báo sẽ được hiển thị cho người dùng để cảnh báo rằng họ đang sử dụng phiên bản suy giảm của hệ thống cache. Thông báo này có thể được tắt bằng cách đặt biến môi trường HF_HUB_DISABLE_SYMLINKS_WARNING thành true.

Các blob dùng chung giữa các kho

Mặc định, các tệp Xet cũng được khử trùng lặp giữa các kho. Một tệp Xet được tải xuống qua hf_xet sẽ được lưu trữ một lần tại <CACHE_DIR>/blobs/<prefix>/<xet_hash>, và mục blobs/<etag> của kho là một liên kết tương đối trỏ đến tệp đó. Khi một kho khác cần cùng tệp đó, nó sẽ nhận được một liên kết thay vì tải xuống: không có byte nào được truyền và không tốn thêm dung lượng. Bố cục snapshot không thay đổi. Một tệp đánh dấu xác định kho lưu trữ, do đó một thư mục blobs không được tạo bởi huggingface_hub sẽ không bao giờ bị đụng chạm.

Mỗi tệp dùng chung có một manifest <xet_hash>.refs liệt kê các blob trong repo sử dụng nó. hf cache rm đọc manifest này để chỉ kiểm tra các tệp dùng chung bị ảnh hưởng bởi thao tác xóa, và hf cache prune sẽ xóa các tệp dùng chung không còn được repo nào trong cache sử dụng nữa. Manifest chỉ là một gợi ý: mọi mục đều được đối chiếu với hệ thống tệp, và một tệp có metadata bị thiếu hoặc không đọc được sẽ được giữ lại. Việc dọn dẹp ưu tiên để lại dữ liệu có thể thu hồi thay vì làm hỏng một mục cache hợp lệ.

Kích thước theo từng repo vẫn mang tính logic, do đó một tệp dùng chung được tính cho mọi repo sử dụng nó. size_on_disk trên toàn bộ cache là kích thước vật lý: mỗi tệp dùng chung chỉ được tính một lần, bao gồm cả những tệp không còn được repo nào sử dụng.

Các client cũ (huggingface_hub, huggingface.js, hf-hub, llama.cpp, và bất kỳ thứ gì theo dõi symlink) vẫn tiếp tục đọc và tải xuống bình thường, trong cùng các thư mục repo. Hai hạn chế:

  • huggingface_hub<=1.31 để lại các tệp dùng chung của kho đã bị xóa trong store, nơi hf cache ls đánh dấu chúng và hf cache prune xóa chúng. Công cụ xóa cache của các client khác có thể thay vào đó xóa một tệp dùng chung vẫn đang được các kho khác sử dụng; các tệp bị ảnh hưởng sẽ được tải xuống lại khi sử dụng lần tiếp theo. Hãy sử dụng huggingface_hub mới nhất cho hf cache rm, hf cache prune và việc xóa bằng chương trình.
  • Trình quét cache của chúng có thể báo cáo thư mục blobs cấp cao nhất là một mục không xác định.

Store yêu cầu bố cục cache dựa trên symlink và bị vô hiệu hóa bởi HF_HUB_DISABLE_XET=1. Mọi lỗi khi chia sẻ tệp, chẳng hạn như hệ thống tệp không được hỗ trợ, lỗi quyền truy cập, hoặc thư mục blobs hiện có không được đánh dấu, sẽ âm thầm chuyển sang lưu trữ cục bộ của repo thông thường. Đặt HF_HUB_DISABLE_SHARED_BLOBS=1 để từ chối hoàn toàn.

Ghim một bản sửa đổi (nâng cao)

Nếu bạn đang tích hợp Hub vào một thư viện ML, một lệnh gọi snapshot_download() đơn lẻ vẫn là cách tiếp cận được khuyến nghị: nó giải quyết revision một lần, tải xuống mọi thứ song song và lưu bộ nhớ đệm danh sách tệp. Những gì tiếp theo chỉ hữu ích cho các thư viện phức tạp tải xuống và nạp nhiều thành phần riêng biệt (config, weights, tokenizer, processor, adapters, …) và không thể sử dụng một lệnh gọi duy nhất.

Khi một thư viện tải xuống nhiều tệp một cách tuần tự, mỗi lần gọi đều phải phân giải revision="main" thành một commit hash một lần nữa. Điều này tốn một cuộc gọi HTTP cho mỗi tệp và, tệ hơn, hai cuộc gọi cách nhau vài giây có thể trỏ đến hai commit khác nhau nếu kho được cập nhật trong khoảng thời gian đó.

HfApi.resolve_revision() phân giải revision một lần và trả về một ResolvedRevision:

>>> from huggingface_hub import resolve_revision
>>> revision = resolve_revision("openai-community/gpt2")
>>> revision
ResolvedRevision(initial=None, resolved='607a30d783dfa663caf39e06633721c8d4cfcd7e')

ResolvedRevision là một lớp con của str, do đó nó có thể được truyền vào bất kỳ phương thức nào của huggingface_hub nhận đối số revision. Giá trị chuỗi của nó là thứ mà người dùng ban đầu yêu cầu ("main" ở đây, do đó thông báo lỗi dễ đọc), trong khi .resolved chứa mã băm của commit:

>>> revision == "main"
True
>>> revision.resolved
'607a30d783dfa663caf39e06633721c8d4cfcd7e'

Các tiện ích tải xuống (hf_hub_download(), snapshot_download(), get_cached_repo_tree()) phát hiện một ResolvedRevision và sử dụng trực tiếp mã băm của commit. Mọi tệp đều được đảm bảo đến từ cùng một commit, và một khi các tệp đã được lưu vào bộ nhớ đệm thì không cần bất kỳ cuộc gọi HTTP nào:

>>> from huggingface_hub import hf_hub_download
>>> config = hf_hub_download("openai-community/gpt2", "config.json", revision=revision)
>>> weights = hf_hub_download("openai-community/gpt2", "model.safetensors", revision=revision)

Bản ánh xạ revision -> commit hash cũng được ghi vào thư mục refs/ của bộ nhớ đệm (xem Refs). Điều này có nghĩa là nếu sau đó không thể kết nối đến Hub (chế độ ngoại tuyến, lỗi kết nối, hết thời gian chờ, Hub ngừng hoạt động), HfApi.resolve_revision() sẽ tự động chuyển sang sử dụng giá trị đã được lưu trong bộ nhớ đệm. Nếu cũng không có gì được lưu trong bộ nhớ đệm, một RevisionResolutionError sẽ được ném ra.

Một commit hash chỉ có ý nghĩa đối với repo mà nó được resolve, và các hàm hỗ trợ tải xuống sử dụng nó nguyên như vậy. Do đó, một ResolvedRevision chỉ được truyền cho repo mà nó được resolve. Nếu một thư viện cũng tải xuống từ một repo khác (một base model, một adapter, một component nằm trong repo riêng của nó, …), nó cần một revision được resolve cho repo đó. Chỉ cần truyền ResolvedRevision trở lại HfApi.resolve_revision(): nó ghi nhớ repo mà nó thuộc về và resolve lại revision ban đầu được yêu cầu ("main" ở đây) cho repo mới.

>>> other_revision = resolve_revision("openai-community/gpt2-medium", revision=revision)  # resolves "main" again
>>> other_revision.resolved
'6dcaa7a952f72f9298047fd5137cd6e4f05f41da'
>>> config = hf_hub_download("openai-community/gpt2-medium", "config.json", revision=other_revision)

Xet caching

Để cung cấp các thao tác tải lên hiệu quả hơn, hf_xet thêm một thư mục xet vào bộ nhớ đệm huggingface_hub hiện có. Thư mục này lưu trữ các shard (cấu trúc dữ liệu ánh xạ tệp sang các chunk) và dữ liệu staging được sử dụng để loại bỏ trùng lặp và tiếp tục quá trình tải lên. Để biết thêm thông tin về hệ thống Xet Storage, hãy xem phần này.

hf_xet không còn sử dụng bộ nhớ đệm chunk cục bộ cho các tệp tải xuống. Việc đặt HF_XET_CHUNK_CACHE_SIZE_BYTES sẽ không kích hoạt bộ nhớ đệm này. Các tệp đã tải xuống vẫn được lưu trong bộ nhớ đệm dựa trên tệp.

Thư mục xet, mặc định nằm tại ~/.cache/huggingface/xet, có thể được cấu hình bằng HF_XET_CACHE. Nó có cấu trúc như sau:

<CACHE_DIR>
├─ xet
│  ├─ environment_identifier
│  │  ├─ shard-cache
│  │  ├─ staging

Thư mục environment_identifier là một chuỗi được mã hóa (trên máy của bạn, nó có thể hiển thị dưới dạng https___cas_serv-tGqkUaZf_CBPHQ6h). Chuỗi này được sử dụng trong quá trình phát triển, cho phép các phiên bản cache cục bộ và production tồn tại song song với nhau. Nó cũng được sử dụng khi tải xuống từ các kho lưu trữ nằm ở các khu vực lưu trữ khác nhau. Bạn có thể thấy nhiều mục như vậy trong thư mục xet, mỗi mục tương ứng với một môi trường khác nhau, nhưng cấu trúc bên trong của chúng là giống nhau.

Các thư mục nội bộ phục vụ các mục đích sau:

  • shard-cache chứa các shard được lưu cache, được sử dụng trên đường dẫn tải lên.
  • staging là một không gian làm việc được thiết kế để hỗ trợ các thao tác tải lên có thể tiếp tục.

Chúng được tài liệu hóa bên dưới.

Bộ nhớ đệm shard và dữ liệu staging được quản lý bởi hf_xet như một lớp tối ưu hóa cho việc tải lên. Để quản lý các tệp đã tải xuống, hãy sử dụng các API bộ nhớ đệm dựa trên tệp của huggingface_hub.

shard-cache

Bộ nhớ đệm này được sử dụng khi tải nội dung lên Hub. Thư mục này phẳng, chỉ bao gồm các tệp shard, mỗi tệp sử dụng một ID làm tên shard.

<CACHE_DIR>
├─ xet
│  ├─ environment_identifier
│  │  ├─ shard-cache
│  │  │  ├─ 1fe4ffd5cf0c3375f1ef9aec5016cf773ccc5ca294293d3f92d92771dacfc15d.mdb
│  │  │  ├─ 906ee184dc1cd0615164a89ed64e8147b3fdccd1163d80d794c66814b3b09992.mdb
│  │  │  ├─ ceeeb7ea4cf6c0a8d395a2cf9c08871211fbbd17b9b5dc1005811845307e6b8f.mdb
│  │  │  ├─ e8535155b1b11ebd894c908e91a1e14e3461dddd1392695ddc90ae54a548d8b2.mdb

shard-cache chứa các shard có đặc điểm:

  • Đã được tạo cục bộ và tải lên CAS thành công
  • Đã tải xuống từ CAS như một phần của thuật toán khử trùng lặp toàn cục

Shards cung cấp ánh xạ giữa các tệp và các khối (chunks). Trong quá trình tải lên, mỗi tệp được chia thành các khối và băm (hash) của từng khối được lưu lại. Sau đó, mọi shard trong bộ nhớ đệm sẽ được tham chiếu. Nếu một shard chứa băm của một khối có mặt trong tệp cục bộ đang được tải lên, thì khối đó có thể bị loại bỏ vì nó đã được lưu trong CAS.

Tất cả các shard có hạn sử dụng là 3-4 tuần kể từ thời điểm được tải xuống. Các shard đã hết hạn sẽ không được tải lên và sẽ bị xóa một tuần sau khi hết hạn.

staging

Khi quá trình tải lên bị kết thúc trước khi nội dung mới được cam kết vào kho, bạn sẽ cần tiếp tục chuyển tệp. Tuy nhiên, có thể một số khối đã được tải lên thành công trước khi bị gián đoạn.

Để bạn không phải bắt đầu lại từ đầu, thư mục staging đóng vai trò là không gian làm việc trong quá trình tải lên, lưu trữ metadata cho các chunk đã tải lên thành công. Thư mục staging có cấu trúc như sau:

<CACHE_DIR>
├─ xet
│  ├─ environment_identifier
│  │  ├─ staging
│  │  │  ├─ shard-session
│  │  │  │  ├─ 906ee184dc1cd0615164a89ed64e8147b3fdccd1163d80d794c66814b3b09992.mdb
│  │  │  │  ├─ xorb-metadata
│  │  │  │  │  ├─ 1fe4ffd5cf0c3375f1ef9aec5016cf773ccc5ca294293d3f92d92771dacfc15d.mdb

Khi các tệp được xử lý và các khối (chunks) được tải lên thành công, metadata của chúng được lưu trữ trong xorb-metadata dưới dạng một shard. Khi tiếp tục phiên tải lên, mỗi tệp sẽ được xử lý lại và các shard trong thư mục này sẽ được tham chiếu. Mọi nội dung đã được tải lên thành công sẽ bị bỏ qua, và mọi nội dung mới sẽ được tải lên (và metadata của nó được lưu lại).

Trong khi đó, shard-session lưu trữ thông tin về tệp và chunk cho các tệp đã được xử lý. Khi quá trình tải lên hoàn tất thành công, nội dung từ các shard này sẽ được chuyển sang shard-cache bền vững hơn.

Hạn chế

shard-cache có giới hạn mềm là 16GB, có thể cấu hình thông qua biến môi trường HF_XET_SHARD_CACHE_SIZE_LIMIT. Không có API cấp cao nào để quản lý bộ nhớ đệm này.

Bộ nhớ đệm shard và dữ liệu staging được sử dụng để tối ưu hóa việc tải lên. Để tương tác với chính các tài sản, bạn nên sử dụng các API của hệ thống bộ nhớ đệm huggingface_hub.

Nếu bạn cần thu hồi dung lượng mà Xet đang sử dụng hoặc cần gỡ lỗi các vấn đề liên quan đến bộ nhớ đệm, hãy xóa hoàn toàn bộ nhớ đệm xet bằng cách chạy rm -rf ~/<cache_dir>/xet, trong đó <cache_dir> là vị trí bộ nhớ đệm Hugging Face của bạn, thường là ~/.cache/huggingface

Cây thư mục cache xet mẫu:

<CACHE_DIR>
├─ xet
│  ├─ environment_identifier
│  │  ├─ shard-cache
│  │  │  ├─ 1fe4ffd5cf0c3375f1ef9aec5016cf773ccc5ca294293d3f92d92771dacfc15d.mdb
│  │  │  ├─ 906ee184dc1cd0615164a89ed64e8147b3fdccd1163d80d794c66814b3b09992.mdb
│  │  │  ├─ ceeeb7ea4cf6c0a8d395a2cf9c08871211fbbd17b9b5dc1005811845307e6b8f.mdb
│  │  │  ├─ e8535155b1b11ebd894c908e91a1e14e3461dddd1392695ddc90ae54a548d8b2.mdb
│  │  ├─ staging
│  │  │  ├─ shard-session
│  │  │  │  ├─ 906ee184dc1cd0615164a89ed64e8147b3fdccd1163d80d794c66814b3b09992.mdb
│  │  │  │  ├─ xorb-metadata
│  │  │  │  │  ├─ 1fe4ffd5cf0c3375f1ef9aec5016cf773ccc5ca294293d3f92d92771dacfc15d.mdb

Để tìm hiểu thêm về Xet Storage, hãy xem phần này.

Lưu trữ tạm thời tài nguyên

In addition to caching files from the Hub, downstream libraries often requires to cache other files related to HF but not handled directly by huggingface_hub (example: file downloaded from GitHub, preprocessed data, logs,…). In order to cache those files, called assets, one can use cached_assets_path(). This small helper generates paths in the HF cache in a unified way based on the name of the library requesting it and optionally on a namespace and a subfolder name. The goal is to let every downstream libraries manage its assets its own way (e.g. no rule on the structure) as long as it stays in the right assets folder. Those libraries can then leverage tools from huggingface_hub to manage the cache, in particular scanning and deleting parts of the assets from a CLI command.

from huggingface_hub import cached_assets_path

assets_path = cached_assets_path(library_name="datasets", namespace="SQuAD", subfolder="download")
something_path = assets_path / "something.json" # Do anything you like in your assets folder !

cached_assets_path() là cách được khuyến nghị để lưu trữ tài sản nhưng không bắt buộc. Nếu thư viện của bạn đã sử dụng bộ nhớ đệm riêng, hãy thoải mái sử dụng nó!

Tài sản trong thực tế

Trong thực tế, bộ đệm tài nguyên của bạn nên có cấu trúc cây như sau:

    assets/
    └── datasets/
    │   ├── SQuAD/
    │   │   ├── downloaded/
    │   │   ├── extracted/
    │   │   └── processed/
    │   ├── Helsinki-NLP--tatoeba_mt/
    │       ├── downloaded/
    │       ├── extracted/
    │       └── processed/
    └── transformers/
        ├── default/
        │   ├── something/
        ├── bert-base-cased/
        │   ├── default/
        │   └── training/
    hub/
    └── models--julien-c--EsperBERTo-small/
        ├── blobs/
        │   ├── (...)
        │   ├── (...)
        ├── refs/
        │   └── (...)
        └── [ 128]  snapshots/
            ├── 2439f60ef33a0d46d85da5001d52aeda5b00ce9f/
            │   ├── (...)
            └── bbc77c8132af1cc5cf678da3f1ddf2de43606d48/
                └── (...)

Quản lý bộ nhớ đệm dựa trên tệp của bạn

Kiểm tra bộ nhớ đệm của bạn

Hiện tại, các tệp được lưu trong bộ nhớ đệm sẽ không bao giờ bị xóa khỏi thư mục cục bộ của bạn: khi bạn tải xuống một phiên bản mới của một nhánh, các tệp trước đó sẽ được giữ lại trong trường hợp bạn cần dùng lại. Do đó, việc kiểm tra thư mục bộ nhớ đệm có thể hữu ích để biết các kho và phiên bản nào đang chiếm nhiều dung lượng ổ đĩa nhất. huggingface_hub cung cấp các hàm trợ giúp mà bạn có thể sử dụng từ CLI hf hoặc từ Python.

Kiểm tra bộ nhớ đệm từ terminal

Chạy hf cache ls để khám phá những gì được lưu trữ cục bộ. Mặc định, lệnh này tổng hợp thông tin theo kho:

➜ hf cache ls
ID                                   SIZE   LAST_ACCESSED LAST_MODIFIED REFS
------------------------------------ ------- ------------- ------------- -------------------
dataset/glue                         116.3K 4 days ago     4 days ago     2.4.0 main 1.17.0
dataset/google/fleurs                 64.9M 1 week ago     1 week ago     main refs/pr/1
model/Jean-Baptiste/camembert-ner    441.0M 2 weeks ago    16 hours ago   main
model/bert-base-cased                  1.9G 1 week ago     2 years ago
model/t5-base                          10.1K 3 months ago   3 months ago   main
model/t5-small                        970.7M 3 days ago     3 days ago     main refs/pr/1

Found 6 repo(s) for a total of 12 revision(s) and 3.4G on disk.

Thêm --revisions để liệt kê mọi snapshot được cache và kết nối các bộ lọc để tập trung vào những gì quan trọng. Các bộ lọc hiểu các kích thước và thời lượng thân thiện với con người, vì vậy các biểu thức như size>1GB hoặc accessed>30d hoạt động ngay lập tức:

➜ hf cache ls --revisions --filter "size>1GB" --filter "accessed>30d"
ID                                   REVISION            SIZE   LAST_MODIFIED REFS
------------------------------------ ------------------ ------- ------------- -------------------
model/bert-base-cased                6d1d7a1a2a6cf4c2    1.9G  2 years ago
model/t5-small                       1c610f6b3f5e7d8a    1.1G  3 months ago  main

Found 2 repo(s) for a total of 2 revision(s) and 3.0G on disk.

Cần đầu ra thân thiện với máy? Hãy dùng --format json để nhận các đối tượng có cấu trúc hoặc --format csv cho bảng tính. Ngoài ra, --quiet chỉ in ra các định danh (mỗi dòng một định danh) để bạn có thể chuyển chúng vào các công cụ khác. Dùng --sort để sắp xếp các mục theo accessed, modified, name hoặc size (thêm :asc hoặc :desc để kiểm soát thứ tự), và --limit để giới hạn kết quả ở N mục đầu tiên. Kết hợp các tùy chọn này với --cache-dir khi bạn cần kiểm tra bộ nhớ đệm được lưu trữ bên ngoài HF_HOME.

Lọc bằng các công cụ shell phổ biến

Đầu ra dạng bảng có nghĩa là bạn có thể tiếp tục sử dụng các công cụ mà bạn đã quen thuộc. Ví dụ, đoạn mã bên dưới tìm tất cả các bản sửa đổi được lưu trong bộ nhớ đệm liên quan đến t5-small:

➜ eval "hf cache ls --revisions" | grep "t5-small"
model/t5-small                       1c610f6b3f5e7d8a    1.1G  3 months ago  main
model/t5-small                       8f3ad1c90fed7a62    820.1M 2 weeks ago   refs/pr/1

Kiểm tra bộ nhớ đệm từ Python

Để sử dụng nâng cao hơn, hãy dùng scan_cache_dir(), đây là tiện ích python được gọi bởi công cụ CLI.

Bạn có thể sử dụng nó để lấy báo cáo chi tiết được cấu trúc xung quanh 4 dataclass:

  • HFCacheInfo: báo cáo hoàn chỉnh được trả về bởi scan_cache_dir()
  • CachedRepoInfo: thông tin về một kho đã được lưu bộ nhớ đệm
  • CachedRevisionInfo: thông tin về một bản sửa đổi được lưu trong bộ nhớ đệm (ví dụ: “snapshot”) bên trong một kho
  • CachedFileInfo: thông tin về một tệp được lưu trong bộ nhớ đệm của một bản chụp

Dưới đây là một ví dụ sử dụng đơn giản. Xem tài liệu tham khảo để biết thêm chi tiết.

>>> from huggingface_hub import scan_cache_dir

>>> hf_cache_info = scan_cache_dir()
HFCacheInfo(
    size_on_disk=3398085269,
    repos=frozenset({
        CachedRepoInfo(
            repo_id='t5-small',
            repo_type='model',
            repo_path=PosixPath(...),
            size_on_disk=970726914,
            nb_files=11,
            last_accessed=1662971707.3567169,
            last_modified=1662971107.3567169,
            revisions=frozenset({
                CachedRevisionInfo(
                    commit_hash='d78aea13fa7ecd06c29e3e46195d6341255065d5',
                    size_on_disk=970726339,
                    snapshot_path=PosixPath(...),
                    # No `last_accessed` as blobs are shared among revisions
                    last_modified=1662971107.3567169,
                    files=frozenset({
                        CachedFileInfo(
                            file_name='config.json',
                            size_on_disk=1197
                            file_path=PosixPath(...),
                            blob_path=PosixPath(...),
                            blob_last_accessed=1662971707.3567169,
                            blob_last_modified=1662971107.3567169,
                        ),
                        CachedFileInfo(...),
                        ...
                    }),
                ),
                CachedRevisionInfo(...),
                ...
            }),
        ),
        CachedRepoInfo(...),
        ...
    }),
    warnings=[
        CorruptedCacheException("Snapshots dir doesn't exist in cached repo: ..."),
        CorruptedCacheException(...),
        ...
    ],
)

Xác minh bộ nhớ đệm của bạn

huggingface_hub có thể xác minh rằng các tệp đã lưu trong bộ nhớ đệm của bạn khớp với các mã kiểm tra trên Hub. Sử dụng CLI hf cache verify để kiểm tra tính nhất quán của tệp cho một phiên bản cụ thể của một kho lưu trữ cụ thể:

>>> hf cache verify meta-llama/Llama-3.2-1B-Instruct
✅ Verified 13 file(s) for 'meta-llama/Llama-3.2-1B-Instruct' (model) in ~/.cache/huggingface/hub/models--meta-llama--Llama-3.2-1B-Instruct/snapshots/9213176726f574b556790deb65791e0c5aa438b6
  All checksums match.

Xác minh một bản sửa đổi được lưu trong bộ nhớ đệm cụ thể:

>>> hf cache verify meta-llama/Llama-3.1-8B-Instruct --revision 0e9e39f249a16976918f6564b8830bc894c89659

Xem tham chiếu CLI hf cache verify để biết thêm chi tiết về cách sử dụng và danh sách đầy đủ các tùy chọn.

Dọn dẹp bộ nhớ đệm

Việc quét cache là thú vị nhưng điều bạn thực sự muốn làm tiếp theo thường là xóa một số phần để giải phóng dung lượng trên ổ đĩa. Bạn có thể thực hiện điều này bằng các lệnh CLI hf cache rm và hf cache prune. Bạn cũng có thể sử dụng theo cách lập trình các hàm trợ giúp delete_revisions() và delete_files() từ đối tượng HFCacheInfo được trả về khi quét cache.

Chiến lược xóa

Để xóa một phần bộ nhớ đệm, bạn cần truyền vào một danh sách các phiên bản cần xóa. Công cụ sẽ xác định chiến lược giải phóng dung lượng dựa trên danh sách này. Nó trả về một đối tượng DeleteCacheStrategy mô tả các tệp và thư mục sẽ bị xóa. Đối tượng DeleteCacheStrategy cho phép bạn biết dung lượng dự kiến sẽ được giải phóng. Khi bạn đồng ý với việc xóa, bạn phải thực thi nó để việc xóa có hiệu lực. Để tránh sai lệch, bạn không thể chỉnh sửa thủ công một đối tượng chiến lược.

Chiến lược để xóa các bản sửa đổi như sau:

  • thư mục snapshot chứa các liên kết mềm (symlink) của phiên bản sẽ bị xóa.
  • các tệp blobs chỉ được nhắm đến bởi các bản sửa đổi sẽ bị xóa cũng sẽ bị xóa.
  • nếu một revision được liên kết với 1 hoặc nhiều refs, các tham chiếu sẽ bị xóa.
  • nếu tất cả các phiên bản từ một kho được xóa, toàn bộ kho được lưu trong bộ nhớ đệm sẽ bị xóa.

Việc xóa các tệp riêng lẻ bằng delete_files() cũng tuân theo cùng một logic: các mục snapshot sẽ bị xóa, và các blob của chúng chỉ bị xóa nếu không có tệp cache nào khác tham chiếu đến chúng. Các Refs và thư mục snapshot được giữ lại.

Revision hashes là duy nhất trên tất cả các kho. Do đó, hf cache rm chấp nhận một định danh kho (ví dụ model/bert-base-uncased) hoặc một revision hash đơn thuần; khi truyền hash, bạn không cần chỉ định kho riêng biệt.

Nếu một revision không được tìm thấy trong cache, nó sẽ bị bỏ qua một cách im lặng. Ngoài ra, nếu một tệp hoặc thư mục không thể được tìm thấy khi cố gắng xóa nó, một cảnh báo sẽ được ghi log nhưng không có lỗi nào được ném ra. Việc xóa sẽ tiếp tục cho các đường dẫn khác chứa trong đối tượng DeleteCacheStrategy.

Dọn dẹp bộ nhớ đệm từ terminal

Sử dụng hf cache rm để xóa vĩnh viễn các kho hoặc bản sửa đổi khỏi bộ nhớ đệm của bạn. Truyền vào một hoặc nhiều định danh kho (ví dụ model/bert-base-uncased) hoặc các băm bản sửa đổi:

➜ hf cache rm model/bert-base-cased
About to delete 1 repo(s) totalling 1.9G.
  - model/bert-base-cased (entire repo)
Proceed with deletion? [y/N]: y
Deleted 1 repo(s) and 1 revision(s); freed 1.9G.

Bạn cũng có thể sử dụng hf cache rm kết hợp với hf cache ls --quiet để xóa hàng loạt các mục được xác định bởi bộ lọc:

>>> hf cache rm $(hf cache ls --filter "accessed>1y" -q) -y
About to delete 2 repo(s) totalling 5.31G.
  - model/meta-llama/Llama-3.2-1B-Instruct (entire repo)
  - model/hexgrad/Kokoro-82M (entire repo)
Deleted 2 repo(s) and 2 revision(s); freed 5.31G.

Trộn các kho và các bản sửa đổi trong cùng một lệnh gọi. Thêm --dry-run để xem trước tác động, hoặc --yes để bỏ qua lời nhắc xác nhận khi viết script:

➜ hf cache rm model/t5-small 8f3ad1c --dry-run
About to delete 1 repo(s) and 1 revision(s) totalling 1.1G.
  - model/t5-small:
      8f3ad1c [main] 1.1G
Dry run: no files were deleted.

Để xóa một tệp duy nhất thay vì toàn bộ kho, chẳng hạn một lượng tử hóa GGUF, hãy truyền một URI tệp hf://. Tệp sẽ bị xóa khỏi mọi bản sửa đổi đã được lưu trong bộ nhớ đệm của kho, và blob của nó chỉ bị xóa nếu không còn tệp nào khác trong bộ nhớ đệm tham chiếu đến nó nữa. Bản sửa đổi vẫn sử dụng được, và tệp đã bị xóa sẽ được tải xuống lại vào lần tiếp theo khi cần. Đường dẫn phải khớp chính xác: không hỗ trợ thư mục và mẫu glob.

➜ hf cache rm hf://models/unsloth/gemma-3-27b-it-GGUF/gemma-3-27b-it-Q4_K_M.gguf --dry-run
About to delete 1 file(s) totalling 16.5G.
  - model/unsloth/gemma-3-27b-it-GGUF@3f4b5c1d2e6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c/gemma-3-27b-it-Q4_K_M.gguf
Dry run: no files were deleted.

Khi làm việc ngoài vị trí cache mặc định, hãy kết hợp lệnh với --cache-dir PATH.

Để dọn dẹp rác trong cache hàng loạt, hãy chạy hf cache prune. Lệnh này tự động xóa các phiên bản không còn được tham chiếu bởi nhánh hoặc thẻ nào, các tệp .incomplete còn sót lại từ các lượt tải bị gián đoạn, và các blob dùng chung không còn được bất kỳ kho cache nào tham chiếu nữa:

➜ hf cache prune
About to delete 3 unreferenced revision(s) and 2 incomplete download(s) (2.4G total).
  - model/t5-small:
      1c610f6b [refs/pr/1] 820.1M
      d4ec9b72 [(detached)] 640.5M
  - dataset/google/fleurs:
      2b91c8dd [(detached)] 937.6M
Proceed? [y/N]: y
Deleted 3 unreferenced revision(s) and 2 incomplete download(s); freed 2.4G.

Các tệp .incomplete là các blob một phần còn sót lại khi quá trình tải xuống bị gián đoạn. Chúng không được theo dõi bởi quy trình quét dựa trên revision, do đó hf cache ls chỉ đưa ra một gợi ý (Found X incomplete download(s) ...) trong khi hf cache prune mới là lệnh thực sự xóa chúng. hf cache rm không bao giờ chạm đến chúng, ngoại trừ khi xóa toàn bộ một repo.

Cả hai lệnh đều hỗ trợ --dry-run, --yes và --cache-dir để bạn có thể xem trước, tự động hóa và chỉ định các thư mục cache thay thế khi cần.

Dọn cache từ Python

Để có thêm sự linh hoạt, bạn cũng có thể sử dụng phương thức delete_revisions() một cách lập trình. Dưới đây là một ví dụ đơn giản. Xem tài liệu tham khảo để biết thêm chi tiết.

>>> from huggingface_hub import scan_cache_dir

>>> delete_strategy = scan_cache_dir().delete_revisions(
...     "81fd1d6e7847c99f5862c9fb81387956d99ec7aa"
...     "e2983b237dccf3ab4937c97fa717319a9ca1a96d",
...     "6c0e6080953db56375760c0471a8c5f2929baf11",
... )
>>> print("Will free " + delete_strategy.expected_freed_size_str)
Will free 8.6G

>>> delete_strategy.execute()
Update on GitHub