Hub documentation
Lance
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