Парадокс мультимодальных датасетов: данные есть, а поделиться нельзя
Представьте ситуацию. Вы три месяца собирали датасет для обучения модели: 50 тысяч изображений, к каждому - текстовое описание, координаты bounding boxes, эмбеддинги от CLIP, метаданные. Всё лежит в папке на диске. Коллега из другого отдела просит дать доступ.
Что вы делаете? Архивируете 120 ГБ в tar.gz? Кидаете ссылку на S3? Пишете инструкцию на три страницы как распаковать, преобразовать, загрузить? Через неделю получаете вопрос: "А как мне достать только изображения с котами и их эмбеддинги?"
Проблема не в данных. Проблема в формате. Традиционные подходы - CSV, JSON, Parquet - не справляются с мультимодальностью. Изображения хранятся отдельно от текста, эмбеддинги - в отдельных файлах, индексы нужно строить заново. Каждый кто работает с датасетом тратит 80% времени на инфраструктуру и 20% - на анализ.
На 09.02.2026 стандарт де-факто для мультимодальных датасетов - формат Lance. Это не просто ещё один формат файлов. Это смена парадигмы в том, как мы думаем о данных для ML.
Что такое Lance и почему он меняет правила игры
Lance - колоночный формат хранения данных, созданный специально для ML-рабочих нагрузок. Не путайте с Parquet - у Lance другая философия.
Parquet оптимизирован для аналитики: агрегации, фильтрации, JOIN'ы. Lance оптимизирован для ML: векторный поиск, потоковая загрузка, мультимодальные данные.
Ключевые особенности Lance на 2026 год:
- Встроенные векторные индексы - не нужно перестраивать при каждом использовании
- Прямое хранение бинарных данных - изображения, аудио, видео внутри таблицы
- Мгновенные обновления - добавляйте данные без перезаписи всего файла
- Потоковый доступ - загружайте терабайты данных без скачивания на диск
Но самый важный момент: LanceDB (реализация формата Lance) теперь нативно интегрирован с Hugging Face Hub. Это меняет всё.
Hugging Face Hub становится платформой для данных, а не только для моделей
Раньше Hugging Face Hub был местом где хранят модели и датасеты в формате 🤗 Datasets. Теперь - это полноценная платформа для обмена мультимодальными данными в формате Lance.
Зачем это нужно? Представьте что вы публикуете датасет на HF Hub. Раньше пользователь должен был:
- Скачать весь датасет (даже если нужна только часть)
- Установить 🤗 Datasets
- Написать код для загрузки и преобразования
- Построить векторные индексы (если нужен семантический поиск)
Теперь с LanceDB на HF Hub:
- Подключаетесь к датасету как к базе данных
- Сразу получаете доступ к предварительно построенным индексам
- Фильтруете, ищете, выбираете только нужные данные
- Загружаете потоково без полного скачивания
Разница как между доставкой воды в бутылках и подключением к водопроводу.
Практика: создаём и публикуем мультимодальный датасет
Давайте создадим реальный пример: датасет скриншотов мобильных приложений с разметкой UI-элементов. Каждая запись содержит:
- Изображение скриншота (бинарные данные)
- Текстовое описание приложения
- Координаты UI-элементов (bounding boxes)
- Эмбеддинги изображения от Vision Transformer
- Метаданные: разрешение, ОС, время создания
1 Устанавливаем и настраиваем окружение
На 09.02.2026 актуальные версии:
pip install lancedb==0.8.4 huggingface-hub==1.0.0 pillow transformers torch
Внимание с версиями! huggingface-hub 1.0.0 содержит breaking changes по сравнению с 0.x. Если у вас старый код - смотрите наш гайд по переходу на v1.0. Основное изменение: новый API для работы с датасетами и моделями.
2 Создаём LanceDB таблицу с мультимодальными данными
Вот как НЕ надо делать (старый подход):
# ПЛОХО: раздельное хранение данных
import json
import pickle
# Изображения в папке images/
# Метаданные в metadata.json
# Эмбеддинги в embeddings.pkl
# Координаты в bboxes.json
# Чтобы получить полную запись нужно:
# 1. Прочитать metadata.json
# 2. Загрузить изображение из images/{id}.png
# 3. Найти эмбеддинг в embeddings.pkl
# 4. Найти bounding boxes в bboxes.json
# 4 разных файла, 4 операции ввода-вывода. Ужас.
А вот правильный подход с LanceDB:
# ХОРОШО: всё в одной таблице
import lancedb
from PIL import Image
import io
import json
# Создаём локальную базу данных
db = lancedb.connect("./data/lancedb")
# Определяем схему таблицы
schema = lancedb.schema([
lancedb.field("id", lancedb.types.string()), # Уникальный ID
lancedb.field("image", lancedb.types.binary()), # Бинарные данные изображения
lancedb.field("description", lancedb.types.string()), # Текстовое описание
lancedb.field("embedding", lancedb.types.vector(768)), # Вектор эмбеддинга
lancedb.field("bboxes", lancedb.types.string()), # JSON с координатами
lancedb.field("metadata", lancedb.types.string()) # JSON с метаданными
])
# Создаём таблицу
table = db.create_table("mobile_screenshots", schema=schema)
# Добавляем данные
records = []
for screenshot_data in collected_data:
# Загружаем изображение
with open(screenshot_data["image_path"], "rb") as f:
image_bytes = f.read()
# Генерируем эмбеддинг (упрощённо)
embedding = generate_embedding(screenshot_data["image_path"])
# Формируем запись
record = {
"id": screenshot_data["id"],
"image": image_bytes, # Бинарные данные прямо в таблице!
"description": screenshot_data["description"],
"embedding": embedding,
"bboxes": json.dumps(screenshot_data["bboxes"]),
"metadata": json.dumps({
"resolution": screenshot_data["resolution"],
"os": screenshot_data["os"],
"timestamp": screenshot_data["timestamp"]
})
}
records.append(record)
# Вставляем все записи одной операцией
table.add(records)
# Строим векторный индекс для быстрого поиска
table.create_index(
column="embedding",
index_type="IVF_PQ",
num_partitions=256,
num_sub_vectors=16
)
Ключевой момент: изображения хранятся прямо в таблице как бинарные данные. Не как ссылки на файлы, не как base64 строки - как настоящие бинарные данные. Это значит что когда вы делаете запрос к таблице, вы получаете изображение сразу, без дополнительных операций ввода-вывода.
3 Публикуем датасет на Hugging Face Hub
Раньше публикация датасета на HF Hub означала конвертацию в формат 🤗 Datasets. Теперь можно публиковать напрямую LanceDB таблицы.
from huggingface_hub import HfApi
import shutil
# 1. Сохраняем таблицу в формате Lance
table_path = "./data/lancedb/mobile_screenshots.lance"
# 2. Клонируем репозиторий датасета
from huggingface_hub import Repository
repo = Repository(
local_dir="./hf_dataset",
clone_from="your-username/mobile-screenshots-dataset",
repo_type="dataset",
use_auth_token=True # Токен из HF_TOKEN
)
# 3. Копируем Lance файлы в репозиторий
import os
os.makedirs("./hf_dataset/data", exist_ok=True)
shutil.copytree(table_path, "./hf_dataset/data/mobile_screenshots")
# 4. Создаём README с метаданными датасета
with open("./hf_dataset/README.md", "w") as f:
f.write("""---
license: apache-2.0
tags:
- computer-vision
- ui-detection
- multimodal
dataset_info:
features:
- name: id
dtype: string
- name: image
dtype: binary
- name: description
dtype: string
- name: embedding
dtype: float32
shape: [768]
- name: bboxes
dtype: string
- name: metadata
dtype: string
splits:
- name: train
num_bytes: 1240000000 # 1.24 GB
num_examples: 50000
---
# Mobile Screenshots Dataset
Датасет скриншотов мобильных приложений с разметкой UI-элементов.
## Использование
python
import lancedb
from huggingface_hub import hf_hub_download
# Загружаем датасет как LanceDB таблицу
db = lancedb.connect(hf_hub_download(
repo_id="your-username/mobile-screenshots-dataset",
filename="data/mobile_screenshots",
repo_type="dataset"
))
table = db.open_table("mobile_screenshots")
""")
# 5. Пушим на Hugging Face Hub
repo.push_to_hub()
Как другие будут использовать ваш датасет
Вот где проявляется магия интеграции LanceDB + HF Hub. Пользователь вашего датасета может:
1. Загрузить датасет как базу данных с предварительно построенными индексами
import lancedb
from huggingface_hub import hf_hub_download
# Скачиваем только метаданные датасета
lance_path = hf_hub_download(
repo_id="your-username/mobile-screenshots-dataset",
filename="data/mobile_screenshots",
repo_type="dataset",
local_dir="./cache" # Кэшируем локально
)
# Подключаемся как к базе данных
db = lancedb.connect(lance_path)
table = db.open_table("mobile_screenshots")
# Векторный поиск уже работает!
# Ищем похожие на эмбеддинг запроса
query_embedding = get_embedding("скриншот с кнопкой логина")
results = table.search(query_embedding).limit(10).to_list()
# results содержит полные записи с изображениями
for result in results:
image_bytes = result["image"] # Бинарные данные изображения
description = result["description"]
# ...
2. Использовать потоковый доступ без полного скачивания
Если датасет огромный (сотни ГБ), не нужно скачивать его целиком:
# Потоковый доступ к данным
# Загружаем только то, что нужно
streaming_table = table.to_streaming()
# Фильтруем по метаданным
filtered = streaming_table.filter("metadata->'os' = 'iOS'")
# Итерируемся по результатам
for batch in filtered.to_batches(batch_size=100):
# Обрабатываем batch из 100 записей
# Данные загружаются по мере необходимости
process_batch(batch)
3. Доставать только нужные колонки
Зачем загружать изображения если нужны только эмбеддинги?
# Выбираем только эмбеддинги и ID
embeddings_only = table.select(["id", "embedding"]).to_list()
# Или только метаданные
metadata_only = table.select(["id", "metadata"]).to_list()
Это колоночное хранение в действии. Данные физически организованы по колонкам, так что чтение только части колонок - эффективная операция.
Типичные ошибки и как их избежать
| Ошибка | Почему происходит | Как исправить |
|---|---|---|
| "ValueError: embedding dimension mismatch" | Размерность эмбеддингов в данных не совпадает с размерностью в схеме | Убедитесь что generate_embedding() возвращает вектор правильной длины (в примере - 768) |
| Датасет слишком большой для памяти | Попытка загрузить весь датасет разом вместо потокового доступа | Используйте .to_streaming() и работайте с батчами |
| Медленный векторный поиск | Индекс не построен или построен с неправильными параметрами | Постройте индекс с optimize_for="recall" для точности или "speed" для скорости |
| Ошибки при публикации на HF Hub | Новая версия huggingface-hub 1.0.0 имеет другой API | Смотрите гайд по переходу на v1.0 |
Зачем всё это нужно? Реальные use cases
Вы думаете: "Ну хорошо, технология крутая. Но где моя выгода?"
Вот конкретные сценарии где LanceDB + HF Hub решает реальные проблемы:
Сценарий 1: Обучение мультимодальных моделей
Вы собираете датасет для обучения модели типа CLIP или OpenCLIP. Нужны пары изображение-текст. С LanceDB вы:
- Храните изображения и тексты вместе
- Сразу имеете эмбеддинги для негативной семплизации
- Можете фильтровать данные по качеству (через метаданные)
- Делитесь готовым датасетом с коллегами одним URL
Сценарий 2: RAG (Retrieval-Augmented Generation) системы
Строите систему где LLM отвечает на вопросы по документам с изображениями. Например, техническая документация с скриншотами интерфейсов.
С традиционными подходами вам нужно:
- Хранить документы в одной системе
- Изображения - в другой
- Строить отдельные индексы для текста и изображений
- Склеивать результаты поиска
С LanceDB:
- Всё в одной таблице: текст, изображения, эмбеддинги
- Единый векторный индекс по мультимодальным эмбеддингам
- Один запрос находит релевантные тексты И изображения
- Публикуете готовую базу знаний на HF Hub для всей команды
Сценарий 3: Коллаборация над датасетами
Работаете в распределённой команде над улучшением датасета. Один добавляет новые изображения в Берлине, другой - разметку в Сан-Франциско, третий - исправления в Москве.
Раньше это был кошмар с merge conflict'ами в JSON файлах. Теперь:
- LanceDB поддерживает concurrent writes (с версии 0.8)
- Каждый работает со своей копией таблицы
- Изменения мержатся автоматически
- HF Hub синхронизирует версии
Это как Git для мультимодальных данных, только без головной боли.
Что будет дальше? Прогноз на 2026-2027
Интеграция LanceDB и Hugging Face Hub - только начало. Вот что ждёт нас в ближайшем будущем:
- Автоматическая оптимизация индексов - HF Hub будет анализировать запросы к вашему датасету и предлагать перестроить индексы с другими параметрами
- Кросc-датасетный поиск - поиск по всем датасетам на HF Hub одновременно, как сейчас ищут по моделям
- Встроенная разметка данных - инструменты для разметки прямо в интерфейсе HF Hub, с сохранением в Lance формат
- Интеграция с ML-пайплайнами - автоматическое обновление датасетов при обучении моделей, как в Lemonade v9.2 но для данных
Самое важное: формат Lance становится стандартом для мультимодальных данных в ML. Через год-два публиковать датасет в другом формате будет как отправлять документ в формате .doc в 2026 году - технически возможно, но все посмотрят на вас странно.
Совет напоследок: начните с миграции одного своего датасета в LanceDB. Не обязательно самого большого - возьмите тот, с которым чаще всего работаете. Прочувствуйте разницу в производительности, удобстве, возможности делиться. После этого вы не захотите возвращаться к старым форматам. Это как перейти с HDD на SSD - обратного пути нет.
P.S. Если вы работаете с генеративными моделями и собираете датасеты для fine-tuning (например, для LoRA обучения), LanceDB особенно полезен. Можете хранить prompt-output пары вместе с эмбеддингами, метаданными о качестве, версиями моделей. И всё это в одном месте, с возможностью семантического поиска по промптам.