Hub documentation
Lance
Lance
Lance é um formato de tabela de lakehouse multimodal aberto para IA. Você pode usar caminhos do Hugging Face (hf://) para acessar conjuntos de dados Lance no Hub. Isso permite varrer e pesquisar grandes conjuntos de dados no Hugging Face Hub sem precisar copiar o conjunto de dados inteiro localmente.

Começando
Para começar, instale pylance e pyarrow com pip:
pip install pylance pyarrow
Por que Lance?
- Otimizado para cargas de trabalho de ML/IA: Lance é um formato colunar moderno projetado para acesso aleatório rápido sem comprometer o desempenho de varredura, tornando-o útil para busca, análise, treinamento, engenharia de recursos e muitos outros casos de uso.
- Ativos multimodais são armazenados como bytes, ou objetos binários (“blobs as files”) no Lance, junto com embeddings e dados escalares tradicionais — isso facilita a governança, o compartilhamento e a distribuição dos seus grandes conjuntos de dados via Hub.
- O indexamento é um cidadão de primeira classe (nativo ao próprio formato): o Lance vem com índices rápidos, em disco e escaláveis de vetores e FTS que ficam lado a lado com o conjunto de dados no Hub, permitindo que você compartilhe não apenas seus dados, mas também seus embeddings e índices, sem que seus usuários precisem recalculá-los.
- O esquema flexível e a evolução de dados permitem adicionar novas funcionalidades/colunas (tags de moderação, embeddings, etc.) de forma incremental, sem a necessidade de reescrever a tabela inteira.
Armazene todos os seus dados em um único local
No Lance, seus ativos de dados multimodais (imagens, áudio, vídeo) são armazenados como bytes brutos junto com seus metadados escalares e embeddings. Isso facilita a varredura e a filtragem do seu dataset em um único local, sem a necessidade de integrar múltiplos sistemas de armazenamento.
Faça streaming do Hub com datasets
Use load_dataset(..., streaming=True) para varrer e iterar pelos dados sem baixá-los localmente.
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"])Streaming é ótimo para amostrar metadados e entender o que você tem. Para busca vetorial ou para trabalhar com grandes blobs binários, você pode usar a API de dataset do Lance, explicada abaixo.
O streaming é rápido para amostrar metadados escalares simples, mas não é tão rápido para embeddings ou grandes ativos multimodais. Para trabalhar com grandes conjuntos de dados, é recomendado escanear os metadados, identificar os subconjuntos de que você precisa e baixar essa parte do dataset localmente para evitar enfrentar os limites de taxa do Hub:
hf download lance-format/laion-1m --repo-type dataset --local-dir ./laion
Faça streaming do Hub com lance.dataset
Você também pode escanear um dataset Lance armazenado no Hugging Face Hub usando o especificador de caminho hf://. Isso escaneia o dataset remoto sem exigir que você o baixe localmente. Usando a API de dataset do Lance, é muito simples definir limites, filtros e projeções para buscar apenas os dados de que você precisa.
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)Trabalhar com ativos binários
O exemplo abaixo mostra como as imagens são recuperadas de um dataset Lance como bytes JPEG brutos na coluna image e usadas a jusante.
Use ds.take para buscar os bytes e gravá-los em disco para que você possa usá-los em outros lugares.
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']}")Escreva um subconjunto para um novo dataset Lance
Trabalhando com grandes conjuntos de dados? É simples executar um scan filtrado para selecionar um subconjunto de linhas do Hub e materializá-las em um dataset Lance local.
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")Criar índice
Se o seu conjunto de dados ainda não tiver um índice associado, você pode criar um após baixá-lo localmente.
# ds is a local Lance dataset
ds.create_index(
"img_emb",
index_type="IVF_PQ",
num_partitions=256,
num_sub_vectors=96,
replace=True,
)Consulte a documentação do Lance sobre a criação de índices vetoriais para um exemplo mais detalhado. Depois de criar um índice vetorial, você pode executar a busca por similaridade nos dados por meio de embeddings.
Busca vetorial
Como os índices são cidadãos de primeira classe no Lance, você pode armazenar não apenas seus dados, mas também seus embeddings e índices juntos e consultá-los diretamente no Hub. Basta usar o método describe_indices() para listar as informações dos índices do dataset. Se um índice não existir no dataset, você pode usar lance.write_dataset() para gravar uma versão local do dataset e usar LanceDataset.create_index para criar um índice para suas necessidades.
O exemplo abaixo mostra um conjunto de dados para o qual já temos um índice vetorial no campo 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
#. )
# ]Você pode executar consultas de busca vetorial diretamente no dataset remoto sem baixá-lo (ou, se preferir, baixar o dataset localmente e criar um novo índice). O exemplo abaixo mostra como executar uma busca de vizinho mais próximo em um índice vetorial usando um embedding de imagem como vetor de consulta.
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()Definir um valor grande para
kounprobes, ou enviar um lote grande de consultas de uma só vez, pode atingir os limites de taxa do Hub. Para uso intenso, baixe o dataset (ou um subconjunto dele) localmente e aponte o Lance para o caminho local para evitar a limitação.
Evolução do conjunto de dados
Uma das funcionalidades mais poderosas do Lance é a evolução de dados flexível e sem custo, o que significa que você pode adicionar colunas derivadas sem reescrever a tabela original. Para tabelas muito grandes com muitos blobs de grande porte, as economias em I/O podem ser bastante significativas. Essa funcionalidade é muito relevante se você estiver experimentando com seus dados para tarefas de engenharia de ML/IA e frequentemente se encontrar adicionando novos recursos, embeddings ou metadados derivados.
O exemplo abaixo mostra como adicionar uma coluna derivada moderation_label que marca uma imagem como NSFW com base em uma coluna de pontuação existente. Ao fazer essa alteração, o backfill da nova coluna somente grava os dados da nova coluna, sem alterar os blobs de imagem originais ou os dados em outras colunas. Você também pode escolher adicionar apenas o esquema da nova coluna sem fazer o backfill de nenhum dado.
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"
}
)Consulte a documentação do Lance sobre evolução de dados para aprender a alterar e remover colunas em conjuntos de dados Lance.
Trabalhar com blobs de vídeo
As tabelas Lance também suportam blobs de vídeo grandes inline. O conjunto de dados OpenVid-1M (do este artigo) contém vídeos de alta qualidade e expressivos, juntamente com suas legendas. Os dados de vídeo estão armazenados na coluna video_blob do seguinte conjunto de dados Lance no Hub.
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()Diferentemente de outros formatos de dados, objetos binários multimodais grandes (blobs) são cidadãos de primeira classe no Lance. A API de blob fornece uma API de alto nível para armazenar e recuperar blobs grandes em conjuntos de dados Lance. O exemplo a seguir mostra como navegar eficientemente pelos metadados sem carregar os blobs de vídeo mais pesados e, em seguida, buscar os blobs de vídeo relevantes sob demanda.
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())Preparar dados para treinamento
O treinamento é outra área em que o rápido acesso aleatório e o desempenho de varredura do Lance podem ser úteis. Você pode usar conjuntos de dados Lance como mecanismo de armazenamento para seus dados de treinamento, embaralhando-os e carregando-os em lotes como parte de seus pipelines de treinamento.
A API de blobs no Lance é compatível com torchcodec, então você pode decodificar facilmente blobs de vídeo como tensores torch:
from torchcodec.decoders import VideoDecoder
decoder = VideoDecoder(blob_file)
tensor = decoder[0] # uint8 tensor of shape [C, H, W]Consulte a documentação do torchcodec para mais funções de decodificação eficiente de vídeos.
Além disso, você também pode consultar a documentação do Lance para mais exemplos sobre como carregar dados de imagem no torchvision para treinar seus próprios modelos de imagem.
Explore mais conjuntos de dados Lance
Lance é um formato aberto com suporte nativo para blobs multimodais ao lado dos seus dados tabulares tradicionais. Com a integração do Hugging Face Hub, você pode trabalhar facilmente com imagens, áudio, vídeo, texto, embeddings e metadados escalares, tudo em um só lugar.
Explore mais conjuntos de dados Lance no Hugging Face Hub e compartilhe seus próprios conjuntos de dados Lance com outros na comunidade! Você pode visitar lance.org para mais trechos de código e exemplos.
Update on GitHub