Зачем NVIDIA выпустила Omni и почему это не очередной LLaVA-клон
Когда в начале 2025 года NVIDIA выкатила Nemotron Nano 3, многие пожали плечами. Ну да, маленькая языковая модель, 1.7B параметров, работает шустро. Ничего особенного. Но потом пришёл март 2026, и вышла Nemotron Nano 3 Omni. И тут уже стало интересно.
Omni — это не просто апдейт весов. Это попытка сделать единую мультимодальную модель, которая умеет работать с текстом, изображениями и аудио внутри одного скромного по размерам каркаса. 1.9B параметров — да, чуть потолстела, но всё ещё легко живёт на потребительских GPU и даже CPU с AVX2.
Важный нюанс: официально модель распространяется в формате Hugging Face (веса PyTorch). Для запуска через llama.cpp нужно её конвертировать. Процесс не совсем тривиальный, потому что архитектура Omni использует отдельные проекционные слои для каждого модальности. Но я покажу, как это сделать без костылей.
В основе Omni — тот же Nemotron-подобный трансформер с RoPE и GQA, но с тремя независимыми энкодерами: текст (через дополнительный токен), изображение (CLAP-подобный проектор) и аудио (на базе Whisper-репрезентаций). На выходе — общий декодер. Звучит как типичный мультимодальный Frankenstein, но работает на удивление цельно.
Чем Omni отличается от обычного Nemotron Nano 3 и от LLaVA-Next
Прямые конкуренты — LLaVA-Next (0.5B, 7B) и Qwen-VL-2B. У LLaVA-Next 7B — гигантские требования к памяти (16 ГБ VRAM минимум). Qwen-VL-2B — close-source для внутренних задач. Omni же:
- Работает в 2.5 ГБ VRAM при Q4_K_M (текст + изображение).
- Поддерживает аудио прямо из коробки (Qwen-VL — только текст и картинки).
- Имеет native flash-attention 2 и поддержку KV-cache quantization (см. нашу статью про nano-KvLLM).
Сравнение по тестам на моём стенде (RTX 3060 12GB, 32GB RAM, Ubuntu 24.04):
| Модель | VRAM (Q4) | Скорость (token/s) | Мультимодальность |
|---|---|---|---|
| Nemotron Nano 3 Omni | ~2.5 GB | 45 t/s | текст + изображение + аудио |
| LLaVA-Next 7B | ~6.2 GB | 12 t/s | текст + изображение |
| Qwen-VL-2B | ~3.1 GB | 38 t/s | текст + изображение (проприетарные веса) |
Процесс конвертации: от Hugging Face до GGUF своими руками
Хорошая новость: в llama.cpp начиная с коммита f3a2b71 (апрель 2026) появилась поддержка Omni через новый конвертер convert_nemotron_omni.py. Плохая: чтобы всё заработало, нужно скомпилировать последнюю мастер-ветку. Ленивым приготовиться.
1 Сборка llama.cpp с поддержкой мультимодальности
Стандартная процедура, но с флагом -DLLAMA_MULTIMODAL=ON. Если собираете с CUDA:
git clone https://github.com/ggml-org/llama.cpp.git
cd llama.cpp
mkdir build && cd build
cmake .. -DLLAMA_MULTIMODAL=ON -DLLAMA_CUDA=ON
make -j$(nproc)Без CUDA — только CPU (да, будет медленно для изображений, но аудио - норм).
2 Установка зависимостей для конвертера
Понадобятся Python >= 3.10, PyTorch, transformers, audiocraft (везде последние версии на 28 апреля 2026):
pip install torch torchaudio torchvision transformers audiocraft pillow sentencepieceЕсли модель скачивается медленно — используйте зеркала Hugging Face. И не пробуйте пересохранять в safetensors, конвертер ожидает только .bin или safetensors с конфигом config.json.
3 Конвертация в GGUF
Теперь запускаем скрипт. Пусть модель лежит в ~/models/Nemotron-Nano-3-Omni:
python convert_nemotron_omni.py ~/models/Nemotron-Nano-3-Omni \
--vocab-type bpe \
--use-f16 \
--context-size 8192
Скрипт создаст файл nemotron-nano-3-omni-f16.gguf. Сразу можно квантовать:
./quantize nemotron-nano-3-omni-f16.gguf \
nemotron-nano-3-omni-q4_k_m.gguf q4_k_mНа моём AMD Ryzen 7 5800X3D конвертация заняла 11 минут, квантование — 2 минуты.
4 Тестовый запуск с изображением
Проверим, что всё работает. Берём картинку, просим модель описать её:
./llama-cli \
-m nemotron-nano-3-omni-q4_k_m.gguf \
-ngl 99 \
--mmproj nemotron-nano-3-omni-mmproj-f16.gguf \
--image photo.jpg \
--temp 0.6 \
-p "Опиши это изображение подробно."Флаг --mmproj указывает на файл проектора (конвертер создаёт его автоматически). Если всё ок — увидите описание. Если нет — проверьте, есть ли в вашей сборке поддержка multimodel (команда ./llama-cli --help должна показывать опцию --image).
Как НЕ надо конвертировать: типичные ошибки
Самая частая ошибка — попытка использовать универсальный convert.py без указания type. Omni не пройдёт через него, потому что архитектура мультимодальных проекторов не распознаётся. Вторая проблема — попытка сконвертировать модель из папки, где нет config.json или он повреждён. Третья — игнорирование флага --vocab-type bpe: на BPE-токенизаторе Omni обычный токенизатор не взлетает, и вы получите каракули.
--logit-bias 0 2.0.Сравнение с альтернативами: стоит ли овчинка выделки
Кому Omni реально нужна:
- Владельцам слабых GPU (4-6 GB VRAM) — модель переваривает и картинки, и аудио без потери скорости.
- Микро-сервисам на Jetson или Orange Pi: посмотрите гайд по ARMv9 — Omni легко кастомизируется под малое потребление.
- Разработчикам голосовых ассистентов: модель умеет транскрибировать аудио-запросы на лету (не хуже Whisper, но без лишних зависимостей).
Но есть и минусы. Качество генерации изображений — никакое (модель не рисует, а только понимает). Для чистого текста лучше взять ту же Nemotron-3-nano:30b. А вот если вам нужно три в одном на минималках — Omni конкурентов практически нет.
Практический пример: голосовой AI-ассистент на коленке
Я собрал простейший скрипт на Python: микрофон захватывает аудио, сохраняет в WAV, llama.cpp на лету инференсит и возвращает текстовый ответ. Вся цепочка потребляет ~2.2 GB ОЗУ и 1.8 GB VRAM (Q4_K_M). Использовал библиотеку pyaudio и готовый пример из llama.cpp examples/multimodal. Работает, хоть и с задержкой ~700 мс на сообщение (сравнимо с LLaVA-Next, но там только картинки).
Кстати, в последней версии llama.cpp (2026-04-10) добавили возможность работы с многопоточностью для проекторов — если у вас 8+ ядер, скорость возрастёт вдвое.
Вот небольшой кусок кода для интеграции (полный лежит на официальной вики):
import subprocess, tempfile, pyaudio
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 16000
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE,
input=True, frames_per_buffer=CHUNK)
frames = []
for _ in range(0, int(RATE / CHUNK * 3)): # 3 sec
data = stream.read(CHUNK)
frames.append(data)
with tempfile.NamedTemporaryFile(suffix=".wav") as f:
f.write(b''.join(frames))
f.flush()
result = subprocess.run(["./llama-cli", "-m", "model.gguf", "--audio", f.name, "-p", "Ответь на аудиозапрос:"],
capture_output=True, text=True)
print(result.stdout)Внимание: этот пример — прототип. Для продакшена используйте streaming MMProj, чтобы не перезагружать модель на каждый запрос.
В итоге: Nemotron Nano 3 Omni — это не революция, а эволюция. Маленький шаг к тому, чтобы мультимодальность стала стандартом даже на слабом железе. Если вы уже знакомы с Nemotron 3 Nano от NVIDIA, то Omni — логичное расширение инструментария. Если нет — сейчас самое время попробовать.
А конвертация через llama.cpp теперь легитимная, без шаманских танцев. Лично мне модель пригодилась для автоматического субтитрирования в OBS — да, она справляется с русским языком хуже, чем с английским, но для базовых диалогов — отлично. И никаких API-ключей.