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 est un format de table open source pour lakehouse multimodal destiné à l’IA. Vous pouvez utiliser des chemins Hugging Face (hf://) pour accéder aux jeux de données Lance sur le Hub. Cela vous permet d’analyser et de rechercher dans de grands jeux de données sur le Hugging Face Hub sans avoir à copier l’intégralité du jeu de données localement.

Premiers pas

Pour commencer, installez pylance et pyarrow avec pip :

pip install pylance pyarrow

Pourquoi Lance ?

  • Optimisé pour les charges de travail ML/IA : Lance est un format de colonnes moderne conçu pour un accès aléatoire rapide sans compromettre les performances de balayage, ce qui le rend utile pour la recherche, l’analyse, l’entraînement, l’ingénierie de caractéristiques et de nombreux autres cas d’usage.
  • Les actifs multimodaux sont stockés sous forme d’octets, ou d’objets binaires (« blobs as files ») dans Lance, aux côtés des embeddings et des données scalaires traditionnelles — ce qui facilite la gouvernance, le partage et la distribution de vos grands jeux de données via le Hub.
  • L’indexation est un élément de premier plan (natif du format lui-même) : Lance est livré avec des index vector et FTS rapides, sur disque et évolutifs, qui se trouvent juste à côté du jeu de données sur le Hub. Vous pouvez ainsi partager non seulement vos données, mais aussi vos embeddings et vos index, sans que vos utilisateurs aient à les recalculer.
  • Le schéma flexible et l'évolution des données vous permettent d'ajouter progressivement de nouvelles fonctionnalités/colonnes (balises de modération, embeddings, etc.) sans avoir à réécrire l'intégralité du tableau.

Stockez toutes vos données au même endroit

Dans Lance, vos actifs de données multimodales (images, audio, vidéo) sont stockés sous forme d'octets bruts, aux côtés de vos métadonnées scalaires et de vos embeddings. Cela facilite le balayage et le filtrage de votre jeu de données en un seul endroit, sans avoir à assembler plusieurs systèmes de stockage.

Diffusion en continu depuis le Hub avec datasets

Utilisez load_dataset(..., streaming=True) pour parcourir et itérer sur les données sans les télécharger localement.

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"])

Le streaming est idéal pour échantillonner les métadonnées afin de comprendre le contenu de vos données. Pour la recherche vectorielle ou le travail avec de gros blobs binaires, vous pouvez utiliser l'API dataset de Lance, décrite ci-dessous.

Le streaming est rapide pour l’échantillonnage de métadonnées scalaires simples, mais moins rapide pour les embeddings ou les actifs multimodaux volumineux. Pour travailler avec de grands jeux de données, il est recommandé de parcourir les métadonnées, d’identifier les sous-ensembles nécessaires et de télécharger cette partie du jeu de données localement afin d’éviter les limites de débit du Hub : hf download lance-format/laion-1m --repo-type dataset --local-dir ./laion

Flux depuis le Hub avec lance.dataset

Vous pouvez également scanner un jeu de données Lance stocké sur le Hugging Face Hub à l’aide du spécificateur de chemin hf://. Cette opération scanne le jeu de données distant sans nécessiter son téléchargement local. Grâce à l’API dataset de Lance, il est très simple de définir des limites, des filtres et des projections afin de ne récupérer que les données dont vous avez besoin.

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)

Travailler avec des actifs binaires

L’exemple ci-dessous montre comment les images sont récupérées depuis un jeu de données Lance sous forme d’octets JPEG bruts dans la colonne image, puis utilisées en aval. Utilisez ds.take pour récupérer les octets et les écrire sur le disque afin de pouvoir les utiliser ailleurs.

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']}")

Écrire un sous-ensemble dans un nouveau jeu de données Lance

Vous travaillez avec de grands jeux de données ? Il est simple d’exécuter un scan filtré pour sélectionner un sous-ensemble de lignes depuis le Hub et les matérialiser dans un jeu de données 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")

Créer un index

Si votre jeu de données n'a pas encore d'index associé, vous pouvez en créer un après l'avoir téléchargé localement.

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

Consultez la documentation Lance sur la création d’index vectoriels pour un exemple plus détaillé. Une fois un index vectoriel créé, vous pouvez effectuer une recherche de similarité sur les données via des embeddings.

Recherche vectorielle

