Модели «зрение + язык»
Как картинка превращается в токены (ViT), как CLIP учит картинки и тексты жить в одном пространстве, как устроены VLM вроде Qwen-VL и InternVL и что такое «оптическое сжатие контекста» DeepSeek-OCR.
Зачем это нужно
Заголовок раздела «Зачем это нужно»Всё, что мы строили до сих пор, работало с текстом. Но флагманы 2026 года — Qwen3.5, Kimi K2.5, MiniMax M3 — нативно мультимодальныемультимодальныйEN multimodal: они читают скриншоты, графики, сканы договоров и кадры видео. Агент из модуля 8.3, который «видит» экран, и RAG из модуля 8.2 по PDF с таблицами — это всё работа зрения.
Хорошая новость: нового «зоопарка» архитектур учить не придётся. Картинку режут на кусочки, каждый кусочек превращают в вектор — и дальше работает тот же трансформер, что вы собрали на ступени 4. Весь урок — про три идеи: как сделать из картинки токены (ViT), как научить эти токены «понимать» язык (CLIP) и как пристегнуть их к LLM (VLM). В конце разберём свежую и спорную идею DeepSeek: хранить длинный текст в виде картинки.
Картинка как последовательность: ViT
Заголовок раздела «Картинка как последовательность: ViT»Интуиция
Заголовок раздела «Интуиция»Трансформер умеет работать с последовательностью векторов. Текст мы превращали в последовательность токенов (урок 4.2). Для картинки авторы Vision Transformer (ViT)визуальный трансформер (ViT)EN Vision Transformer (ViT)картинка режется на патчи, каждый патч становится токеном (Google, 2020) предложили самое простое решение — название статьи говорит само за себя: «Картинка стоит 16×16 слов».
- Режем картинку на квадратные патчипатч изображенияEN image patchквадратный кусок картинки (обычно 14×14 или 16×16 пикселей), «слово» для ViT, например 16×16 пикселей.
- Каждый патч вытягиваем в вектор: чисел (три канала RGB).
- Умножаем на обучаемую матрицу — получаем эмбеддингэмбеддинг, векторное представлениеEN embedding патча.
- Прибавляем позиционный эмбеддинг (иначе модель не знает, где был патч — та же проблема, что в уроке 4.5.2).
- Подаём последовательность в обычный энкодер трансформера. Маски нет: каждый патч «смотрит» на все остальные.
Для картинки 224×224 и патча 16 получаем сетку патчей. Это 196 «слов» — короткая фраза по меркам LLM.
Сколько токенов «стоит» картинка
Заголовок раздела «Сколько токенов «стоит» картинка»Число визуальных токенов — главный параметр стоимости VLM: они занимают место в контексте и в KV-кэшеKV-кэшEN KV cache точно так же, как текст.
| Модель | Вход | Патч | Патчей | Сжатие | Токенов в LLM |
|---|---|---|---|---|---|
| ViT-B/16 | 224×224 | 16 | 196 | — | 196 |
| CLIP ViT-L/14 (LLaVA-1.5) | 336×336 | 14 | 576 | — | 576 |
| Qwen2-VL | 224×224 | 14 | 256 | слияние 2×2 | 64 + 2 служебных = 66 |
| InternVL 1.5 (один тайл) | 448×448 | 14 | 1024 | pixel shuffle, в 4 раза | 256 |
| DeepSeek-OCR, режим Base | 1024×1024 | 16 | 4096 | свёрточное, в 16 раз | 256 |
Обратите внимание на последнюю строку. Без сжатия страница документа в 1024×1024 дала бы 4096 токенов, а внимание стоит : это 16.7 млн пар «патч — патч» на один слой. Поэтому почти все современные VLM так или иначе сжимают визуальные токены.
Патч-эмбеддинг — это свёртка
Заголовок раздела «Патч-эмбеддинг — это свёртка»В реальном коде ViT вы не найдёте цикла по патчам. Нарезка плюс линейный слой — это ровно свёртка с ядром и шагом : окно свёртки не перекрывается и «смотрит» на один патч (размерности свёртки и её запись через матричное умножение — в уроке 3.5.1). Проверим, что два способа дают одно и то же:
import torchimport torch.nn as nn
torch.manual_seed(0)
# Картинка: батч из 1, 3 канала (RGB), 224×224 пикселяimg = torch.randn(1, 3, 224, 224)p, d = 16, 768 # размер патча и ширина эмбеддинга (как в ViT-B/16)
# Способ 1: «руками» — нарезать на патчи и умножить на матрицу# unfold(ось, размер, шаг) режет ось на окна: ось высоты (2) → 14 окон по 16, затем ось ширины (3) — так жеpatches = img.unfold(2, p, p).unfold(3, p, p) # (1, 3, 14, 14, 16, 16)patches = patches.permute(0, 2, 3, 1, 4, 5) # (1, 14, 14, 3, 16, 16)patches = patches.reshape(1, 14 * 14, 3 * p * p) # (1, 196, 768)proj = nn.Linear(3 * p * p, d)tokens_a = proj(patches)
# Способ 2: свёртка с ядром p и шагом p — так пишут в реальном коде ViTconv = nn.Conv2d(3, d, kernel_size=p, stride=p)with torch.no_grad(): # переносим те же веса в свёртку conv.weight.copy_(proj.weight.view(d, 3, p, p)) conv.bias.copy_(proj.bias)tokens_b = conv(img).flatten(2).transpose(1, 2) # (1, 768, 14, 14) → (1, 196, 768)
print("форма токенов:", tuple(tokens_a.shape))print("одинаково?", torch.allclose(tokens_a, tokens_b, atol=1e-4))print("параметров в patch embedding:", sum(t.numel() for t in conv.parameters()))форма токенов: (1, 196, 768)одинаково? Trueпараметров в patch embedding: 590592: матрица плюс сдвиг. Если allclose вернул False, почти наверняка перепутан порядок
осей в permute — патч должен вытягиваться в порядке «канал, строка, столбец», как веса свёртки.
CLIP: учим картинки и тексты говорить на одном языке
Заголовок раздела «CLIP: учим картинки и тексты говорить на одном языке»ViT выдаёт векторы, но откуда модель узнает, что вектор фотографии панды как-то связан со словом «панда»? Классический путь — разметить картинки по 1000 классам (ImageNet). Это дорого и узко: модель выучит «panda» как класс № 388, но не поймёт фразу «панда спит на дереве».
CLIPCLIP (контрастивное предобучение «картинка — текст»)EN Contrastive Language–Image Pre-training (CLIP) (OpenAI, 2021) взял другой источник сигнала: 400 млн пар «картинка — подпись», собранных в интернете. Два энкодера — для картинок (ViT или ResNet) и для текста (трансформер) — учатся так, чтобы эмбеддинги картинки и её подписи оказались рядом, а с чужими подписями — далеко. Это и есть контрастивное обучениеконтрастивное обучениеEN contrastive learningсближаем представления «правильных пар» и раздвигаем «неправильные».
flowchart LR I["Батч из B картинок"] --> VE["Визуальный энкодер (ViT)"] --> IE["B векторов картинок"] T["B подписей"] --> TE["Текстовый энкодер"] --> TT["B векторов текстов"] IE --> S["Матрица сходств B×B"] TT --> S S --> L["Правильные пары — на диагонали: cross-entropy по строкам и столбцам"]
Формула InfoNCE
Заголовок раздела «Формула InfoNCE»Возьмём батч из пар. Нормируем все векторы до длины 1 и посчитаем матрицу косинусных сходствкосинусное сходствоEN cosine similarityКосинус угла между векторами — скалярное произведение, делённое на произведение длин. Для нормированных векторов равно скалярному произведению. : картинка против подписи . Для картинки правильная подпись одна — с тем же номером. Значит, каждая строка матрицы — это задача классификации на классов, и мы уже знаем loss для неё — cross-entropy из урока 1.3:
То же самое по столбцам даёт («какая картинка к этой подписи?»). Итоговый InfoNCEInfoNCE (контрастивная функция потерь)EN InfoNCE losscross-entropy по матрице сходств, где правильные пары стоят на диагонали — среднее двух: . Эту формулу вы уже видели в уроке 8.2.1: так обучают эмбеддинг-модели для RAG, только там пары «запрос — фрагмент», а здесь «картинка — подпись». А сама идея — притянуть настоящую пару и оттолкнуть негативы — пришла из негативного сэмплирования word2vec (урок 4.3.2).
Что здесь написано словами: «вероятность, которую модель дала правильной паре среди всех кандидатов, должна быть высокой». Остальные подписей в батче служат негативами. CLIP обучали с батчем 32 768 — каждая картинка соревновалась с 32 767 чужими подписями. Чем больше негативов, тем тоньше различия, которые модель вынуждена выучить.
Пример с числами и роль температуры
Заголовок раздела «Пример с числами и роль температуры»Три фотографии, три подписи — одна по-английски. Эмбеддинги зададим руками:
import numpy as np
# Игрушечные «эмбеддинги» (в CLIP их выдают энкодеры; здесь задаём руками, D = 4)images = np.array([ [0.9, 0.1, 0.0, 0.1], # фото: кошка на диване [0.1, 0.9, 0.2, 0.0], # фото: панда ест бамбук [0.0, 0.2, 0.9, 0.3], # фото: схема метро Пекина])texts = np.array([ [0.8, 0.2, 0.1, 0.0], # «кошка на диване» [0.2, 0.8, 0.0, 0.1], # «panda eating bamboo» (панда ест бамбук) [0.1, 0.1, 0.8, 0.4], # «карта метро»])
def l2n(x): return x / np.linalg.norm(x, axis=1, keepdims=True)
def softmax_rows(z): z = z - z.max(axis=1, keepdims=True) e = np.exp(z) return e / e.sum(axis=1, keepdims=True)
sim = l2n(images) @ l2n(texts).T # косинусные сходства 3×3print("сходства:\n", np.round(sim, 3))
for T in (1.0, 0.07): p = softmax_rows(sim / T) # строка i: «какая подпись к картинке i?» q = softmax_rows(sim.T / T) # строка j: «какая картинка к подписи j?» loss = (-np.mean(np.log(np.diag(p))) - np.mean(np.log(np.diag(q)))) / 2 print(f"T = {T}: P(правильная подпись) = {np.round(np.diag(p), 3)}, loss = {loss:.4f}")сходства: [[0.978 0.357 0.17 ] [0.363 0.961 0.31 ] [0.161 0.236 0.98 ]]T = 1.0: P(правильная подпись) = [0.504 0.483 0.522], loss = 0.6880T = 0.07: P(правильная подпись) = [1. 1. 1.], loss = 0.0002Диагональ явно больше остальных — «модель» всё различает правильно. Но при вероятность правильной подписи всего ≈0.5, а loss 0.69 далёк от нуля. Причина: косинус живёт в , и разница между 0.98 и 0.36 для softmax слишком мала (урок 1.3: разница логитов в 1 даёт отношение вероятностей всего ). Деление на растягивает шкалу в 14 раз. В CLIP температура обучаемая: стартует с 0.07, а множитель ограничен сверху числом 100, чтобы обучение не разогналось.
Zero-shot классификация
Заголовок раздела «Zero-shot классификация»Обученный CLIP умеет классифицировать без единого размеченного примера. Пишем для каждого класса подпись «фото кошки», «фото панды», …, кодируем их текстовым энкодером и выбираем ту, что ближе к картинке. Так CLIP без обучения на 1.28 млн размеченных картинок ImageNet сравнялся по точности с ResNet-50, обученным на них «с учителем». На том же приёме — сравнить эмбеддинги текста и картинки — построен поиск картинок по тексту и RAGгенерация с дополнением извлечёнными данными (RAG)EN retrieval-augmented generation (RAG) по документам с иллюстрациями: поиск «по смыслу» между модальностями.
Архитектура VLM: энкодер + проектор + LLM
Заголовок раздела «Архитектура VLM: энкодер + проектор + LLM»Три блока
Заголовок раздела «Три блока»CLIP сопоставляет картинку и текст, но не умеет отвечать на вопросы. VLM (визуально-языковая модель)визуально-языковая модель (VLM)EN vision-language model (VLM)в китайских статьях также «мультимодальная большая модель» (MLLM) добавляет к визуальному энкодеру языковую модель. Схема, которую в 2023 году популяризовала LLaVA и которую с вариациями используют почти все открытые модели:
flowchart LR IMG["Картинка"] --> VIT["Визуальный энкодер (ViT из CLIP)"] VIT --> PRJ["Проектор (MLP)"] PRJ --> CAT["Склейка последовательности"] TXT["Текст: «Что на картинке?»"] --> EMB["Эмбеддинги LLM"] --> CAT CAT --> LLM["LLM (Qwen, InternLM, DeepSeek…)"] --> OUT["Ответ токен за токеном"]
- Визуальный энкодер — обычно ViT, предобученный как CLIP. Его выходы уже «пахнут языком».
- Проекторпроектор (визуальный адаптер)EN projector, vision-language connectorпереводит выходы визуального энкодера в пространство эмбеддингов LLM — маленькая сеть (часто двухслойный MLP), которая переводит векторы энкодера в пространство эмбеддингов LLM. У ViT и LLM разная ширина и разные «системы координат».
- LLM — та же модель, что в текстовом чате. Визуальные токены для неё — просто ещё несколько векторов в начале последовательности. Loss считается только на токенах ответа, как при SFT в уроке 6.1.2.
Обучают обычно в два этапа. Сначала замораживают энкодер и LLM и учат только проектор на парах «картинка — подпись» (выравнивание). Затем размораживают LLM и учат на диалогах с картинками (visual instruction tuning).
Собираем вход VLM
Заголовок раздела «Собираем вход VLM»Вот как это выглядит в коде — с приёмом Qwen2-VL, где 4 соседних патча (квадрат 2×2) склеиваются в один токен:
import torchimport torch.nn as nn
torch.manual_seed(0)d_vis, d_llm = 768, 896 # ширина ViT-B и ширина маленькой LLM (у Qwen2.5-0.5B hidden_size = 896)
vis_tokens = torch.randn(1, 196, d_vis) # выход визуального энкодера: сетка 14×14 патчей
# 1) Сжатие 2×2 → 1 (как в Qwen2-VL): склеиваем 4 соседних патча в один векторg = 14x = vis_tokens.view(1, g // 2, 2, g // 2, 2, d_vis) # (1, 7, 2, 7, 2, 768)x = x.permute(0, 1, 3, 2, 4, 5).reshape(1, 49, 4 * d_vis) # (1, 49, 3072)
# 2) Проектор: двухслойный MLP переводит «язык зрения» в пространство эмбеддингов LLMprojector = nn.Sequential(nn.Linear(4 * d_vis, d_llm), nn.GELU(), nn.Linear(d_llm, d_llm))img_emb = projector(x) # (1, 49, 896)
# 3) Текстовые эмбеддинги (в настоящей модели — nn.Embedding LLM)text_emb = torch.randn(1, 12, d_llm) # «Что изображено на картинке?» ≈ 12 токенов
# 4) Склеиваем по оси последовательности — дальше это обычный вход трансформераseq = torch.cat([img_emb, text_emb], dim=1)print("после ViT: ", tuple(vis_tokens.shape))print("после 2×2-слияния:", tuple(x.shape))print("после проектора:", tuple(img_emb.shape))print("вход LLM: ", tuple(seq.shape))print("параметров в проекторе:", sum(p.numel() for p in projector.parameters()))после ViT: (1, 196, 768)после 2×2-слияния: (1, 49, 3072)после проектора: (1, 49, 896)вход LLM: (1, 61, 896)параметров в проекторе: 3557120Проектор — 3.6 млн параметров, капля по сравнению с LLM. Слияние 2×2 сократило визуальные токены в 4 раза, а информацию не выбросило: она переехала из длины последовательности в ширину вектора (768 → 3072).
Проблема разрешения
Заголовок раздела «Проблема разрешения»ViT из CLIP обучен на картинках 224 или 336 пикселей. Сожмите до 336×336 скан договора — и мелкий текст превратится в кашу. Стандартом стали два решения, и оба массово распространили китайские модели:
- Динамическое разрешение (Qwen2-VL, 2024). Картинка подаётся в родном размере: большая даёт много токенов, маленькая — мало. Чтобы трансформер понимал, где патч, Qwen придумал M-RoPE: позиция токена раскладывается на три компоненты — время, высота, ширина — и каждая вращает свою часть вектора (вспомните RoPE из урока 4.5). Тот же механизм работает для видео. Саму идею «ViT в родном разрешении» предложила Google в NaViT (2023); Qwen2-VL сделала её стандартом открытых VLM.
- Нарезка на тайлы (InternVL 1.5, 2024). Картинка режется на 1–40 тайлов по 448×448 пикселей в зависимости от пропорций, плюс уменьшенная копия целиком (thumbnail). Каждый тайл — 1024 патча, после pixel shuffle — 256 токенов. Pixel shuffle — та же идея, что слияние 2×2 в коде выше: четыре соседних токена складываются в один вектор вчетверо большей ширины.
Китайские семейства VLM
Заголовок раздела «Китайские семейства VLM»| Модель | Лаборатория | Когда | Что важно |
|---|---|---|---|
| Qwen-VL | Alibaba | 08.2023 | энкодер ViT-bigG; один слой cross-attention с 256 обучаемыми запросами сжимает картинку 448×448 до 256 токенов; умеет указывать рамки объектов |
| InternVL | Shanghai AI Lab | 12.2023 | визуальный энкодер InternViT-6B — «вырастили» зрение до размеров, сравнимых с LLM |
| InternVL 1.5 | Shanghai AI Lab | 04.2024 | тайлы 448×448 (до 4K), pixel shuffle, двуязычные данные с упором на документы и китайский OCR |
| Qwen2-VL | Alibaba | 09.2024 | динамическое разрешение, M-RoPE, слияние 2×2, видео; размеры от 2B до 72B |
| Qwen2.5-VL | Alibaba | 02.2025 | окно внимания в ViT для больших картинок, документы, видео, агенты для GUI |
| DeepSeek-OCR | DeepSeek | 10.2025 | оптическое сжатие контекста (ниже) |
| Kimi K2.5, Qwen3.5, MiniMax M3 | Moonshot, Alibaba, MiniMax | 2026 | зрение встроено во флагманскую модель, а не в отдельную «-VL»-версию |
Тренд хорошо виден по таблице: от «LLM + пристёгнутый CLIP» к моделям, где картинки — равноправная часть претрейна.
DeepSeek-OCR: «оптическое сжатие контекста»
Заголовок раздела «DeepSeek-OCR: «оптическое сжатие контекста»»Длинный контекст дорог: KV-кэш растёт линейно, внимание — квадратично (урок 4.6.4). А теперь заметьте странную вещь. Страница текста — это ~1000 текстовых токенов. Та же страница в виде картинки, как мы видели, может занять 100–256 визуальных токенов. Что, если хранить старый контекст картинкой? Это вопрос, который DeepSeek поставила в статье 2025 года: сколько визуальных токенов нужно, чтобы модель могла восстановить текстовых?
Мерило — степень оптического сжатияоптическое сжатие контекстаEN optical context compressionидея DeepSeek-OCR — хранить длинный текст как картинку в меньшем числе визуальных токенов:
Проверяют через оптическое распознавание символовоптическое распознавание символов (OCR)EN optical character recognition (OCR): если модель может прочитать текст с картинки, информация в визуальных токенах сохранилась.
Архитектура
Заголовок раздела «Архитектура»- DeepEncoder (≈380M параметров) — последовательно соединены SAM-base (≈80M; энкодер из модели сегментации Segment Anything от Meta, внимание в окнах — дёшево видит мелкие детали) → свёрточный компрессор, сокращающий токены в 16 раз → CLIP-large (≈300M, глобальное внимание — видит страницу целиком). Дорогое глобальное внимание работает уже по сжатым токенам.
- Декодер — DeepSeek-3B-MoE с ≈570M активных параметров (вспомните MoE из модуля 5.3).
| Режим | Разрешение | Визуальных токенов |
|---|---|---|
| Tiny | 512×512 | 64 |
| Small | 640×640 | 100 |
| Base | 1024×1024 | 256 |
| Large | 1280×1280 | 400 |
| Gundam | тайлов 640×640 + обзор 1024×1024 |
Результаты из статьи
Заголовок раздела «Результаты из статьи»- При сжатии меньше 10× точность распознавания ≈97%; при 20× — около 60%.
- На бенчмарке разбора документов OmniDocBench модель обходит GOT-OCR2.0 (256 токенов на страницу), используя 100 токенов, и MinerU2.0 (в среднем 6000+ токенов на страницу), используя меньше 800. Обе системы — тоже китайские: GOT-OCR2.0 сделали в StepFun, MinerU — в Shanghai AI Lab.
- В продакшене одна A100-40G размечает 200 тыс.+ страниц в день — это генератор обучающих данных для LLM и VLM.
Самая смелая часть — идея «забывания»: старые реплики диалога хранить картинками всё меньшего разрешения, как человеческая память, в которой давние события постепенно размываются. В статье это направление для исследований, а не проверенный результат.
Критика: не спешите с выводами
Заголовок раздела «Критика: не спешите с выводами»Через полтора месяца исследователи из UC San Diego выложили статью с говорящим названием «Optical Context Compression Is Just (Bad) Autoencoding» (arXiv:2512.03643). Они сравнили визуальный энкодер DeepSeek-OCR с почти бесплатным усреднением (mean pooling) соседних текстовых эмбеддингов и с обученным иерархическим энкодером. Вывод: на задаче восстановления текста простые методы не хуже или лучше картинок при любой степени сжатия, а «энтузиазм вокруг оптического сжатия опережает доказательства».
Это не значит, что DeepSeek-OCR плохая модель — как OCR-система она отличная. Это значит, что заголовок «картинки сжимают текст лучше токенов» требует более строгого сравнения. Как читать такие споры — тема урока 9.2.2. В январе 2026 года DeepSeek выпустила DeepSeek-OCR 2 (arXiv:2601.20552): новый энкодер переупорядочивает визуальные токены по смыслу страницы, а не построчно «слева направо, сверху вниз».
Практика
Заголовок раздела «Практика»Реализуйте две главные операции урока на NumPy: нарезку картинки на патчи (без циклов, через reshape и
transpose) и симметричный InfoNCE. Тесты проверят форму и порядок патчей, устойчивость loss к крошечной
температуре и его симметричность.
Одно отличие от кода на PyTorch выше: там картинка хранилась как (C, H, W) — так принято в PyTorch, — а здесь как
(H, W, C), как её отдают NumPy и библиотеки чтения картинок. Поэтому внутри патча числа идут в порядке «строка,
столбец, канал». На результат это не влияет, пока порядок одинаков для всех патчей.
import numpy as np
def patchify(img, p):
"""Режет картинку формы (H, W, C) на квадратные патчи p×p и вытягивает каждый в вектор.
Возвращает массив формы (N, p*p*C), где N = (H // p) * (W // p).
Порядок патчей — построчно: слева направо, сверху вниз (как мы читаем текст).
Внутри патча порядок такой же, как у img[i:i+p, j:j+p, :].reshape(-1).
Считаем, что H и W делятся на p без остатка.
"""
# TODO: проще всего через reshape → transpose → reshape (без циклов)
...
def l2_normalize(x, eps=1e-8):
"""Делит каждую строку x (форма (B, D)) на её L2-норму: строки становятся единичными векторами."""
# TODO
...
def info_nce(img_emb, txt_emb, temperature=0.07):
"""Симметричный контрастивный loss CLIP (InfoNCE) для батча из B пар «картинка — подпись».
img_emb, txt_emb — массивы формы (B, D); правильная пара i — это img_emb[i] и txt_emb[i].
Шаги:
1) нормируем строки обоих массивов (l2_normalize);
2) logits = img @ txt.T / temperature — матрица B×B косинусных сходств;
3) loss_i2t — средняя cross-entropy по СТРОКАМ (у строки i правильный класс — i);
loss_t2i — то же самое по СТОЛБЦАМ (это строки матрицы logits.T);
4) вернуть (loss_i2t + loss_t2i) / 2 как float.
Считайте устойчиво: log-sum-exp с вычитанием максимума (как в уроке 1.3).
"""
# TODO
...
# Проверьте себя кнопкой «Запустить»:
img = np.arange(4 * 4 * 3, dtype=float).reshape(4, 4, 3) # «картинка» 4×4, 3 канала
out = patchify(img, 2)
print("patchify ещё не реализована" if out is None else out.shape) # ожидается (4, 12)
rng = np.random.default_rng(0)
a = rng.normal(size=(8, 16))
print(info_nce(a, a + 0.1 * rng.normal(size=(8, 16)))) # маленькое число: пары почти совпадают
print(info_nce(a, rng.normal(size=(8, 16)))) # большое число: пары случайные
Проверь себя
Заголовок раздела «Проверь себя»- ViT превращает картинку в последовательность патчей; патч-эмбеддинг — это свёртка с ядром и шагом . Число визуальных токенов — главный параметр стоимости VLM.
- CLIP учит два энкодера контрастивно: InfoNCE — это cross-entropy по строкам и столбцам матрицы сходств, а температура растягивает шкалу косинусов.
- VLM = визуальный энкодер + проектор + LLM. Китайские Qwen-VL и InternVL сделали стандартом динамическое разрешение, M-RoPE и тайлинг.
- DeepSeek-OCR показала, что страницу можно закодировать в ~10 раз меньшим числом визуальных токенов, чем текстовых, почти без потерь для OCR. Но вывод «картинки — лучший способ сжимать контекст» оспорен: громкие идеи требуют сильных базлайновбазовое решение, бейзлайнEN baselineПростейшая модель (среднее, самый частый класс), с которой сравнивают всё остальное. — простых методов для сравнения.
Дальше: диффузионные модели — как нейросеть рисует картинки и видео, начиная с чистого шума.