Hub Python Library documentation
Взаимодействие с Hub через Filesystem API
Взаимодействие с Hub через Filesystem API
Помимо HfApi, библиотека huggingface_hub предоставляет HfFileSystem — pythonic-интерфейс файловой системы, совместимый с fsspec, для работы с Hugging Face Hub. HfFileSystem построена на базе HfApi и предлагает типичные файловые операции, такие как cp, mv, ls, du, glob, get_file и put_file.
HfFileSystem обеспечивает совместимость с fsspec, что полезно для библиотек, требующих её (например, для прямого чтения наборов данных и бакетов Hugging Face с помощью
pandas). Однако этот слой совместимости вносит дополнительные накладные расходы. Для лучшей производительности и надёжности рекомендуется по возможности использовать методы HfApi.
Использование
>>> from huggingface_hub import hffs
>>> # List all files in a dataset directory
>>> hffs.ls("datasets/my-username/my-dataset-repo/data", detail=False)
['datasets/my-username/my-dataset-repo/data/train.csv', 'datasets/my-username/my-dataset-repo/data/test.csv']
>>> # List all files in a bucket directory
>>> hffs.ls("buckets/my-username/my-bucket/experiment-data", detail=False)
['bucket/my-username/my-bucket/data/train-0000.parquet', 'bucket/my-username/my-bucket/data/train-0001.parquet', ...]
>>> # List all ".csv" files in a dataset repository
>>> hffs.glob("datasets/my-username/my-dataset-repo/**/*.csv")
['datasets/my-username/my-dataset-repo/data/train.csv', 'datasets/my-username/my-dataset-repo/data/test.csv']
>>> # Read a remote file
>>> with hffs.open("datasets/my-username/my-dataset-repo/data/train.csv", "r") as f:
... train_data = f.readlines()
>>> # Read the content of a remote file as a string
>>> train_data = hffs.read_text("datasets/my-username/my-dataset-repo/data/train.csv", revision="dev")
>>> # Write a remote file
>>> with hffs.open("datasets/my-username/my-dataset-repo/data/validation.csv", "w") as f:
... f.write("text,label")
... f.write("Fantastic movie!,good")Необязательный аргумент revision можно передать для выполнения операции из конкретного коммита, например ветки, тега или хэша коммита. Обратите внимание, что revision несовместим с Buckets.
В отличие от встроенной в Python функции open, функция open из fsspec по умолчанию работает в двоичном режиме "rb". Это означает, что для чтения и записи в текстовом режиме необходимо явно указать режимы "r" и "w" соответственно. Добавление данных в конец файла (режимы "a" и "ab") пока не поддерживается.
Список крупных репозиториев
Операции, перечисляющие файлы рекурсивно, такие как find и glob, требуют получения всего содержимого репозитория. Hub возвращает такие записи постранично, и запрос следующей страницы возможен только после получения предыдущей: для перечисления репозитория с 800 тыс. файлов требуется около 800 последовательных запросов, а значит, примерно 30 минут.
Чтобы избежать этого, HfFileSystem перечисляет содержимое крупных репозиториев по одному каталогу за раз, параллельно:
>>> from huggingface_hub import hffs
>>> # Takes ~30s on a repository holding 800k files
>>> files = hffs.glob("datasets/allenai/objaverse/**/*.glb", maxdepth=3)Количество одновременных запросов контролируется аргументом max_workers класса HfFileSystem. По умолчанию он равен 16
и может быть установлен в 1 для отключения параллельного получения списков.
Обратите внимание, что передача параметра maxdepth также значительно ускоряет получение списков, поскольку Hub в этом случае возвращает только те записи,
которые действительно запрошены.
Держите списки актуальными
Каталоги перечисляются один раз, а их содержимое кэшируется, поэтому изменения, внесённые другим пользователем, не подхватываются автоматически. HfFileSystem.invalidate_cache() сбрасывает кэшированные списки, либо для одного пути (и его родительских каталогов), либо для всех путей, если вызывается без аргументов:
>>> hffs.ls("buckets/my-username/my-bucket/data", detail=False) # listing is cached
>>> # ... another process uploads a file to the bucket ...
>>> hffs.invalidate_cache("buckets/my-username/my-bucket/data")
>>> hffs.ls("buckets/my-username/my-bucket/data", detail=False) # listed again
['buckets/my-username/my-bucket/data/train.csv', 'buckets/my-username/my-bucket/data/new-file.csv']Для бакетов huggingface_hub может сделать это за вас: Хаб транслирует изменения файлов в бакете по мере их появления, а HfFileSystem удаляет из списков те записи, на которые повлияло изменение, сразу после его получения. Включите это с помощью live_follow=True:
>>> from huggingface_hub import HfFileSystem
>>> hffs = HfFileSystem(live_follow=True)
>>> hffs.ls("buckets/my-username/my-bucket/data", detail=False) # starts following that bucket
>>> # ... another process uploads a file to the bucket ...
>>> hffs.ls("buckets/my-username/my-bucket/data", detail=False) # refreshed as changes arrive
['buckets/my-username/my-bucket/data/train.csv', 'buckets/my-username/my-bucket/data/new-file.csv']Также его можно передать через fsspec, с помощью fsspec.filesystem("hf", live_follow=True) или через аргумент storage_options в библиотеках, которые его поддерживают (pandas, arrow, …).
Несколько важных моментов:
- Только корзины. Репозитории моделей, наборов данных и пространств являются git-репозиториями, и Хаб не транслирует их изменения: передайте
refresh=Trueв HfFileSystem.ls() (или используйте HfApi.list_repo_tree()), чтобы увидеть новый коммит. - Обновляются только списки и их метаданные. При чтении файла его содержимое всегда запрашивается с Hub, поэтому live following влияет только на то, что сообщают
ls,info,exists,glob, … - Подписка начинается сразу после получения списка объектов в бакете, и для каждого отслеживаемого бакета поддерживается одно фоновое соединение, общее для всех экземпляров HfFileSystem. Именно поэтому этот параметр включается явно.
Интеграции
Систему HfFileSystem можно использовать с любой библиотекой, интегрирующей fsspec, при условии, что URL соответствует схеме:
hf://[<repo_type_prefix>]<repo_id>[@<revision>]/<path/in/repo>
repo_type_prefix имеет значение datasets/ для наборов данных, spaces/ для Spaces, а для моделей префикс в URL не требуется.
Помимо репозиториев, HfFileSystem также поддерживает Hugging Face Buckets, представляющие собой объектное хранилище, аналогичное S3 (подробнее см. это руководство):
hf://buckets/<bucket_id>/<path/in/bucket>Ниже перечислены некоторые интересные интеграции, в которых HfFileSystem упрощает взаимодействие с Hub:
Чтение/запись Pandas DataFrame из/в репозиторий Hub:
>>> import pandas as pd >>> # Read a remote CSV file into a dataframe >>> df = pd.read_csv("hf://datasets/my-username/my-dataset-repo/train.csv") >>> df = pd.read_csv("hf://buckets/my-username/my-bucket/train.csv") >>> # Write a dataframe to a remote CSV file >>> df.to_csv("hf://datasets/my-username/my-dataset-repo/test.csv") >>> df.to_csv("hf://buckets/my-username/my-bucket/test.csv")
Этот же рабочий процесс можно использовать и для DataFrames в Dask и Polars.
Запрос файлов (удалённого) Hub с помощью DuckDB:
>>> from huggingface_hub import HfFileSystem >>> import duckdb >>> fs = HfFileSystem() >>> duckdb.register_filesystem(fs) >>> # Query a remote file and get the result back as a dataframe >>> fs_query_file = "hf://datasets/my-username/my-dataset-repo/data_dir/data.parquet" >>> df = duckdb.query(f"SELECT * FROM '{fs_query_file}' LIMIT 10").df()Использование Hub в качестве хранилища массивов с Zarr:
>>> import numpy as np >>> import zarr >>> embeddings = np.random.randn(50000, 1000).astype("float32") >>> # Write an array to a repo >>> root = zarr.open_group("hf://my-username/my-model-repo/array-store", mode="w") >>> foo = root.create_group("embeddings") >>> foobar = foo.zeros(name="experiment_0", shape=(50000, 1000), chunks=(10000, 1000), dtype="f4") >>> foobar[:] = embeddings >>> # Read an array from a repo >>> root = zarr.open_group("hf://my-username/my-model-repo/array-store", mode="r") >>> first_row = root["embeddings/experiment_0"][0]
Аутентификация
Во многих случаях для взаимодействия с Hub необходимо войти в систему с учётной записью Hugging Face. Подробнее о методах аутентификации на Hub см. в разделе Authentication документации.
Также можно выполнить вход в систему программно, передав ваш token в качестве аргумента в HfFileSystem:
>>> from huggingface_hub import HfFileSystem
>>> hffs = HfFileSystem(token=token)Если вы входите в систему таким образом, будьте осторожны, чтобы случайно не раскрыть токен при публикации исходного кода!
Update on GitHub