English translation is not available yet. Showing Russian content.
Как вы делаете RAG для видео (индексация subshots, аудио, ключевые кадры)?
Краткий тезис
RAG для видео — это мультимодальная задача: видео содержит визуальный ряд (кадры), аудиодорожку (речь, звуки) и текстовые метаданные. Типичный пайплайн включает сегментацию видео на subshots, извлечение ключевых кадров (через CLIP или детекторы сцен), транскрипцию аудио (Whisper) и объединение эмбеддингов всех модальностей в единый вектор для поиска. Такой подход позволяет отвечать на вопросы по содержанию видео, используя как визуальную, так и текстовую информацию.
1. Термины: subshot, ключевой кадр, аудиоэмбеддинг
- Subshot (подсцена) — непрерывный фрагмент видео с минимальным изменением визуального содержания. Разбивка на subshots нужна, чтобы индексировать не всё видео целиком, а логические единицы (сцены, планы).
- Ключевой кадр (keyframe) — репрезентативный кадр subshot, который лучше всего описывает его визуальное содержание. Обычно выбирается центральный кадр или кадр с максимальной резкостью.
- Аудиоэмбеддинг — векторное представление аудиосегмента, полученное с помощью модели (например, Whisper, Wav2Vec2). Для RAG чаще используют текстовую транскрипцию (Whisper → текст → текстовый эмбеддинг), но можно и напрямую эмбеддинги аудио.
2. Этап 1: Сегментация видео на subshots
Цель — разбить видео на семантически однородные куски (сцены). Методы:
- На основе гистограмм кадров: сравниваем гистограммы соседних кадров (по цвету, яркости). Резкое изменение → граница subshot.
- PySceneDetect (Python-библиотека): использует детекторы
ContentDetector(по разнице кадров) иThresholdDetector(по яркости). - Глубокие модели: детекторы сцен на основе CNN (например, TransNetV2) — точнее, но тяжелее.
Пример кода с PySceneDetect:
from scenedetect import open_video, SceneManager, ContentDetector
video = open_video("lecture.mp4")
scene_manager = SceneManager()
scene_manager.add_detector(ContentDetector(threshold=30))
scene_manager.detect_scenes(video)
scene_list = scene_manager.get_scene_list() # список (start_time, end_time)
Результат: список временных интервалов (subshots). Для каждого subshot извлекаем ключевой кадр (например, средний по времени) и аудиосегмент.
3. Этап 2: Извлечение и эмбеддинг ключевых кадров
Для каждого subshot выбираем один или несколько ключевых кадров. Затем получаем их визуальные эмбеддинги с помощью CLIP (Contrastive Language–Image Pre-training) — модели, которая проецирует изображения и текст в общее пространство.
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():
image_features = model.encode_image(image)
image_features /= image_features.norm(dim=-1, keepdim=True)
Эмбеддинг ключевого кадра — вектор фиксированной размерности (например, 512 для ViT-B/32). Если subshot длинный, можно взять несколько кадров и усреднить их эмбеддинги (или использовать attention).
4. Этап 3: Обработка аудио (Whisper + эмбеддинг)
Аудиодорожку subshot транскрибируем в текст с помощью Whisper (OpenAI). Полученный текст эмбеддируем той же моделью, что и текстовые запросы (например, sentence-transformers/all-MiniLM-L6-v2 или CLIP text encoder).
import whisper
from sentence_transformers import SentenceTransformer
model_whisper = whisper.load_model("base")
result = model_whisper.transcribe("subshot_audio.wav")
text = result["text"]
text_embedder = SentenceTransformer("all-MiniLM-L6-v2")
text_embedding = text_embedder.encode(text)
Если аудио содержит не только речь (музыка, шумы), можно добавить аудиоэмбеддинги (например, через Wav2Vec2) и объединить их с текстовыми.
5. Этап 4: Объединение эмбеддингов (fusion)
У нас есть визуальный эмбеддинг (из ключевых кадров) и текстовый эмбеддинг (из транскрипции). Нужно получить единый вектор для subshot. Основные стратегии:
| Метод | Описание | Плюсы | Минусы |
|---|---|---|---|
| Concatenation | Конкатенация векторов | Простота, сохраняет все признаки | Размерность растёт, может быть избыточно |
| Weighted average | Взвешенное среднее (например, 0.7 визуальный + 0.3 текстовый) | Гибкость, настраивается под данные | Веса нужно подбирать |
| Attention fusion | Обучаемый механизм cross-attention между модальностями | Учитывает взаимосвязь | Требует данных для обучения |
| Late fusion | Поиск отдельно по визуальным и текстовым эмбеддингам, затем объединение рангов | Простота, не требует единого вектора | Два запроса к БД, сложнее ранжирование |
Пример взвешенного среднего (после нормализации):
vis_emb = image_features / image_features.norm()
txt_emb = torch.tensor(text_embedding)
txt_emb = txt_emb / txt_emb.norm()
alpha = 0.6
combined_emb = alpha * vis_emb + (1 - alpha) * txt_emb
combined_emb = combined_emb / combined_emb.norm()
Полученные векторы индексируются в векторной БД (FAISS, Milvus, Qdrant) вместе с метаданными (время начала/конца subshot, ссылка на видео).
6. Поиск и генерация ответа
На этапе inference пользователь задаёт текстовый вопрос. Его эмбеддим той же текстовой моделью (например, CLIP text encoder или sentence-transformer). Ищем ближайшие векторы subshots в БД по косинусной близости. Возвращаем top-k subshots.
Далее возможны два подхода:
- Прямая генерация: передаём LLM транскрипцию + описание ключевых кадров (через captioning) как контекст.
- Мультимодальный LLM: используем модель, которая принимает и текст, и изображения (например, GPT-4V, LLaVA). Тогда в контекст можно добавить сами ключевые кадры.
7. Проблемы и их решения
| Проблема | Решение |
|---|---|
| Синхронизация аудио и видео | Использовать временные метки subshot как единую ось; аудио и видео обрабатываются для одного интервала |
| Шум в аудио | Применять фильтрацию (noise reduction) перед Whisper; использовать субтитры, если есть |
| Длинные видео | Индексировать только subshots, а не всё видео; использовать иерархическую индексацию (сцена → subshot) |
| Разные модальности не совпадают по смыслу | Например, ведущий говорит одно, а на экране другое. Тогда weighted average может размыть семантику. Лучше late fusion или обучаемый fusion |
| Масштабирование | Для тысяч часов видео — распределённая обработка (Spark, Ray), параллельное эмбеддирование |
8. Метрики оценки видео RAG
Оффлайн-метрики (на размеченном датасете запросов и релевантных subshots):
- Hit Rate@k — доля запросов, для которых хотя бы один релевантный subshot попал в top-k.
- MRR — средний обратный ранг первого релевантного subshot.
- Recall@k — доля всех релевантных subshots, найденных в top-k.
Онлайн-метрики (с LLM):
- Faithfulness — насколько ответ LLM соответствует найденным subshots (не галлюцинирует).
- Answer relevance — насколько ответ отвечает на вопрос пользователя.
- Context relevance — насколько найденные subshots релевантны запросу.
Инструменты: RAGAS, TruLens, DeepEval.
9. Инструменты и библиотеки
| Задача | Инструмент |
|---|---|
| Сегментация видео | PySceneDetect, TransNetV2 |
| Визуальные эмбеддинги | CLIP (OpenAI), DINOv2, VideoCLIP |
| Транскрипция аудио | Whisper (OpenAI), Wav2Vec2, Google Speech-to-Text |
| Текстовые эмбеддинги | sentence-transformers, CLIP text encoder |
| Векторная БД | FAISS, Milvus, Qdrant, Pinecone |
| Мультимодальный LLM | GPT-4V, LLaVA, Gemini Pro Vision |
10. Сравнение с текстовым RAG
| Аспект | Текстовый RAG | Видео RAG |
|---|---|---|
| Входные данные | Текст (документы, чанки) | Видео (кадры, аудио, субтитры) |
| Модальности | Одна (текст) | Три (визуал, аудио, текст) |
| Сложность индексации | Низкая (разбить текст на чанки) | Высокая (сегментация, извлечение кадров, аудио) |
| Размер данных | Относительно мал | Огромный (видеофайлы) |
| Метод fusion | Не нужен | Обязателен (объединение модальностей) |
| LLM на выходе | Текстовый LLM | Мультимодальный LLM или текстовый + captioning |
Пет-проект для закрепления
Задача: Создать систему поиска по видео-лекциям (например, по курсу на YouTube). Пользователь задаёт вопрос, система находит релевантный фрагмент видео и возвращает его с таймкодом и кратким ответом.
Инструменты: Python, PySceneDetect, CLIP, Whisper, sentence-transformers, FAISS, Streamlit (UI).
Шаги:
- Скачать 5–10 видео-лекций (можно короткие, по 10–20 минут).
- Разбить каждое видео на subshots с помощью PySceneDetect (порог 30–40).
- Для каждого subshot извлечь ключевой кадр (средний по времени) и сохранить как JPEG.
- Транскрибировать аудио subshot через Whisper (модель
base). - Получить визуальный эмбеддинг ключевого кадра через CLIP (ViT-B/32).
- Получить текстовый эмбеддинг транскрипции через
all-MiniLM-L6-v2. - Объединить эмбеддинги взвешенным средним (α=0.5) и нормализовать.
- Индексировать все векторы в FAISS (IndexFlatIP).
- Написать простой веб-интерфейс на Streamlit: поле ввода вопроса, кнопка поиска, вывод top-3 subshots с таймкодами и транскрипцией.
- Оценить качество на 10–20 тестовых вопросах вручную.
Ожидаемый результат: Работающий прототип, который на вопрос "Что такое attention?" находит фрагмент лекции, где объясняется attention, и показывает его текст и время.
Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 365 | Как делать RAG для изображений? |
| 367 | Как делать RAG для аудио? |
| 370 | Что такое мультимодальный RAG? |
| 371 | Как объединять результаты из разных модальностей? |
| 372 | Какие метрики для мультимодального RAG? |
| 373 | Как обрабатывать длинные видео (часы)? |
Навигация
- Предыдущий: 365
- Следующий: 367
- Индекс: 00. Индекс разборов