Hub documentation

Lance

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Lance

Lance 是一种面向 AI 的开源多模态数据湖仓表格式。您可以使用 Hugging Face 路径(hf://)来访问 Hub 上的 Lance 数据集。这使得您无需将整个数据集复制到本地,即可在 Hugging Face Hub 上扫描和搜索大型数据集。

入门

要开始使用,请通过 pip 安装 pylance 和 pyarrow:

pip install pylance pyarrow

为什么选择 Lance?

  • 针对 ML/AI 工作负载进行了优化:Lance 是一种现代列式格式,专为快速随机访问而设计,同时不会牺牲扫描性能,因此适用于搜索、分析、训练、特征工程等众多用例。
  • 多模态资产以字节或二进制对象(“以文件形式存储的 blob”)的形式与嵌入向量及传统标量数据一起存储在 Lance 中,这使得通过 Hub 管理、共享和分发大型数据集变得更加便捷。
  • 索引是一等公民(该格式本身原生支持):Lance 自带快速、基于磁盘且可扩展的向量和 FTS 索引,这些索引与数据集一同存放在 Hub 上,因此您不仅可以共享数据,还可以共享嵌入和索引,而无需用户重新计算。
  • 灵活的架构和数据演进允许您逐步添加新的特征/列(如审核标签、嵌入等),而无需重写整个表。

将所有数据存储在一个地方

在 Lance 中,您的多模态数据资产(图像、音频、视频)以原始字节的形式与标量元数据和嵌入向量一起存储。这使得您可以在一个地方轻松扫描和过滤数据集,而无需将多个存储系统拼接在一起。

使用 datasets 从 Hub 流式传输

使用 load_dataset(..., streaming=True) 可在不将数据下载到本地的情况下扫描并迭代数据。

from datasets import load_dataset

# Return as a Hugging Face dataset
ds = load_dataset(
    "lance-format/laion-1m",
    split="train",
    streaming=True
)
# Take first three rows
for row in ds.take(3):
    print(row["caption"])

流式处理非常适合采样元数据以了解数据内容。对于向量搜索或处理大型二进制数据块,您可以使用 Lance dataset API,其用法将在下文说明。

流式读取在采样简单的标量元数据时速度很快,但在处理嵌入向量或大型多模态资源时则不够迅速。为了处理大型数据集,建议先扫描元数据,确定所需的数据子集,然后将该部分数据集下载到本地,以避免触发 Hub 的速率限制:hf download lance-format/laion-1m --repo-type dataset --local-dir ./laion

使用 lance.dataset 从 Hub 流式传输

您还可以使用 hf:// 路径说明符来扫描存储在 Hugging Face Hub 上的 Lance 数据集。这可以在无需将其下载到本地的情况下扫描远程数据集。使用 Lance dataset API,设置限制、过滤和投影以仅获取所需数据非常简单。

import lance

# Return as a Lance dataset
ds = lance.dataset("hf://datasets/lance-format/laion-1m/data/train.lance")

scanner = ds.scanner(
    columns=["caption", "url", "similarity"],
    limit=5
)

rows = scanner.to_table().to_pylist()
for row in rows:
    print(row)

处理二进制资产

以下示例展示了如何从 Lance 数据集中以原始 JPEG 字节的形式获取 image 列中的图像,并在下游使用。 使用 ds.take 获取字节并将其写入磁盘,以便在其他地方使用。

import lance
from pathlib import Path

ds = lance.dataset("hf://datasets/lance-format/laion-1m/data/train.lance")

dir_name = "laion_samples"
Path(dir_name).mkdir(exist_ok=True)

rows = ds.take([0, 1], columns=["image", "caption"]).to_pylist()
for idx, row in enumerate(rows):
    with open(f"{dir_name}/{idx}.jpg", "wb") as f:
        f.write(row["image"])
        print(f"Wrote image with caption: {row['caption']}")

将子集写入新的 Lance 数据集

处理大型数据集?只需运行一次过滤扫描,即可从 Hub 中选取行子集,并将其物化为本地 Lance 数据集。

import lance

ds = lance.dataset("hf://datasets/lance-format/laion-1m/data/train.lance")
scanner = ds.scanner(
    columns=["image", "caption", "width", "height"],
    filter="width >= 200 AND height >= 100",
    limit=10,
)
subset = scanner.to_table()

lance.write_dataset(subset, "./laion_subset")

创建索引

如果数据集尚未关联索引,您可以在将其下载到本地后创建一个。

# ds is a local Lance dataset
ds.create_index(
    "img_emb",
    index_type="IVF_PQ",
    num_partitions=256,
    num_sub_vectors=96,
    replace=True,
)

有关向量索引创建的更详细示例,请参阅 Lance 文档。创建向量索引后,您可以通过嵌入在数据上执行相似性搜索。

向量搜索

由于索引在 Lance 中是一等公民,您可以将数据、嵌入和索引一起存储,并直接在 Hub 上进行查询。只需使用 describe_indices() 方法即可列出数据集的索引信息。如果数据集中不存在索引,您可以使用 lance.write_dataset() 写入数据集的本地版本,并使用 LanceDataset.create_index 根据您的需求创建索引。

下面的示例展示了一个数据集,该数据集在 img_emb 字段上已经有一个向量索引:

import lance

ds = lance.dataset("hf://datasets/lance-format/laion-1m/data/train.lance")

print(ds.list_indices())

# Returns
# [
#   IndexDescription(
#       name=img_emb_idx,
#       type_url=/lance.table.VectorIndexDetails,
#       num_rows_indexed=1209588,
#       fields=[15],
#       field_names=["img_emb"],
#       num_segments=1
#.   )
# ]

您可以直接在远程数据集上运行向量搜索查询,而无需将其下载(或者,如果您愿意,也可以将数据集下载到本地并创建新的索引)。下面的示例展示了如何使用图像嵌入作为查询向量,在向量索引上运行最近邻搜索。

import lance
import pyarrow as pa

ds = lance.dataset("hf://datasets/lance-format/laion-1m/data/train.lance")

emb_field = ds.schema.field("img_emb")
ref = ds.take([0], columns=["img_emb"]).to_pylist()[0]["img_emb"]
query = pa.array([ref], type=emb_field.type)

neighbors = ds.scanner(
    nearest={
        "column": emb_field.name,
        "q": query[0],
        "k": 6,
        "nprobes": 16,
        "refine_factor": 30,
    },
    columns=["caption", "url", "similarity"],
).to_table().to_pylist()

设置较大的 k 或 nprobes 值,或一次性发送大批量查询,可能会触发 Hub 的速率限制。对于高负载使用场景,请将数据集(或其子集)下载到本地,并将 Lance 指向本地路径,以避免被限流。

数据集演进

Lance 最强大的特性之一是灵活且零成本的数据演化,这意味着您可以在不重写原始表的情况下轻松添加派生列。对于包含大量大型二进制对象(blobs)的超大表,I/O 节省效果可能非常显著。如果您正在为机器学习/人工智能工程任务对数据进行实验,并且经常需要添加新特征、嵌入或派生元数据,那么这一特性将非常实用。

以下示例展示了如何添加一个派生的 moderation_label 列,该列基于现有的分数列将图像标记为 NSFW。进行此更改时,对新列进行回填(backfilling)仅会写入新列的数据,而不会触及原始图像 blob 或其他列中的数据。您也可以选择不回填任何数据,仅添加新列的 schema。

import lance
import pyarrow as pa

# Assumes you ran the export to Lance example above to store a local subset of the data
local_ds = lance.dataset("./laion_subset")

# schema only (data to be added later)
local_ds.add_columns(pa.field("moderation_label", pa.string()))

# with data backfill
local_ds.add_columns(
    {
        "moderation_label": "case WHEN \"NSFW\" > 0.5 THEN 'review' ELSE 'ok' END"
    }
)

请参阅 Lance 文档中的 数据演化 部分,了解如何在 Lance 数据集中修改和删除列。

处理视频 blob

Lance 表还支持大型内联视频 blob。OpenVid-1M 数据集(来自这篇论文)包含高质量、富有表现力的视频及其字幕。视频数据存储在 Hub 上以下 Lance 数据集的 video_blob 列中。

import lance

lance_ds = lance.dataset("hf://datasets/lance-format/Openvid-1M/data/train.lance")
blob_file = lance_ds.take_blobs("video_blob", ids=[0])[0]
video_bytes = blob_file.read()

与其他数据格式不同,大型多模态二进制对象(blob)在 Lance 中是一等公民。blob API 提供了一个高级 API,用于在 Lance 数据集中存储和检索大型 blob。以下示例展示了如何在不加载较重的视频 blob 的情况下高效浏览元数据,然后按需获取相关的视频 blob。

import lance

ds = lance.dataset("hf://datasets/lance-format/Openvid-1M/data/train.lance")

# 1. Browse metadata without loading video blobs.
metadata = ds.scanner(
    columns=["caption", "aesthetic_score"],
    filter="aesthetic_score >= 4.5",
    limit=2,
).to_table().to_pylist()

# 2. Fetch a single video blob by row index.
selected_index = 0
blob_file = ds.take_blobs("video_blob", ids=[selected_index])[0]
with open("video_0.mp4", "wb") as f:
    f.write(blob_file.read())

准备训练数据

训练是 Lance 的快速随机访问和扫描性能同样可以发挥作用的另一个领域。您可以将 Lance 数据集用作训练数据的存储机制,并在训练流程中对其进行洗牌和按批次加载。

Lance 中的 blob API 与 torchcodec 兼容,因此您可以轻松地将视频 blob 解码为 torch 张量:

from torchcodec.decoders import VideoDecoder
decoder = VideoDecoder(blob_file)
tensor = decoder[0]  # uint8 tensor of shape [C, H, W]

有关高效解码视频的更多函数,请参阅 torchcodec 文档。

此外,您还可以查阅 Lance 文档,了解将图像数据加载到 torchvision 中以训练自定义图像模型的更多示例。

探索更多 Lance 数据集

Lance 是一种开放格式,支持在传统的表格数据旁边原生存储多模态 blob。 借助 Hugging Face Hub 集成,您可以在一个地方轻松处理图像、音频、视频、文本、嵌入和标量元数据。

在 Hugging Face Hub 上探索更多 Lance 数据集, 并与社区中的其他人分享您自己的 Lance 数据集! 您可以访问 lance.org 获取更多代码片段和示例。

Update on GitHub