Les index étant des citoyens de premier ordre dans Lance, vous pouvez stocker non seulement vos données, mais aussi vos embeddings et vos index ensemble, et les interroger directement sur le Hub. Utilisez simplement la méthode describe_indices() pour lister les informations d’index du jeu de données. Si un index n’existe pas dans le jeu de données, vous pouvez utiliser lance.write_dataset() pour écrire une version locale du jeu de données et utiliser LanceDataset.create_index pour créer un index adapté à vos besoins.

L'exemple ci-dessous montre un jeu de données pour lequel nous disposons déjà d'un index vectoriel sur le champ 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
#.   )
# ]

Vous pouvez exécuter des requêtes de recherche vectorielle directement sur le jeu de données distant sans le télécharger (ou, si vous préférez, télécharger le jeu de données localement et créer un nouvel index). L’exemple ci-dessous montre comment exécuter une recherche de plus proches voisins sur un index vectoriel en utilisant un embedding d’image comme vecteur de requête.

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()

Définir une valeur élevée pour k ou nprobes, ou envoyer un grand lot de requêtes d'un coup, peut atteindre les limites de débit du Hub. Pour une utilisation intensive, téléchargez le jeu de données (ou un sous-ensemble) localement et pointez Lance vers le chemin local pour éviter le ralentissement.

Évolution des jeux de données

L’une des fonctionnalités les plus puissantes de Lance est l’évolution des données flexible et sans surcoût, ce qui signifie que vous pouvez ajouter des colonnes dérivées sans réécrire la table d’origine. Pour les très grandes tables contenant de nombreux blobs volumineux, les gains en I/O peuvent être considérables. Cette fonctionnalité est particulièrement pertinente si vous expérimentez sur vos données pour des tâches d’ingénierie ML/IA et que vous ajoutez fréquemment de nouvelles caractéristiques, des embeddings ou des métadonnées dérivées.

L’exemple ci-dessous montre comment ajouter une colonne dérivée moderation_label qui marque une image comme NSFW sur la base d’une colonne de score existante. Lorsque vous apportez cette modification, le backfill de la nouvelle colonne uniquement écrit les données de la nouvelle colonne, sans toucher aux blobs d’images originaux ni aux données des autres colonnes. Vous pouvez également choisir d’ajouter simplement le schéma de la nouvelle colonne sans effectuer de backfill de données.

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"
    }
)

Consultez la documentation Lance sur l'évolution des données pour apprendre à modifier et supprimer des colonnes dans les jeux de données Lance.

Travailler avec des blobs vidéo

Les tables Lance prennent également en charge les blobs vidéo inline de grande taille. Le jeu de données OpenVid-1M (issu de cet article) contient des vidéos de haute qualité et expressives ainsi que leurs légendes. Les données vidéo sont stockées dans la colonne video_blob du jeu de données Lance suivant sur le 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()

Contrairement à d'autres formats de données, les objets binaires multimodaux volumineux (blobs) sont des citoyens de premier ordre dans Lance. L'API blob fournit une API de haut niveau pour stocker et récupérer de gros blobs dans les jeux de données Lance. L'exemple suivant montre comment parcourir efficacement les métadonnées sans charger les blobs vidéo plus lourds, puis récupérer les blobs vidéo pertinents à la demande.

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())

Préparer les données pour l'entraînement

L’entraînement est un autre domaine où les performances d’accès aléatoire et de balayage rapides de Lance peuvent s’avérer utiles. Vous pouvez utiliser les jeux de données Lance comme mécanisme de stockage pour vos données d’entraînement, en les mélangeant et en les chargeant par lots dans le cadre de vos pipelines d’entraînement.

L'API blob de Lance est compatible avec torchcodec, ce qui vous permet de décoder facilement les blobs vidéo en tenseurs torch :

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

Consultez la documentation de torchcodec pour d'autres fonctions permettant de décoder efficacement des vidéos.

En outre, vous pouvez également consulter la documentation Lance pour plus d'exemples sur le chargement de données d'images dans torchvision afin d'entraîner vos propres modèles d'images.

Explorer d'autres jeux de données Lance

Lance est un format ouvert avec un support natif pour les blobs multimodaux en plus de vos données tabulaires traditionnelles. Grâce à l’intégration avec le Hugging Face Hub, vous pouvez facilement travailler avec des images, de l’audio, de la vidéo, du texte, des embeddings et des métadonnées scalaires, le tout au même endroit.

Explorez davantage de jeux de données Lance sur le Hugging Face Hub, et partagez vos propres jeux de données Lance avec les autres membres de la communauté ! Vous pouvez consulter lance.org pour plus d’extraits de code et d’exemples.

Update on GitHub