smol course, юнит 3: модели «зрение + язык» (VLM)
Перевод юнита о VLM из smol course Hugging Face: как устроены модели «зрение + язык», как запускать SmolVLM2 через pipeline и вручную, как дообучать VLM методами SFT и DPO с LoRA и квантованием, и практикум на датасете графиков ChartQA.
Это перевод юнита «Vision Language Models» из второй версии smol course. Предыдущий юнит — выравнивание по предпочтениям и DPO, путеводитель по курсу — здесь.
3.1. Введение в модели «зрение + язык»
Заголовок раздела «3.1. Введение в модели «зрение + язык»»Модели «зрение + язык» (Vision Language Models, VLM) понимают одновременно изображения и текст. Они умеют описывать
картинки, отвечать на вопросы по изображению и рассуждать сразу по нескольким модальностям. Как и LLM, VLM обучаются
предсказывать следующий токен — но вдобавок умеют обрабатывать визуальную информацию. Например,
HuggingFaceTB/SmolVLM2-2.2B-Base — базовая VLM, а
HuggingFaceTB/SmolVLM2-2.2B-Instruct дообучена на
инструкциях для диалога с пользователем.
В этом юните мы разберём, как устроены эти модели, как они работают и, главное, как использовать и адаптировать их в своих проектах.
Что такое модели «зрение + язык»?
Заголовок раздела «Что такое модели «зрение + язык»?»VLM обрабатывают изображение вместе с текстом и решают задачи вроде описания изображений, ответов на вопросы по картинке и мультимодальных рассуждений.
Типичная архитектура VLM состоит из кодировщика изображений, который извлекает визуальные признаки, проекционного слоя, который согласует визуальные и текстовые представления, и языковой модели, которая обрабатывает или генерирует текст. Так модель связывает визуальные элементы с языковыми понятиями.
VLM можно использовать в разных конфигурациях в зависимости от задачи. Базовые модели решают общие задачи на стыке зрения и языка, а варианты, оптимизированные для чата, поддерживают диалог. В некоторых моделях есть дополнительные компоненты, чтобы привязывать ответы к конкретным местам изображения (grounding) или специализироваться на отдельных задачах вроде детекции объектов.
Последние тенденции
Заголовок раздела «Последние тенденции»Добавление зрения к языковым моделям открыло много интересных направлений, среди них:
- VLM для рассуждений: решают сложные задачи по визуальным входам.
- Специализированные VLM: например, детекция объектов, сегментация или понимание документов.
- Модели «зрение — язык — действие» (VLA): выдают действия для роботов.
- Агентные VLM: позволяют строить сложные сценарии вроде разговора с документами или управления компьютером по скриншотам.
- Модели «что угодно во что угодно» (any-to-any): выходят за пределы зрения и текста и работают с разными модальностями на входе и выходе (текст, изображения, звук, видео и т. д.).
Адаптация VLM под конкретные задачи
Заголовок раздела «Адаптация VLM под конкретные задачи»Дообучить VLM — значит адаптировать предобученную модель к своему датасету или задаче. Вы уже видели такие стратегии, как обучение с учителем (SFT) и выравнивание по предпочтениям в прошлых юнитах, — здесь работают те же идеи.
Основные инструменты и приёмы те же, что для LLM, но у дообучения VLM есть свои трудности. Главная — представление данных: изображения нужно аккуратно подготовить, чтобы модель эффективно сочетала визуальную и текстовую информацию. Другая — размер модели. VLM часто заметно больше LLM, так что эффективность критична.
Чтобы обучение оставалось практичным и недорогим, можно опереться на квантование и PEFT (параметрически-эффективное дообучение), которые мы разбирали в юните 1. Эти подходы делают дообучение легче и позволяют большему числу людей адаптировать мощные VLM и экспериментировать с ними.
(Примечание переводчика: LoRA и квантование подробно — в уроках 6.2.1 и 7.2.1, а также в переводе главы 11 LLM Course.)
Оценка VLM
Заголовок раздела «Оценка VLM»Как мы видели в юните 2, оценка — важнейший шаг и при разработке, и в продакшне. Для VLM действует тот же принцип: при разработке нужны бенчмарки, чтобы понять возможности и ограничения модели, а после развёртывания — проверки в реальных условиях, чтобы убедиться в её надёжности и практической пользе.
Широко используемые универсальные бенчмарки:
- MMMU и MMMU-Pro: большие междисциплинарные бенчмарки, требующие рассуждений в областях от искусства до науки и инженерии.
- MMBench: более 3000 вопросов с одним правильным вариантом, проверяющих такие навыки, как OCR, локализация и рассуждение.
- MMT-Bench: экспертные мультимодальные задачи — распознавание, локализация, рассуждение и планирование.
Есть и предметные бенчмарки для проверки отдельных навыков:
- MathVista: математические рассуждения по изображениям.
- AI2D: понимание схем и диаграмм.
- ScienceQA: ответы на научные вопросы.
- OCRBench: понимание документов и распознавание текста.
Наконец, для удобной оценки есть OpenVLM Leaderboard — он даёт инструмент, который оценивает VLM на многих бенчмарках одной командой.
(Примечание переводчика: инструмент за этим лидербордом — VLMEvalKit от OpenCompass (Шанхайская лаборатория ИИ). Общие проблемы бенчмарков — утечки в обучающие данные, чувствительность к формату — те же, что у текстовых, см. урок 7.3.1.)
Что вы сделаете
Заголовок раздела «Что вы сделаете»К концу модуля вы:
- научитесь пользоваться VLM в библиотеке 🤗 transformers;
- разберётесь с chat-шаблонами и форматом диалога для VLM;
- дообучите SmolVLM на своём датасете;
- запустите обучение и из кода на Python, и из командной строки.
Погрузимся в увлекательный мир моделей «зрение + язык»!
- Vision Language Models (Better, Faster, Stronger)
- Fine-Tuning a Vision Language Model (Qwen2-VL-7B) with the Hugging Face Ecosystem (TRL)
- Fine-tuning SmolVLM with TRL on a consumer GPU
- Fine-tuning SmolVLM using direct preference optimization (DPO) with TRL on a consumer GPU
- Fine tuning a VLM for Object Detection Grounding using TRL
- Fine-Tuning a Vision Language Model with TRL using MPO
- Post training a VLM for reasoning with GRPO using TRL
- Preference Optimization for Vision Language Models with TRL
- Vision Language Models Explained
- SmolVLM — small yet mighty Vision Language Model
- SmolVLM2-2.2B-Instruct
- CLIP: Learning Transferable Visual Models from Natural Language Supervision
- Align Before Fuse: Vision and Language Representation Learning with Momentum Distillation
- Space «Object Understanding with Vision Language Models»
(Почти все ссылки — на английские статьи блога и рецепты Open-Source AI Cookbook Hugging Face.)
3.2. Готовые VLM на практике
Заголовок раздела «3.2. Готовые VLM на практике»Модели «зрение + язык» обрабатывают изображения и текст одновременно и решают продвинутые задачи: описывают картинки, отвечают на вопросы по ним, рассуждают сразу по нескольким модальностям. В этом разделе мы сосредоточимся на том, как VLM работают и как ими пользоваться на практике.
Обзор архитектуры
Заголовок раздела «Обзор архитектуры»(В оригинале — схема архитектуры VLM: изображение идёт через кодировщик изображений и проектор, текст — через токенизатор, а затем обе последовательности поступают в декодер, который генерирует ответ. Ссылка на рисунок.)
flowchart LR I["Изображение"] --> E["Кодировщик изображений<br/>(SigLIP, CLIP)"] E --> P["Проектор<br/>(MLP)"] T["Текст промпта"] --> TK["Токенизатор<br/>и эмбеддинги"] P --> D["Текстовый декодер<br/>(LLM)"] TK --> D D --> O["Ответ текстом"]
VLM соединяют компоненты обработки изображений и генерации текста для единого мультимодального понимания. Основные элементы:
- Кодировщик изображений: превращает изображения в компактные числовые представления. Примеры: CLIP, SigLIP.
- Проектор эмбеддингов: согласует признаки изображения с эмбеддингами текста (часто это небольшой MLP или линейный слой, дообучаемый под мультимодальную задачу).
- Мультимодальный проектор / модуль слияния: сливает визуальные и текстовые представления и усиливает связи между ними. Этот шаг идёт дальше простого согласования и даёт богатое взаимодействие модальностей.
- Текстовый декодер: генерирует текст (или другой выход) по слитым мультимодальным представлениям.
Большинство VLM используют предобученные кодировщики изображений и текстовые декодеры, а затем дообучаются на датасетах пар «изображение — текст» — так обучение эффективнее, а обобщение лучше.
(Примечание переводчика: «проектор эмбеддингов» и «мультимодальный проектор» в большинстве современных VLM — это одна и та же небольшая сеть. В SmolVLM, например, признаки SigLIP сначала сжимаются (pixel shuffle уменьшает число визуальных токенов), а затем MLP переводит их в пространство эмбеддингов языковой модели; дальше LLM просто видит последовательность, где визуальные токены стоят вперемешку с текстовыми. Подробно — в уроке 9.1.1.)
Практическое применение
Заголовок раздела «Практическое применение»VLM применяют для таких задач:
- Описание изображений (image captioning): генерировать подписи к картинкам.
- Ответы на вопросы по изображению (VQA): отвечать на вопросы о картинке.
- Кросс-модальный поиск: находить картинки по тексту и наоборот.
- Творческие применения: дизайн, создание изображений, мультимедийный контент.
Ключ к успеху — качественные датасеты пар, а 🤗 transformers дают предобученные модели и удобные процессы дообучения.
(В оригинале — иллюстрация примеров применения VLM: описание, вопросы по картинке, поиск. Ссылка на рисунок.)
Формат чата
Заголовок раздела «Формат чата»Многие VLM поддерживают диалог, где сообщения устроены так:
- Системное сообщение задаёт контекст:
"You are an assistant analyzing visual data."(«Ты — ассистент, анализирующий визуальные данные»). - Запросы пользователя сочетают текст и изображения.
- Ответы ассистента — текст, сгенерированный по мультимодальному анализу.
Пример:
[ { "role": "system", "content": [{"type": "text", "text": "You are a VLM specialized in charts."}] }, { "role": "user", "content": [ {"type": "image", "image": "<image_data>"}, {"type": "text", "text": "What is the highest value in this chart?"} ] }, { "role": "assistant", "content": [{"type": "text", "text": "42"}] }](Системное сообщение: «Ты — VLM, специализирующаяся на графиках». Вопрос: «Какое наибольшее значение на этом графике?» Ответ: «42». Обратите внимание: содержимое сообщения — не строка, а список частей, и картинка — одна из частей.)
VLM умеют принимать и несколько изображений или кадры видео: последовательность изображений передаётся через тот же chat-шаблон.
VLM через pipeline
Заголовок раздела «VLM через pipeline»Как мы видели в юните 1, проще всего
пользоваться VLM через абстракцию 🤗 pipeline:
from transformers import pipeline
# Создаём pipeline с VLMpipe = pipeline("image-text-to-text", "HuggingFaceTB/SmolVLM2-2.2B-Instruct", device_map="auto")
# Задаём диалог с изображениемmessages = [ { "role": "user", "content": [ { "type": "image", "image": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg", }, {"type": "text", "text": "Describe this image."}, ], } ]
outputs = pipe(text=messages, max_new_tokens=60, return_full_text=False)
# Генерируем ответ — pipeline сам обрабатывает мультимодальный входresponse = pipe(messages, max_new_tokens=128, temperature=0.7)
print(response[0]['generated_text'][-1]['content']) # печатаем описание от моделиВывод:
The image depicts a close-up view of a flower garden, specifically focusing on a pink flower. The flower is the central subject of the image, and it is a prominent feature due to its vibrant color and intricate details. The flower has a circular shape, with petals that are slightly curled and have a gradient from light to dark pink. The petals are arranged symmetrically around the central pistil, which is visible in the center of the flower. The pistil is a small, yellow structure that is surrounded by a cluster of stamens, which are visible as small, yellow structures. The flower also has a small, black(Перевод: «На изображении крупным планом цветочный сад, в центре — розовый цветок. … Лепестки слегка закручены,
с переходом от светло- к тёмно-розовому, расположены симметрично вокруг пестика… У цветка также есть маленькая,
чёрная» — ответ оборвался на лимите токенов. Забавно, что модель не упомянула пчелу, которая и есть главный объект
снимка bee.jpg.)
(Примечание переводчика: в коде модель генерирует дважды — первый результат outputs (с return_full_text=False,
только новый текст) нигде не используется, печатается второй. Оставьте один вызов. И учтите, что temperature=0.7
без do_sample=True в некоторых версиях transformers игнорируется с предупреждением.)
VLM через Transformers (полный контроль)
Заголовок раздела «VLM через Transformers (полный контроль)»Для продвинутого использования можно обращаться к VLM напрямую через 🤗 Transformers — так вы полностью управляете
каждым компонентом. Чтобы снизить расход памяти и ускорить инференс, можно применить 4-битное квантование через
bitsandbytes.
В отличие от обычных LLM, VLM нужен процессор (processor), а не только токенизатор. Процессор берёт на себя и токенизацию текста, и предобработку изображений, упрощая работу с мультимодальными входами.
import torchfrom transformers import AutoProcessor, AutoModelForImageTextToText, BitsAndBytesConfigfrom transformers.image_utils import load_image
device = "cuda" if torch.cuda.is_available() else "cpu"
# Квантование ради эффективностиquant_config = BitsAndBytesConfig(load_in_4bit=True)model_name = "HuggingFaceTB/SmolVLM2-2.2B-Instruct"model = AutoModelForImageTextToText.from_pretrained(model_name, quantization_config=quant_config).to(device)processor = AutoProcessor.from_pretrained(model_name)Пример: описать изображение
Заголовок раздела «Пример: описать изображение»Описывать изображения можно с помощью chat-шаблона. Каждое изображение в сообщении обозначается как
{"type": "image"}, а сами данные изображения передаются процессору аргументом images. Процессор без усилий
обрабатывает и текст, и изображение.
# Загружаем изображениеimage_url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg"image = load_image(image_url)
# Составляем входные сообщенияmessages = [ { "role": "user", "content": [ {"type": "image"}, {"type": "text", "text": "Can you describe the image?"} ] },]
# Готовим входыprompt = processor.apply_chat_template(messages, add_generation_prompt=True)inputs = processor(text=prompt, images=[image], return_tensors="pt")inputs = inputs.to(device)
# Генерируем ответgenerated_ids = model.generate(**inputs, max_new_tokens=500)generated_texts = processor.batch_decode( generated_ids, skip_special_tokens=True,)[0]
# Оставляем только ответ ассистентаassistant_response = generated_texts.split("Assistant:")[-1].strip()
print(assistant_response)Вывод:
The image is of a bee on a flower.(«На изображении пчела на цветке» — на этот раз модель пчелу заметила. Отличие от прошлого примера — в формулировке вопроса («Can you describe the image?» вместо «Describe this image») и в параметрах генерации: здесь — настройки по умолчанию из конфигурации модели, там — температура 0.7. Ответы VLM заметно зависят от того и другого.)
Процессор объединяет текст и изображение на входе, так что модель может генерировать связные мультимодальные ответы.
Материалы
Заголовок раздела «Материалы»- Vision Language Models (Better, Faster, Stronger)
- Vision Language Models Explained
- SmolVLM — small yet mighty Vision Language Model
3.3. Дообучение VLM
Заголовок раздела «3.3. Дообучение VLM»В юните 1 мы разобрали обучение с учителем для LLM, включая экономные стратегии в TRL. В этом разделе мы адаптируем эти приёмы к моделям «зрение + язык», уделяя внимание эффективности и качеству на конкретной задаче.
Главные приёмы экономии
Заголовок раздела «Главные приёмы экономии»При дообучении VLM память и вычисления быстро становятся узким местом. Основные стратегии:
Квантование
Заголовок раздела «Квантование»Квантование снижает точность весов и активаций модели, уменьшая расход памяти и ускоряя вычисления.
- bfloat16 / float16 вдвое снижают требования к памяти, сохраняя точность.
- 8- и 4-битное квантование экономит ещё больше памяти ценой небольшой потери качества.
⚠️ Особенно важно для VLM, где признаки изображений увеличивают расход памяти.
PEFT и LoRA
Заголовок раздела «PEFT и LoRA»Низкоранговая адаптация (Low-Rank Adaptation, LoRA) замораживает веса базовой модели и обучает компактные матрицы низкорангового разложения, резко сокращая число обучаемых параметров. В связке с PEFT дообучение требует миллионов обучаемых параметров вместо миллиардов, и большие VLM становятся доступны на скромном железе.
Подбор размера батча
Заголовок раздела «Подбор размера батча»Экономного обучения можно добиться так:
- Накопление градиентов (gradient accumulation): эффективный размер батча набирается за несколько шагов.
- Перерасчёт активаций (gradient checkpointing): промежуточные активации пересчитываются заново, чтобы сэкономить память.
- Начинайте с большого батча, уменьшайте его при ошибках нехватки памяти (OOM) и сочетайте с LoRA и квантованием для лучшего результата.
Обучение с учителем (SFT)
Заголовок раздела «Обучение с учителем (SFT)»SFT адаптирует предобученную VLM к конкретной задаче на размеченных датасетах (пары «изображение — текст»). Примеры:
- ответы на вопросы по изображению (VQA);
- описание изображений;
- чтение графиков и диаграмм.
Когда применять SFT
Заголовок раздела «Когда применять SFT»- Чтобы специализировать VLM в области, где базовая модель справляется плохо.
- Чтобы выучить предметную лексику или визуальные закономерности.
Ограничения
- Нужны качественные размеченные датасеты.
- Может требовать много вычислений.
- Риск переобучения, если дообучение слишком узкое.
Пример использования
Заголовок раздела «Пример использования»SFTTrainer умеет обучать VLM напрямую. В датасете должна быть
дополнительная колонка images с визуальными входами. Подробности — в
документации о форматах датасетов.
from trl import SFTTrainer
training_args = SFTTrainer( output_dir="./fine_tuned_model", per_device_train_batch_size=4, num_train_epochs=3, learning_rate=5e-5, save_steps=1000, bf16=True, gradient_checkpointing=True, gradient_accumulation_steps=16, logging_steps=50)(Примечание переводчика: в этом фрагменте опечатка — параметры обучения задаёт SFTConfig, а не SFTTrainer.
Правильно: from trl import SFTConfig и training_args = SFTConfig(...) с теми же аргументами; затем
SFTTrainer(model=model, args=training_args, train_dataset=...). Полный рабочий пример — в упражнении 2 ниже.)
⚠️ Важно: задайте max_length=None в SFTConfig.
Иначе обрезка по длине может удалить токены изображения во время обучения.
SFTConfig(max_length=None, ...)(Почему это важно: одно изображение превращается в сотни и даже тысячи «визуальных токенов». Если обрезать последовательность по длине, обрежутся и они — модель увидит сломанную картинку, а обучение может упасть с ошибкой несовпадения числа токенов изображения.)
Практические шаги
Заголовок раздела «Практические шаги»-
Подготовка данных. Используйте пары «изображение — текст», например
HuggingFaceM4/ChartQA. -
Подготовка модели.
- Загрузите предобученную VLM, например
HuggingFaceTB/SmolVLM2-2.2B-Instruct. - Создайте процессор, который подготовит текстовые и визуальные входы.
- Загрузите предобученную VLM, например
-
Процесс дообучения.
- Приведите данные к формату диалога (
system,user,assistant). - Настройте оптимизатор, размер батча и накопление градиентов.
- Примените квантование и LoRA для экономного по памяти обучения.
- Приведите данные к формату диалога (
Оптимизация предпочтений (DPO)
Заголовок раздела «Оптимизация предпочтений (DPO)»Прямая оптимизация предпочтений (DPO) выравнивает VLM с предпочтениями людей, а не со строгим следованием инструкциям.
- Полезна для творческих задач, субъективных оценок или вопросов с выбором ответа.
- Модель учится выбирать ответ, который больше нравится людям, даже если он не «строго правильный».
Ограничения
- Нужны качественные датасеты с разметкой предпочтений.
- Обучение требует попарной выборки предпочтений и аккуратного обращения с ресурсами.
Пример использования
Заголовок раздела «Пример использования»- Датасет: каждый пример содержит промпт (изображение + вопрос) и два варианта ответа:
Question: How many families?Rejected: The image does not provide information about families.Chosen: The image shows a Union Organization table setup with 18,000 families.(Вопрос: «Сколько семей?» Отвергнутый ответ: «На изображении нет информации о семьях». Выбранный ответ: «На изображении показан стол Union Organization с 18 000 семей».)
- Подготовка модели: загрузите предобученную VLM, подключите DPO из TRL и подготовьте процессор.
- Процесс обучения:
- Приведите датасет к формату диалога.
- Примените функцию потерь на предпочтениях.
- Для экономии используйте накопление градиентов, перерасчёт активаций, LoRA и квантование.
(Как устроен сам DPO — в юните 2 и уроке 6.3.3.
Для VLM всё то же, только в промпте есть изображение, а DPOTrainer получает процессор вместо токенизатора.)
Сравнение SFT и DPO
Заголовок раздела «Сравнение SFT и DPO»| Признак | SFT | DPO |
|---|---|---|
| Вход | размеченные пары «изображение — текст» | «изображение — текст» + ответы, ранжированные по предпочтению |
| Loss | обычный, с учителем | на предпочтениях |
| Цель | адаптация к задаче | ответы, близкие к предпочтениям людей |
| Применение | специализация в области | творческие, субъективные задачи или задачи с выбором ответа |
Практические советы
Заголовок раздела «Практические советы»- Начинайте с малого: проверьте всё на части датасета, прежде чем обучать на полном.
- Используйте перерасчёт активаций + LoRA + квантование, чтобы снизить расход памяти.
- Следите за частотой сохранения чекпойнтов, чтобы сбалансировать место на диске и надёжность.
- Проверяйте качество на небольшом наборе, чтобы не переобучиться.
Что дальше
Заголовок раздела «Что дальше»После дообучения оцените качество VLM на мультимодальных задачах с помощью бенчмарков и своих тестовых наборов, применяя приёмы из юнита 2.
Дообучение VLM в hf jobs с TRL
Заголовок раздела «Дообучение VLM в hf jobs с TRL»Как говорилось в прошлых юнитах, Hugging Face Jobs упрощают дообучение моделей «зрение + язык». Можно запускать SFT или DPO прямо на инфраструктуре Hugging Face с минимальной настройкой, подстраивая параметры обучения, которые мы обсуждали выше.
Быстрый пример
Заголовок раздела «Быстрый пример»hf jobs uv run \ --flavor a100-large \ --secrets HF_TOKEN \ --timeout 2h \ "https://raw.githubusercontent.com/huggingface/trl/main/trl/scripts/sft.py" \ --model_name_or_path HuggingFaceTB/SmolVLM2-2.2B-Instruct \ --dataset_name HuggingFaceM4/ChartQA \ --report_to trackio--flavor a100-large: тип GPU для обучения.--secrets HF_TOKEN: ваш токен Hugging Face.
Скрипт сам настраивает процессор, форматирует данные и обучает модель. Когда задание закончится, дообученную VLM можно скачать и использовать в своих задачах.
(Примечание переводчика: «сам форматирует данные» — не совсем так. Скрипт sft.py ждёт датасет уже в формате
messages + images, а у ChartQA колонки image, query, label. Поэтому в упражнении 3 ниже курс берёт уже
подготовленный датасет trl-lib/llava-instruct-mix; для ChartQA сначала преобразуйте данные функцией format_data
из упражнения 2.)
Материалы
Заголовок раздела «Материалы»- Fine-Tuning a Vision Language Model (Qwen2-VL-7B) with the Hugging Face Ecosystem (TRL)
- Fine-tuning SmolVLM with TRL on a consumer GPU
- Fine-tuning SmolVLM using direct preference optimization (DPO) with TRL on a consumer GPU
- Preference Optimization for Vision Language Models with TRL
3.4. Практические упражнения: дообучаем SmolVLM2-2.2B-Instruct
Заголовок раздела «3.4. Практические упражнения: дообучаем SmolVLM2-2.2B-Instruct»Ноутбук к разделу: Google Colab.
Добро пожаловать в практическую часть! Здесь вы примените на практике всё, что узнали о моделях «зрение + язык», на модели HuggingFaceTB/SmolVLM2-2.2B-Instruct. Упражнения идут от основ к продвинутым приёмам и дают реальный практический опыт.
После упражнений вы сможете:
- Работать с датасетами для VLM: изучить и подготовить HuggingFaceM4/ChartQA.
- Оптимизировать обучение: применить квантование и PEFT для экономного дообучения.
- Дообучать модели на практике: обучить HuggingFaceTB/SmolVLM2-2.2B-Instruct и через API на Python, и через командную строку.
- Адаптировать датасеты для TRL: готовить датасеты VLM так, чтобы они без проблем работали в TRL.
- Перейти к продакшну: понять, как масштабировать процессы дообучения VLM и управлять ими в продакшне.
Упражнение 1: знакомимся с SmolVLM2-2.2B-Instruct
Заголовок раздела «Упражнение 1: знакомимся с SmolVLM2-2.2B-Instruct»Цель: познакомиться с моделью SmolVLM2-2.2B-Instruct и проверить её на примере из датасета.
Подготовка окружения
Заголовок раздела «Подготовка окружения»Сначала установим нужные библиотеки: transformers, datasets, trl, huggingface_hub и trackio. Эти пакеты дают
инструменты для работы с моделью, датасетами и Hugging Face Hub.
# Устанавливаем нужные пакеты (в Colab или в своём окружении)pip install transformers datasets trl huggingface_hub trackio num2words==0.5.14(Примечание переводчика: num2words — зависимость процессора SmolVLM2: без этого пакета загрузка процессора
падает с ошибкой импорта. Для упражнения 2 понадобится ещё peft: pip install peft.)
Импорт зависимостей
Заголовок раздела «Импорт зависимостей»Импортируем основные зависимости:
# Импорт зависимостей
import torchimport osfrom transformers import AutoProcessor, AutoModelForImageTextToText, BitsAndBytesConfigfrom transformers.image_utils import load_imageЗагрузка модели и процессора
Заголовок раздела «Загрузка модели и процессора»1. Выбираем устройство
Заголовок раздела «1. Выбираем устройство»Сначала выберем устройство, на котором будет работать модель: GPU (cuda), Apple Silicon (mps) или, если ничего
нет, CPU.
device = ( "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu")2. Входим в Hugging Face
Заголовок раздела «2. Входим в Hugging Face»Чтобы работать с приватными моделями или выгрузить дообученную модель на Hub (как мы сделаем в этом упражнении), нужно войти в свой аккаунт Hugging Face.
from huggingface_hub import loginlogin()3. Загружаем модель и процессор
Заголовок раздела «3. Загружаем модель и процессор»Наконец, загрузим модель HuggingFaceTB/SmolVLM2-2.2B-Instruct. Здесь же создаётся AutoProcessor — он правильно
подготовит и текст, и изображения, прежде чем передать их модели.
model_name = "HuggingFaceTB/SmolVLM2-2.2B-Instruct"model = AutoModelForImageTextToText.from_pretrained( model_name, dtype=torch.bfloat16,).to(device)
processor = AutoProcessor.from_pretrained(model_name)Изучаем датасет
Заголовок раздела «Изучаем датасет»На этом шаге загрузим небольшую часть датасета ChartQA — лишь 10% обучающей и валидационной частей, — чтобы упражнения шли быстро и оставались учебными.
Затем покажем одно из изображений графика с помощью matplotlib, чтобы увидеть, что получает модель на вход. Ещё
напечатаем соответствующий вопрос и ответ, чтобы полностью понять устройство датасета и тип задач, которые решает
модель.
(В оригинале здесь встроен просмотрщик датасета HuggingFaceM4/ChartQA:
у каждой строки — изображение графика, вопрос query и ответ label.)
from datasets import load_datasetimport matplotlib.pyplot as plt
train_dataset, eval_dataset = load_dataset("HuggingFaceM4/ChartQA", split=["train[:10%]", "val[:10%]"])example = train_dataset[1]image = load_image(example["image"])
print(example["query"])print(example["label"][0])Вывод:
How many values are below 40 in Unfavorable graph?6(Вопрос: «Сколько значений ниже 40 на графике Unfavorable?» Правильный ответ: 6.)
plt.imshow(image)plt.axis("off")plt.title("Sample Chart Image")plt.show()(В оригинале — изображение этого графика: линейная диаграмма опроса с линиями «Favorable» и «Unfavorable» по годам. Ссылка на рисунок.)
Строим промпт в формате чата
Заголовок раздела «Строим промпт в формате чата»Создадим список сообщений, в котором вопрос пользователя идёт вместе с изображением.
С помощью processor.apply_chat_template превратим его ровно в тот формат входа, который ждёт модель.
# Задаём промпт в формате чатаmessages = [ {"role": "user", "content": [ {"type": "image", "image": image}, {"type": "text", "text": example["query"]}, ]}]
# Применяем chat-шаблонchat_prompt = processor.apply_chat_template( messages, add_generation_prompt=True\)print(chat_prompt)Вывод:
<|im_start|>User:<image>How many values are below 40 in Unfavorable graph?<end_of_utterance>Assistant:(Видно, как шаблон SmolVLM2 устроен изнутри: служебный токен начала, роль User:, место для изображения <image>,
текст вопроса, токен конца реплики и приглашение Assistant: для ответа модели. Обратная косая черта \ в конце
строки вызова — лишний перенос строки в оригинале, он безвреден.)
Запускаем инференс
Заголовок раздела «Запускаем инференс»Превратим промпт и изображение в тензоры, сгенерируем ответ моделью и декодируем токены обратно в текст.
# Токенизируем входinputs = processor(images=[image], text=chat_prompt, return_tensors="pt").to(device)
# Генерируем ответ моделиwith torch.no_grad(): output = model.generate(**inputs, max_new_tokens=20)
# Отрезаем входные id, оставляя только сгенерированныеtrimmed_generated_ids = [out_ids[len(in_ids) :] for in_ids, out_ids in zip(inputs.input_ids, output)]
# Декодируем ответ в текстoutput_text = processor.batch_decode( trimmed_generated_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)print(output_text[0])Вывод:
3.Модель сгенерировала ответ, но он неверный (правильно — 6). Его можно улучшить дообучением. Мы увидели, как строить промпты и генерировать ответы SmolVLM2-2.2B-Instruct, — теперь научимся экономно адаптировать и дообучать модель с помощью LoRA (низкоранговой адаптации). Этот подход позволяет обучать большие модели меньшими ресурсами и готовит модель к конкретным задачам.
Упражнение 2: дообучаем модель с LoRA
Заголовок раздела «Упражнение 2: дообучаем модель с LoRA»В этом упражнении мы применим LoRA (низкоранговую адаптацию), чтобы экономно дообучить модель «зрение + язык».
LoRA встраивает обучаемые низкоранговые матрицы в существующие слои модели, и большие модели можно дообучать со значительно меньшим числом обучаемых параметров. Это снижает расход памяти и ускоряет обучение, сохраняя высокое качество.
system_message = """You are a Vision Language Model specialized in interpreting visual data from chart images.Your task is to analyze the provided chart image and respond to queries with concise answers, usually a single word, number, or short phrase.The charts include a variety of types (e.g., line charts, bar charts) and contain colors, labels, and text.Focus on delivering accurate, succinct answers based on the visual information. Avoid additional explanation unless absolutely necessary."""(Системное сообщение оставлено на английском, как в оригинале, — датасет английский. Перевод: «Ты — модель „зрение + язык“, специализирующаяся на чтении визуальных данных с изображений графиков. Твоя задача — проанализировать изображение графика и отвечать на вопросы кратко: обычно одним словом, числом или короткой фразой. Графики бывают разных типов (линейные, столбчатые и др.) и содержат цвета, подписи и текст. Давай точные и сжатые ответы по визуальной информации. Избегай пояснений, если они не абсолютно необходимы».)
Мы приведём датасет к структуре чат-бота, где каждый пример содержит:
- системное сообщение, задающее роль ассистента;
- изображение графика;
- вопрос пользователя;
- ожидаемый ответ.
Именно такой формат ждёт SFTTrainer: с колонками images и messages. Подробнее о подготовке датасетов для
дообучения VLM — в документации.
Форматируем датасет
Заголовок раздела «Форматируем датасет»Первый шаг — привести датасет к структуре для обучения VLM. Зададим системное сообщение, которое поручает модели роль эксперта по анализу графиков, дающего краткие и точные ответы по изображениям графиков.
def format_data(sample): return { "images": [sample["image"]], "messages": [ { "role": "system", "content": [{"type": "text", "text": system_message}], }, { "role": "user", "content": [ { "type": "image", "image": sample["image"], }, { "type": "text", "text": sample["query"], }, ], }, { "role": "assistant", "content": [{"type": "text", "text": sample["label"][0]}], }, ], }Теперь отформатируем данные в структуру чат-бота. Так мы зададим диалоги для модели.
train_dataset = [format_data(sample) for sample in train_dataset]eval_dataset = [format_data(sample) for sample in eval_dataset](Обратите внимание: после этого train_dataset — обычный список Python, а не объект Dataset. SFTTrainer
принимает и такой вариант; при большом датасете удобнее train_dataset.map(format_data), чтобы не держать все
картинки в памяти сразу.)
Настраиваем LoRA
Заголовок раздела «Настраиваем LoRA»Зададим LoraConfig:
rиlora_alphaуправляют рангом и масштабом матриц адаптации;target_modulesзадаёт, какие части модели адаптировать;task_typeуказывает на каузальное языковое моделирование.
Затем применим LoRA к базовой модели через get_peft_model и напечатаем число обучаемых параметров, чтобы проверить
адаптацию.
from peft import LoraConfig, get_peft_model
# Настраиваем LoRApeft_config = LoraConfig( lora_alpha=16, lora_dropout=0.05, r=8, target_modules=["q_proj", "v_proj"], task_type="CAUSAL_LM",)
# Применяем адаптацию PEFTpeft_model = get_peft_model(model, peft_config)
# Печатаем число обучаемых параметровpeft_model.print_trainable_parameters()(Здесь LoRA ставится только на проекции запросов и значений внимания (q_proj, v_proj) с рангом 8 — это классический
минимальный вариант из статьи LoRA. Обучаемых параметров получится доля процента от 2,2 млрд. Как считать число
параметров LoRA — в уроке 6.2.1.)
Настраиваем тренер
Заголовок раздела «Настраиваем тренер»Настроим SFTTrainer из trl через SFTConfig:
num_train_epochs, размер батча иgradient_accumulation_stepsуправляют циклом обучения;gradient_checkpointingиbf16экономят память и ускоряют обучение;learning_rateуправляет оптимизацией;train_datasetиeval_datasetподготовлены под ваш датасет.
Так тренер будет готов к дообучению с PEFT/LoRA.
from trl import SFTConfig, SFTTrainer
# Задаём параметры обучения через SFTConfigtraining_args = SFTConfig( output_dir="smol-course-smolvlm2-2.2b-instruct-trl-sft-ChartQA", num_train_epochs=1, per_device_train_batch_size=4, gradient_accumulation_steps=4, learning_rate=1e-4, logging_steps=25, save_strategy="steps", save_steps=25, optim="adamw_torch_fused", bf16=True, push_to_hub=True, report_to="trackio", max_length=None,)
# Создаём тренерtrainer = SFTTrainer( model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset, peft_config=peft_config,)
# Подстройте параметры SFTTrainer под выбранный датасет.Обучаем и сохраняем модель
Заголовок раздела «Обучаем и сохраняем модель»Запустим цикл обучения:
trainer.train()начинает дообучение с LoRA.trainer.save_model()сохраняет обученную модель локально.
После этого шага модель готова к своим задачам с минимумом дополнительных параметров.
# Обучаем модельtrainer.train()
# Сохраняем модельtrainer.save_model(training_args.output_dir)(Примечание переводчика: на одной RTX 4080 эпоха на 10% ChartQA (около 2800 примеров) идёт порядка десятков минут.
После обучения повторите инференс из упражнения 1 на том же примере и на нескольких примерах из eval_dataset —
так вы увидите, помогло ли дообучение. Для честной проверки посчитайте долю точных совпадений на всей валидационной
части.)
Освоив основы дообучения на Python и LoRA, перенесём этот процесс в продакшн-среду с помощью TRL CLI. Такой подход позволяет автоматизировать дообучение и строить воспроизводимые конвейеры, не написав ни одного полного скрипта на Python.
Упражнение 3: продакшн-процесс с TRL CLI
Заголовок раздела «Упражнение 3: продакшн-процесс с TRL CLI»В прошлых упражнениях мы дообучали SmolVLM2-2.2B-Instruct через API на Python, изучали подготовку датасета и генерировали ответы на промпты в формате чата.
В этом упражнении покажем дообучение через TRL CLI — привычный в продакшне способ. Командная строка позволяет запускать эксперименты и управлять обучением, не создавая скриптов на Python. Если нужно освежить память, мы уже знакомились с этим инструментом в юните 1, и те же идеи и советы по решению проблем применимы здесь.
TRL CLI использует ту же логику и те же параметры, что и API на Python, но через простой интерфейс командной строки. Значит, всё — от модели и датасета до гиперпараметров обучения и папки для результата — можно задать одной командой.
Пример ниже показывает, как дообучить SmolVLM2-2.2B-Instruct на датасете trl-lib/llava-instruct-mix с LoRA для экономного дообучения, смешанной точностью для ускорения и необязательной выгрузкой на Hub. Датасет здесь другой.
Мы берём другой датасет, потому что он уже приведён к ожидаемой для VLM структуре, о которой говорилось выше.
--model_name_or_path— базовая модель для дообучения.--dataset_nameи--dataset_config— датасет и его подмножество.--output_dir— локальная папка для сохранения дообученной модели.--per_device_train_batch_sizeи--gradient_accumulation_steps— эффективный размер батча и расход памяти.--learning_rate,--num_train_epochsи--max_length— основные гиперпараметры обучения.--bf16— смешанная точность для более быстрого и экономного обучения на совместимых GPU.--push_to_hubи--hub_model_id— автоматическая выгрузка обученной модели в ваш репозиторий на Hugging Face Hub.
Использовать TRL CLI — то же самое, что написать полный скрипт обучения на Python, только настраивать быстрее, воспроизводить проще, и это идеально для продакшн-конвейеров и автоматизированного обучения.
trl sft \ --model_name_or_path HuggingFaceTB/SmolVLM2-2.2B-Instruct \ --dataset_name trl-lib/llava-instruct-mix \ --output_dir ./smolvln-instruct-sft-cli \ --per_device_train_batch_size 1 \ --gradient_accumulation_steps 16 \ --learning_rate 2e-4 \ --num_train_epochs 3 \ --max_length -1 \ --logging_steps 5 \ --save_steps 100 \ --warmup_steps 50 \ --bf16 True \ --push_to_hub \ --hub_model_id your-username/smolvlm2-2.2b-instruct-sft-cli(Примечание переводчика: вопреки тексту, в этой команде нет LoRA — это полное дообучение. Чтобы включить LoRA,
добавьте флаги --use_peft --lora_r 8 --lora_alpha 16. Флаг --dataset_config из списка тоже не используется. На
вашей машине обучение можно распределить на все четыре карты: скачайте скрипт trl/scripts/sft.py из репозитория TRL
(тот же, что в упражнении 4) и запустите accelerate launch --num_processes 4 sft.py с теми же аргументами. Три эпохи
на полном llava-instruct-mix — это уже много часов; для пробы поставьте --max_steps 200.)
Упражнение 4: обучение в Hugging Face Jobs
Заголовок раздела «Упражнение 4: обучение в Hugging Face Jobs»В юните 1 мы познакомились с Hugging Face Jobs (HF Jobs) и показали, как дообучить модель с помощью этого управляемого облачного сервиса. HF Jobs даёт полностью управляемую инфраструктуру для обучения: не нужно настраивать GPU, зависимости или окружение локально. Это особенно удобно для обучения SFT, которое может требовать много ресурсов и времени.
Тем же способом можно дообучить и модель «зрение + язык». Если нужно, вернитесь к юниту 1, чтобы освежить в памяти HF Jobs и порядок работы с ними.
Вот пример запуска обучения через поддерживаемый командой TRL скрипт SFT:
# Используем поддерживаемый TRL скрипт SFT напрямуюhf jobs uv run \ --flavor a10g-large \ --timeout 2h \ --secrets HF_TOKEN \ --with num2words==0.5.14 \ "https://raw.githubusercontent.com/huggingface/trl/main/trl/scripts/sft.py" \ --model_name_or_path HuggingFaceTB/SmolVLM2-2.2B-Instruct \ --dataset_name trl-lib/llava-instruct-mix\ --learning_rate 5e-5 \ --per_device_train_batch_size 4 \ --max_length -1 \ --max_steps 1000 \ --output_dir smolvlm2-2.2b-instruct-sft-jobs \ --push_to_hub \ --hub_model_id your-username/smolvlm2-2.2b-instruct-sft-jobs \ --report_to trackioПосле запуска HF Jobs выполнит весь процесс обучения в облаке. Следить за ходом, смотреть логи и метрики можно прямо на Hugging Face Hub.
Когда задание закончится:
- дообученная модель окажется в указанной папке
output_dir; - если был указан
--push_to_hub, модель будет доступна в вашем аккаунте Hugging Face — для инференса или дальнейшего дообучения; - обучение легко возобновить, повторить или масштабировать, перезапустив задание или изменив его конфигурацию.
Такой процесс избавляет от забот о локальных ресурсах и позволяет сосредоточиться на экспериментах с моделью и её оценке.
(Примечание переводчика: в команде пропущен пробел перед \ после llava-instruct-mix — в оболочке это склеит
строки неправильно; поставьте пробел. HF Jobs — платная услуга (нужен тариф Pro и выше); на вашей машине всё делается
локально командой из упражнения 3.)
Проверьте себя
Заголовок раздела «Проверьте себя»Вы прошли юнит — отличная работа! Теперь проверьте знания в тесте.
Материалы для дальнейшего изучения
Заголовок раздела «Материалы для дальнейшего изучения»Полезные материалы, чтобы углубить понимание и продолжить эксперименты с моделями «зрение + язык» и TRL:
- Документация TRL — полный справочник по TRL, включая API на Python и CLI.
- Карточка модели HuggingFaceTB/SmolVLM2-2.2B-Instruct — подробности об архитектуре модели, обучении и использовании.
- Датасет HuggingFaceM4/ChartQA — датасет для обучения и дообучения VLM.
- Hugging Face Hub — площадка, чтобы делиться дообученными моделями и находить модели сообщества.
- Discord-сообщество Hugging Face — обсуждения, помощь и решение проблем.
Словарик
Заголовок раздела «Словарик»| English | Русский |
|---|---|
| Vision Language Model (VLM) | модель «зрение + язык» |
| image encoder, vision encoder | кодировщик изображений |
| projector, fusion module | проектор, модуль слияния |
| processor | процессор (токенизатор + предобработка изображений) |
| image captioning | описание изображений |
| visual question answering (VQA) | ответы на вопросы по изображению |
| grounding | привязка ответа к областям изображения |
| Vision-Language-Action (VLA) | модель «зрение — язык — действие» |
| any-to-any | «что угодно во что угодно» (любые модальности на входе и выходе) |
| OCR (optical character recognition) | распознавание текста на изображениях |
| gradient checkpointing | перерасчёт активаций |
| TRL CLI | командная строка библиотеки TRL |