管理Hugging Face Hub缓存系统
了解缓存
Hugging Face Hub 缓存系统旨在成为所有依赖于 Hub 的库共享的中央缓存。它在 v0.8.0 中进行了更新,以防止在修订版之间重新下载相同的文件。
缓存系统的设计如下
<CACHE_DIR>
├─ <MODELS>
├─ <DATASETS>
├─ <SPACES>
<CACHE_DIR>
通常是用户的 home 目录。但是,可以通过所有方法上的 cache_dir
参数进行自定义,或者通过指定 HF_HOME
或 HF_HUB_CACHE
环境变量进行自定义。
模型、数据集和空间共享一个公共根目录。这些存储库中的每一个都包含存储库类型、(如果存在)命名空间(组织或用户名)以及存储库名称。
<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
现在将从 Hub 下载所有文件到这些文件夹中。缓存确保如果文件已存在且未更新,则不会下载两次;但如果文件已更新,并且您请求的是最新文件,则它会下载最新文件(同时保留以前的文件,以防您再次需要它)。
为了实现这一点,所有文件夹都包含相同的骨架。
<CACHE_DIR>
├─ datasets--glue
│ ├─ refs
│ ├─ blobs
│ ├─ snapshots
...
每个文件夹都设计为包含以下内容:
引用 (Refs)
refs
文件夹包含指示给定引用的最新修订版本的文件。例如,如果我们之前从存储库的 main
分支获取了一个文件,则 refs
文件夹将包含一个名为 main
的文件,该文件本身将包含当前头的提交标识符。
如果 main
的最新提交的标识符为 aaaaaa
,则它将包含 aaaaaa
。
如果同一分支使用新的提交进行更新,该提交的标识符为 bbbbbb
,则重新下载来自该引用的文件将更新 refs/main
文件以包含 bbbbbb
。
文件块 (Blobs)
blobs
文件夹包含我们已下载的实际文件。每个文件的名称都是其哈希值。
快照 (Snapshots)
snapshots
文件夹包含指向上面提到的文件块的符号链接。它本身由多个文件夹组成:每个已知修订版本一个!
在上面的解释中,我们最初从 aaaaaa
修订版本获取了一个文件,然后从 bbbbbb
修订版本获取了一个文件。在这种情况下,我们现在将在 snapshots
文件夹中拥有两个文件夹:aaaaaa
和 bbbbbb
。
在这些文件夹中的每一个中,都存在具有我们已下载的文件名称的符号链接。例如,如果我们在 aaaaaa
修订版本下载了 README.md
文件,我们将有以下路径
<CACHE_DIR>/<REPO_NAME>/snapshots/aaaaaa/README.md
该 README.md
文件实际上是一个符号链接,链接到具有文件哈希值的文件块。
通过这种方式创建框架,我们开启了文件共享机制:如果在 bbbbbb
修订版本中获取了相同的文件,它将具有相同的哈希值,并且无需重新下载该文件。
.no_exist(高级)
除了 blobs
、refs
和 snapshots
文件夹之外,您还可能会在缓存中找到一个 .no_exist
文件夹。此文件夹跟踪您曾经尝试下载但中心站(Hub)上不存在的文件。其结构与 snapshots
文件夹相同,每个已知修订版本都有一个子文件夹。
<CACHE_DIR>/<REPO_NAME>/.no_exist/aaaaaa/config_that_does_not_exist.json
与 snapshots
文件夹不同,文件只是简单的空文件(没有符号链接)。在此示例中,文件 "config_that_does_not_exist.json"
在 "aaaaaa"
修订版本的中心站中不存在。由于它仅存储空文件,因此此文件夹在磁盘使用方面可以忽略不计。
现在您可能想知道,为什么此信息甚至相关?在某些情况下,框架会尝试为模型加载可选文件。保存可选文件的非存在状态可以加快模型加载速度,因为它为每个可能的可选文件节省了 1 次 HTTP 调用。例如,在 transformers
中,每个标记器都可以支持其他文件。您第一次在机器上加载标记器时,它将缓存哪些可选文件存在(以及哪些不存在),以加快下次初始化的加载时间。
要测试文件是否缓存在本地(无需发出任何 HTTP 请求),您可以使用 try_to_load_from_cache() 帮助程序。它将返回文件路径(如果存在且已缓存),对象 _CACHED_NO_EXIST
(如果已缓存非存在)或 None
(如果我们不知道)。
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
...
实践中
在实践中,您的缓存应如下所示:
[ 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
限制
为了拥有高效的缓存系统,huggingface-hub
使用符号链接。但是,并非所有机器都支持符号链接。这是一个已知的限制,尤其是在 Windows 上。在这种情况下,huggingface_hub
不使用 blobs/
目录,而是直接将文件存储在 snapshots/
目录中。此解决方法允许用户以完全相同的方式下载和缓存来自中心站的文件。检查和删除缓存的工具(见下文)也受支持。但是,缓存系统效率较低,因为如果下载了同一存储库的多个修订版本,则可能会多次下载单个文件。
如果您想在 Windows 机器上使用基于符号链接的缓存系统,则需要 激活开发者模式 或以管理员身份运行 Python。
当不支持符号链接时,会向用户显示警告消息,提醒他们正在使用缓存系统的降级版本。可以通过将 HF_HUB_DISABLE_SYMLINKS_WARNING
环境变量设置为 true 来禁用此警告。
缓存资源
除了缓存来自中心站的文件外,下游库通常还需要缓存与 HF 相关但 huggingface_hub
未直接处理的其他文件(例如:从 GitHub 下载的文件、预处理数据、日志等)。为了缓存这些称为“资源”的文件,可以使用 cached_assets_path()。此小型帮助程序以统一的方式根据请求它的库的名称以及可选的命名空间和子文件夹名称在 HF 缓存中生成路径。目标是让每个下游库以自己的方式管理其资源(例如,对结构没有规则),只要它位于正确的资源文件夹中即可。然后,这些库可以利用 huggingface_hub
中的工具来管理缓存,特别是从 CLI 命令扫描和删除资源的某些部分。
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() 是存储资源的推荐方法,但不是强制性的。如果您的库已经使用了自己的缓存,请随意使用它!
实践中的资源
在实践中,您的资源缓存应如下所示:
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/ └── (...)
扫描缓存
目前,缓存文件永远不会从本地目录中删除:当您下载分支的新版本时,会保留以前的文件以备您再次需要。因此,扫描缓存目录以了解哪些仓库和版本占用最多的磁盘空间可能很有用。huggingface_hub
提供了一个辅助工具来执行此操作,该工具可以通过 huggingface-cli
或在 Python 脚本中使用。
从终端扫描缓存
扫描 HF 缓存系统最简单的方法是使用 huggingface-cli
工具中的 scan-cache
命令。此命令扫描缓存并打印一份报告,其中包含仓库 ID、仓库类型、磁盘使用情况、引用和完整本地路径等信息。
以下代码段显示了缓存了 4 个模型和 2 个数据集的文件夹中的扫描报告。
➜ huggingface-cli scan-cache REPO ID REPO TYPE SIZE ON DISK NB FILES LAST_ACCESSED LAST_MODIFIED REFS LOCAL PATH --------------------------- --------- ------------ -------- ------------- ------------- ------------------- ------------------------------------------------------------------------- glue dataset 116.3K 15 4 days ago 4 days ago 2.4.0, main, 1.17.0 /home/wauplin/.cache/huggingface/hub/datasets--glue google/fleurs dataset 64.9M 6 1 week ago 1 week ago refs/pr/1, main /home/wauplin/.cache/huggingface/hub/datasets--google--fleurs Jean-Baptiste/camembert-ner model 441.0M 7 2 weeks ago 16 hours ago main /home/wauplin/.cache/huggingface/hub/models--Jean-Baptiste--camembert-ner bert-base-cased model 1.9G 13 1 week ago 2 years ago /home/wauplin/.cache/huggingface/hub/models--bert-base-cased t5-base model 10.1K 3 3 months ago 3 months ago main /home/wauplin/.cache/huggingface/hub/models--t5-base t5-small model 970.7M 11 3 days ago 3 days ago refs/pr/1, main /home/wauplin/.cache/huggingface/hub/models--t5-small Done in 0.0s. Scanned 6 repo(s) for a total of 3.4G. Got 1 warning(s) while scanning. Use -vvv to print details.
要获取更详细的报告,请使用 --verbose
选项。对于每个仓库,您都会获得已下载的所有版本的列表。如上所述,由于符号链接,两个版本之间不会更改的文件将共享。这意味着磁盘上仓库的大小预计小于其每个版本大小的总和。例如,这里 bert-base-cased
有 2 个版本,分别为 1.4G 和 1.5G,但总磁盘使用量仅为 1.9G。
➜ huggingface-cli scan-cache -v REPO ID REPO TYPE REVISION SIZE ON DISK NB FILES LAST_MODIFIED REFS LOCAL PATH --------------------------- --------- ---------------------------------------- ------------ -------- ------------- ----------- ---------------------------------------------------------------------------------------------------------------------------- glue dataset 9338f7b671827df886678df2bdd7cc7b4f36dffd 97.7K 14 4 days ago main, 2.4.0 /home/wauplin/.cache/huggingface/hub/datasets--glue/snapshots/9338f7b671827df886678df2bdd7cc7b4f36dffd glue dataset f021ae41c879fcabcf823648ec685e3fead91fe7 97.8K 14 1 week ago 1.17.0 /home/wauplin/.cache/huggingface/hub/datasets--glue/snapshots/f021ae41c879fcabcf823648ec685e3fead91fe7 google/fleurs dataset 129b6e96cf1967cd5d2b9b6aec75ce6cce7c89e8 25.4K 3 2 weeks ago refs/pr/1 /home/wauplin/.cache/huggingface/hub/datasets--google--fleurs/snapshots/129b6e96cf1967cd5d2b9b6aec75ce6cce7c89e8 google/fleurs dataset 24f85a01eb955224ca3946e70050869c56446805 64.9M 4 1 week ago main /home/wauplin/.cache/huggingface/hub/datasets--google--fleurs/snapshots/24f85a01eb955224ca3946e70050869c56446805 Jean-Baptiste/camembert-ner model dbec8489a1c44ecad9da8a9185115bccabd799fe 441.0M 7 16 hours ago main /home/wauplin/.cache/huggingface/hub/models--Jean-Baptiste--camembert-ner/snapshots/dbec8489a1c44ecad9da8a9185115bccabd799fe bert-base-cased model 378aa1bda6387fd00e824948ebe3488630ad8565 1.5G 9 2 years ago /home/wauplin/.cache/huggingface/hub/models--bert-base-cased/snapshots/378aa1bda6387fd00e824948ebe3488630ad8565 bert-base-cased model a8d257ba9925ef39f3036bfc338acf5283c512d9 1.4G 9 3 days ago main /home/wauplin/.cache/huggingface/hub/models--bert-base-cased/snapshots/a8d257ba9925ef39f3036bfc338acf5283c512d9 t5-base model 23aa4f41cb7c08d4b05c8f327b22bfa0eb8c7ad9 10.1K 3 1 week ago main /home/wauplin/.cache/huggingface/hub/models--t5-base/snapshots/23aa4f41cb7c08d4b05c8f327b22bfa0eb8c7ad9 t5-small model 98ffebbb27340ec1b1abd7c45da12c253ee1882a 726.2M 6 1 week ago refs/pr/1 /home/wauplin/.cache/huggingface/hub/models--t5-small/snapshots/98ffebbb27340ec1b1abd7c45da12c253ee1882a t5-small model d0a119eedb3718e34c648e594394474cf95e0617 485.8M 6 4 weeks ago /home/wauplin/.cache/huggingface/hub/models--t5-small/snapshots/d0a119eedb3718e34c648e594394474cf95e0617 t5-small model d78aea13fa7ecd06c29e3e46195d6341255065d5 970.7M 9 1 week ago main /home/wauplin/.cache/huggingface/hub/models--t5-small/snapshots/d78aea13fa7ecd06c29e3e46195d6341255065d5 Done in 0.0s. Scanned 6 repo(s) for a total of 3.4G. Got 1 warning(s) while scanning. Use -vvv to print details.
Grep 示例
由于输出采用表格格式,您可以将其与任何类似 grep
的工具结合使用以过滤条目。以下是如何在基于 Unix 的机器上仅过滤“t5-small”模型的版本的示例。
➜ eval "huggingface-cli scan-cache -v" | grep "t5-small" t5-small model 98ffebbb27340ec1b1abd7c45da12c253ee1882a 726.2M 6 1 week ago refs/pr/1 /home/wauplin/.cache/huggingface/hub/models--t5-small/snapshots/98ffebbb27340ec1b1abd7c45da12c253ee1882a t5-small model d0a119eedb3718e34c648e594394474cf95e0617 485.8M 6 4 weeks ago /home/wauplin/.cache/huggingface/hub/models--t5-small/snapshots/d0a119eedb3718e34c648e594394474cf95e0617 t5-small model d78aea13fa7ecd06c29e3e46195d6341255065d5 970.7M 9 1 week ago main /home/wauplin/.cache/huggingface/hub/models--t5-small/snapshots/d78aea13fa7ecd06c29e3e46195d6341255065d5
从 Python 扫描缓存
对于更高级的使用,请使用 scan_cache_dir(),它是 CLI 工具调用的 Python 实用程序。
您可以使用它来获取围绕 4 个数据类结构化的详细报告
- HFCacheInfo:由 scan_cache_dir() 返回的完整报告
- CachedRepoInfo:有关缓存仓库的信息
- CachedRevisionInfo:有关仓库中缓存的版本(例如,“快照”)的信息
- CachedFileInfo:有关快照中缓存的文件的信息
这是一个简单的用法示例。有关详细信息,请参阅参考。
>>> 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(...),
...
],
)
清理缓存
扫描缓存很有趣,但您接下来真正想做的事情通常是删除某些部分以释放驱动器上的空间。这可以通过 delete-cache
CLI 命令实现。还可以以编程方式使用扫描缓存时返回的 HFCacheInfo 对象中的 delete_revisions() 辅助工具。
删除策略
要删除一些缓存,您需要传递要删除的版本列表。该工具将根据此列表定义释放空间的策略。它返回一个 DeleteCacheStrategy 对象,该对象描述将删除哪些文件和文件夹。DeleteCacheStrategy 允许您了解预计将释放多少空间。一旦您同意删除,您必须执行它才能使删除生效。为了避免出现差异,您不能手动编辑策略对象。
删除版本的策略如下
- 包含版本符号链接的
snapshot
文件夹将被删除。 - 仅目标版本要删除的 Blob 文件也将被删除。
- 如果一个版本链接到 1 个或多个
refs
,则引用将被删除。 - 如果删除了仓库中的所有版本,则将删除整个缓存仓库。
版本哈希在所有仓库中都是唯一的。这意味着在删除版本时,您无需提供任何 repo_id
或 repo_type
。
如果缓存中找不到某个版本,则会静默忽略它。此外,如果在尝试删除文件或文件夹时找不到它,则会记录警告,但不会抛出错误。删除继续针对 DeleteCacheStrategy 对象中包含的其他路径。
从终端清理缓存
从 HF 缓存系统删除某些版本最简单的方法是使用 huggingface-cli
工具中的 delete-cache
命令。该命令有两种模式。默认情况下,会向用户显示一个 TUI(终端用户界面)以选择要删除的版本。此 TUI 目前处于测试阶段,因为它尚未在所有平台上进行测试。如果 TUI 在您的机器上不起作用,您可以使用 --disable-tui
标志禁用它。
使用 TUI
这是默认模式。要使用它,您首先需要通过运行以下命令安装额外的依赖项
pip install huggingface_hub["cli"]
然后运行命令
huggingface-cli delete-cache
您现在应该会看到一个可以选中/取消选中的版本列表
说明
- 按键盘方向键
<up>
和<down>
移动光标。 - 按
<space>
切换(选中/取消选中)项目。 - 选中版本后,第一行会更新以显示将释放多少空间。
- 按
<enter>
确认您的选择。 - 如果要取消操作并退出,可以选择第一个项目(“不选择以下任何项目”)。如果选中此项目,则无论选中了哪些其他项目,删除过程都将被取消。否则,您也可以按
<ctrl+c>
退出 TUI。
选择要删除的修订版本并按下<enter>
后,将提示最终确认消息。再次按下<enter>
,删除操作将生效。如果要取消,请输入n
。
✗ huggingface-cli delete-cache --dir ~/.cache/huggingface/hub ? Select revisions to delete: 2 revision(s) selected. ? 2 revisions selected counting for 3.1G. Confirm deletion ? Yes Start deletion. Done. Deleted 1 repo(s) and 0 revision(s) for a total of 3.1G.
不使用 TUI
如上所述,TUI 模式目前处于测试阶段,并且是可选的。它可能无法在您的机器上运行,或者您可能觉得它不方便。
另一种方法是使用--disable-tui
标志。此过程非常相似,因为您将被要求手动查看要删除的修订版本的列表。但是,此手动步骤不会直接在终端中进行,而是在动态生成的临时文件中进行,您可以手动编辑该文件。
此文件在头部包含了您需要的所有说明。在您喜欢的文本编辑器中打开它。要选择/取消选择修订版本,只需使用#
对其进行注释/取消注释。手动审查完成后并编辑了文件,您可以保存它。返回您的终端并按下<enter>
。默认情况下,它将计算使用更新的修订版本列表可以释放多少空间。您可以继续编辑文件或使用"y"
确认。
huggingface-cli delete-cache --disable-tui
命令文件示例
# INSTRUCTIONS # ------------ # This is a temporary file created by running `huggingface-cli delete-cache` with the # `--disable-tui` option. It contains a set of revisions that can be deleted from your # local cache directory. # # Please manually review the revisions you want to delete: # - Revision hashes can be commented out with '#'. # - Only non-commented revisions in this file will be deleted. # - Revision hashes that are removed from this file are ignored as well. # - If `CANCEL_DELETION` line is uncommented, the all cache deletion is cancelled and # no changes will be applied. # # Once you've manually reviewed this file, please confirm deletion in the terminal. This # file will be automatically removed once done. # ------------ # KILL SWITCH # ------------ # Un-comment following line to completely cancel the deletion process # CANCEL_DELETION # ------------ # REVISIONS # ------------ # Dataset chrisjay/crowd-speech-africa (761.7M, used 5 days ago) ebedcd8c55c90d39fd27126d29d8484566cd27ca # Refs: main # modified 5 days ago # Dataset oscar (3.3M, used 4 days ago) # 916f956518279c5e60c63902ebdf3ddf9fa9d629 # Refs: main # modified 4 days ago # Dataset wikiann (804.1K, used 2 weeks ago) 89d089624b6323d69dcd9e5eb2def0551887a73a # Refs: main # modified 2 weeks ago # Dataset z-uo/male-LJSpeech-italian (5.5G, used 5 days ago) # 9cfa5647b32c0a30d0adfca06bf198d82192a0d1 # Refs: main # modified 5 days ago
从 Python 清理缓存
为了获得更大的灵活性,您还可以以编程方式使用delete_revisions()方法。这是一个简单的示例。有关详细信息,请参阅参考。
>>> 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()
Cache deletion done. Saved 8.6G.