English translation is not available yet. Showing Russian content.
Как вы индексируете видео-контент в RAG-системе?
Краткий тезис
Индексация видео в RAG — это мультимодальная задача, требующая извлечения и объединения информации из визуального ряда, аудиодорожки и возможных текстовых субтитров. Основной подход: разбить видео на сцены (шоты), из каждого шота взять ключевой кадр для визуального эмбеддинга (CLIP), транскрибировать аудио (Whisper) для текстового эмбеддинга, затем объединить их взвешенным средним или attention fusion и сохранить в векторную БД с метаданными (timestamp, источник, спикер). Это позволяет отвечать на вопросы по содержанию видео, искать моменты по описанию и строить агентные системы, работающие с видеоконтентом.
1. Термин: Индексация видео в RAG
Индексация видео — процесс преобразования неструктурированного видеопотока в набор поисковых векторов (эмбеддингов) и метаданных, которые можно хранить в векторной базе данных и использовать для retrieval.
В отличие от текстовых документов, видео содержит несколько модальностей:
- Визуальный ряд (кадры, объекты, сцены)
- Аудиодорожка (речь, звуки, музыка)
- Текст (субтитры, OCR-текст на экране)
Задача RAG-системы — по текстовому запросу пользователя найти релевантный фрагмент видео и вернуть его вместе с контекстом (например, таймкод, скриншот, транскрипцию).
2. Детекция сцен (Scene Detection)
Первый шаг — разбить видео на логические сегменты (шоты). Шот — непрерывная последовательность кадров, снятая одной камерой без монтажного склея.
Инструменты
- PySceneDetect (Python) — детектор сцен по резкому изменению гистограммы или контента.
- FFmpeg с фильтром
scene— быстрый, но менее точный. - Глубокие методы (например, TransNetV2) — для сложных переходов (затемнения, наплывы).
Параметры
- Порог чувствительности (threshold) — чем ниже, тем больше шотов.
- Обычная длительность шота: 2–5 секунд (для новостей/лекций) или до 10–15 секунд (для фильмов).
Пример кода (PySceneDetect):
from scenedetect import detect, ContentDetector, split_video_ffmpeg
scene_list = detect("video.mp4", ContentDetector(threshold=27))
for i, scene in enumerate(scene_list):
print(f"Scene {i}: {scene[0].get_timecode()} -> {scene[1].get_timecode()}")
После детекции каждый шот становится единицей индексации (чанком видео).
3. Извлечение ключевых кадров
Для каждого шота нужно выбрать один или несколько ключевых кадров (keyframes), которые репрезентируют визуальное содержание.
Методы
- Центральный кадр — кадр посередине шота (просто, но может быть неинформативным).
- Кадр с максимальным изменением — кадр, наиболее отличающийся от предыдущего (например, по гистограмме).
- Кадр с максимальной чёткостью — оценка резкости (Laplacian variance) для выбора самого чёткого кадра.
- Кластеризация — все кадры шота эмбеддируются (например, через CLIP) и выбирается центроид.
Рекомендация для большинства сценариев достаточно одного ключевого кадра на шот (центральный или с максимальной чёткостью). Для длинных шотов (>10 сек) можно взять 2–3 кадра.
4. Визуальные эмбеддинги (CLIP)
Ключевой кадр подаётся в мультимодальную модель CLIP (Contrastive Language-Image Pre-training) для получения визуального эмбеддинга.
Почему CLIP
- Обучался на парах (изображение, текст) — эмбеддинги изображения и текста находятся в общем пространстве.
- Позволяет искать видео по текстовому описанию (например, "человек в красной шляпе").
- Размер эмбеддинга: 512 (ViT-B/32) или 768 (ViT-L/14).
Альтернативы
- ImageBind (Meta) — объединяет 6 модальностей (изображение, текст, аудио, видео, depth, thermal).
- VideoCLIP — учитывает временную динамику (но сложнее в индексации).
Пример (CLIP):
import clip
import torch
from PIL import Image
model, preprocess = clip.load("ViT-B/32")
image = preprocess(Image.open("keyframe.jpg")).unsqueeze(0)
with torch.no_grad():
embedding = model.encode_image(image) # shape (1, 512)
Эмбеддинг нормализуется (L2) для косинусного поиска.
5. Аудиодорожка: транскрипция через Whisper
Параллельно с визуальным рядом обрабатывается аудиодорожка. Основная цель — получить текстовую транскрипцию речи.
Инструмент: Whisper (OpenAI) — модель для распознавания речи (ASR), поддерживает 100+ языков, выдаёт таймкоды для каждого слова.
Процесс
- Извлечь аудио из видео (ffmpeg -i video.mp4 -vn audio.wav).
- Разбить аудио на сегменты, соответствующие шотам (по таймкодам сцен).
- Транскрибировать каждый сегмент через Whisper.
- Получить текст и таймкоды слов.
Пример (Whisper):
import whisper
model = whisper.load_model("base")
result = model.transcribe("audio.wav", word_timestamps=True)
for segment in result["segments"]:
print(segment["start"], segment["end"], segment["text"])
Важно Whisper может работать на GPU, но для больших объёмов лучше использовать оптимизированные рантаймы (whisper.cpp, faster-whisper).
6. Текстовые эмбеддинги
Транскрибированный текст каждого шота превращается в текстовый эмбеддинг с помощью той же модели, что используется для текстовых запросов (например, text-embedding-3-small от OpenAI или intfloat/e5-mistral-7b-instruct).
Особенности
- Текст может быть коротким (2–5 секунд речи) — используйте модель, хорошо работающую с короткими фрагментами.
- Если в шоте нет речи (музыка, тишина) — текстовый эмбеддинг можно пропустить или использовать пустой вектор.
Пример (OpenAI):
from openai import OpenAI
client = OpenAI()
response = client.embeddings.create(
input="Транскрипция шота",
model="text-embedding-3-small"
)
text_emb = response.data[0].embedding
7. Объединение модальностей (Fusion)
Теперь у нас есть два эмбеддинга на один шот: визуальный (CLIP) и текстовый (Whisper). Их нужно объединить в один вектор для индексации.
Методы объединения
| Метод | Описание | Плюсы | Минусы |
|---|---|---|---|
| Взвешенное среднее | emb = α * vis_emb + (1-α) * text_emb | Просто, интерпретируемо | Вес α подбирается эмпирически |
| Конкатенация | emb = concat(vis_emb, text_emb) | Сохраняет всю информацию | Удваивает размерность, требует переобучения модели поиска |
| Attention fusion | Обучаемый слой cross-attention между модальностями | Адаптивен к контексту | Требует данных для обучения |
| Late fusion | Два отдельных индекса, поиск по каждой модальности отдельно, затем ранжирование | Гибкость | Двойное хранение, сложнее запрос |
Рекомендация для старта используйте взвешенное среднее с α=0.6 для текста и 0.4 для визуала (текст обычно информативнее). Если визуал критичен (например, поиск по жестам), увеличьте вес визуала.
Пример (взвешенное среднее):
import numpy as np
alpha = 0.6
combined_emb = alpha * text_emb + (1 - alpha) * vis_emb
combined_emb = combined_emb / np.linalg.norm(combined_emb) # нормализация
8. Индексация в векторной базе данных
Каждый шот сохраняется как запись в векторной БД (Pinecone, Qdrant, Weaviate, Milvus, FAISS). Поля:
id— уникальный идентификатор шота (например,video_id_scene_num).- vector — объединённый эмбеддинг (нормализованный).
- metadata:
video_source— имя файла или URL.start_time,end_time— таймкоды в секундах.scene_index— номер шота.transcript— полный текст транскрипции.- speaker — если есть диаризация (кто говорит).
keyframe_path— путь к сохранённому ключевому кадру (опционально).visual_embedding— отдельно визуальный эмбеддинг (для гибридного поиска).
Пример записи (JSON):
{
"id": "lecture1_scene42",
"vector": [0.123, -0.456, ...],
"metadata": {
"video_source": "lecture1.mp4",
"start_time": 125.3,
"end_time": 128.7,
"transcript": "Теперь рассмотрим градиентный спуск",
"speaker": "Профессор Иванов",
"keyframe_path": "keyframes/lecture1_scene42.jpg"
}
}
Индексация используйте HNSW (Hierarchical Navigable Small World) для быстрого приближённого поиска (ANN). Настройте ef_construction и M под размер данных.
9. Метаданные и таймстемпы
Метаданные критичны для ответа пользователю. После retrieval нужно не только вернуть текст, но и указать точное время в видео.
Дополнительные метаданные
- Диаризация спикеров — разделение речи по говорящим (модели
pyannote-audio). Позволяет искать по фразам конкретного человека. - OCR-текст — если в видео есть текст на экране (слайды, титры). Используйте PaddleOCR или Tesseract на ключевых кадрах.
- Эмбеддинги звуков — для поиска по неречевым звукам (аплодисменты, музыка). Можно использовать CLAP (Contrastive Language-Audio Pretraining).
Пример использования таймкода в ответе
"Вот фрагмент видео с 2:05 по 2:08, где профессор объясняет градиентный спуск."
10. Продвинутые техники
10.1 Иерархическая индексация
Видео разбивается на несколько уровней: всё видео → главы → сцены → кадры. Поиск сначала на уровне глав, затем уточнение.
10.2 Гибридный поиск (визуал + текст)
При запросе можно вычислять два эмбеддинга (текстовый и визуальный) и искать отдельно, затем объединять результаты через weighted sum или Reciprocal Rank Fusion (RRF).
10.3 Агентный подход
Агент может сначала определить, нужен ли визуальный контекст (например, запрос "как выглядит график?"), и выбрать соответствующую модальность для поиска.
10.4 Сжатие эмбеддингов
Для больших коллекций видео используйте Product Quantization (PQ) для уменьшения размера векторов без сильной потери качества.
11. Проблемы и компромиссы
| Проблема | Решение |
|---|---|
| Шум в транскрипции (акцент, фон) | Использовать Whisper large-v3, постобработка (LLM для исправления) |
| Пустые шоты (только музыка) | Пропускать или добавлять аудио-эмбеддинг (CLAP) |
| Дублирование информации (один и тот же текст в нескольких шотах) | Дедупликация по эмбеддингам (cosine similarity > 0.95) |
| Скорость индексации | Параллельная обработка шотов, GPU для CLIP и Whisper |
| Хранение ключевых кадров | Сжимать в WebP, хранить в object storage (S3) |
Пет-проект для закрепления
Задача Создать RAG-систему для поиска по лекциям на YouTube (10–20 видео).
Инструменты
- yt-dlp — скачивание видео и аудио.
- PySceneDetect — детекция сцен.
CLIP(OpenAI CLIP илиopen_clip) — визуальные эмбеддинги.faster-whisper— транскрипция.Qdrant(in-memory) — векторная БД.LangChainили простой FastAPI — orchestration.
Шаги:
- Скачать 5–10 видео-лекций (например, по машинному обучению).
- Разбить каждое на шоты (порог 27).
- Для каждого шота извлечь ключевой кадр (центральный) и транскрипцию.
- Получить визуальный эмбеддинг (CLIP) и текстовый (e5-small).
- Объединить взвешенным средним (α=0.6).
- Загрузить в Qdrant с метаданными (таймкод, источник, текст).
- Написать простой интерфейс: пользователь вводит запрос, система возвращает top-3 шота с таймкодами и ссылками на видео.
Ожидаемый результат Работающий сервис, который на запрос "градиентный спуск" находит точные моменты в лекциях, показывает скриншот и текст. Можно добавить оценку качества (HR@5, MRR) на размеченных 20 запросах.
Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 1 | Как спроектировать RAG-систему для 10 000 документов |
| 3 | Стратегии chunking'а (аналогия с разбивкой на шоты) |
| 5 | Оценка качества retrieval (применимо к видео) |
| 7 | Уменьшение latency (оптимизация CLIP/Whisper) |
| 10 | Self-RAG (можно адаптировать для видео) |
| 12 | Мультимодальные RAG (общая теория) |
Навигация
- Предыдущий: 545
- Следующий: 547
- Индекс: 00. Индекс разборов