LoRA петли повторений: исправление ошибок дообучения Qwen2.5-VL-3B | AiManual
AiManual Logo Ai / Manual.
17 Янв 2026 Гайд

Петли повторений в LoRA: как я ломал Qwen2.5-VL-3B и что из этого вышло

Разбор причин возникновения петель повторений после LoRA-дообучения мультимодальной модели Qwen2.5-VL-3B. Практические решения для video reasoning задач.

Когда AI начинает заикаться: откуда берутся эти чертовы повторы

Вы только что дообучили Qwen2.5-VL-3B на своих данных. Параметры вроде бы стандартные: r=32, lr=5e-5, batch_size=4. Модель запускаете - и она начинает выдавать что-то вроде: "The cat is walking. The cat is walking. The cat is walking. The cat is..."

Знакомо? Добро пожаловать в клуб.

Петли повторений после LoRA-дообучения - это не баг, а фича. Фича того, что вы неправильно поняли, как работает мультимодальная модель. Особенно когда речь о video reasoning.

Важно: если вы видите повторяющиеся фразы в выводе модели - это уже поздняя стадия. Проблема началась гораздо раньше.

Почему LoRA ломает Video Reasoning

Qwen2.5-VL-3B - не просто языковая модель. Это гибрид, который должен понимать временную последовательность в видео. И вот что происходит при LoRA-дообучении:

  • Смещение распределения вероятностей: LoRA-адаптеры изменяют веса так, что модель начинает предпочитать «безопасные» токены
  • Потеря временного контекста: Видео - это последовательность кадров. LoRA может нарушить понимание этой последовательности
  • Переобучение на коротких последовательностях: Если в датасете много коротких описаний - модель научится генерировать только их

Вот типичная ошибка, которую все делают (и я в том числе):

# Как НЕ надо делать
lora_config = LoraConfig(
    r=32,
    lora_alpha=64,
    target_modules=["q_proj", "v_proj"],
    lora_dropout=0.1,
    bias="none",
    task_type="CAUSAL_LM"
)

Проблема в том, что для мультимодальных моделей target_modules должны быть другими. И task_type тоже.

💡
Video reasoning модели используют специальные attention механизмы для работы с временными последовательностями. Стандартный LoRA их ломает.

Диагностика: где искать корень проблемы

Прежде чем лечить, нужно понять, что болит. Запустите этот код для диагностики:

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

# Загружаем вашу дообученную модель
model = AutoModelForCausalLM.from_pretrained("./your-lora-model")
tokenizer = AutoTokenizer.from_pretrained("./your-lora-model")

# Тестовый промпт для видео
test_prompt = "Describe the video: A person is opening a door. "
inputs = tokenizer(test_prompt, return_tensors="pt")

# Смотрим распределение вероятностей для первых 10 токенов
with torch.no_grad():
    outputs = model(**inputs)
    logits = outputs.logits
    
# Вычисляем энтропию распределения
probs = torch.softmax(logits[0, -1], dim=-1)
entropy = -torch.sum(probs * torch.log(probs + 1e-10))
print(f"Entropy of next token distribution: {entropy.item()}")

# Если энтропия ниже 2.0 - у вас проблемы

Низкая энтропия = модель уверена в своем выборе. Слишком уверена. Настолько, что будет повторять один и тот же токен вечно.

Пять практических решений (от простого к сложному)

1 Регулировка температуры и repetition_penalty

Самое простое - и самое часто игнорируемое. При инференсе нужно выставить правильные параметры:

# Правильные параметры для video reasoning
generation_config = {
    "temperature": 0.7,           # Не 0.1, как все ставят!
    "repetition_penalty": 1.2,    # Наказываем повторы
    "top_p": 0.9,                # Nucleus sampling
    "top_k": 50,                 # Ограничиваем выбор
    "max_new_tokens": 200,
    "do_sample": True,           # Обязательно True!
    "num_beams": 1               # Beam search ломает видео-описания
}

Temperature=0.7 дает достаточно случайности, чтобы избежать петель. Но это костыль, а не решение.

2 Правильная конфигурация LoRA для мультимодальных моделей

Для Qwen2.5-VL нужно адаптировать не только q_proj и v_proj:

# Правильная конфигурация для Qwen2.5-VL
lora_config = LoraConfig(
    r=16,                      # Меньше rank для видео!
    lora_alpha=32,
    target_modules=[
        "q_proj", "v_proj", "k_proj", "o_proj",
        "gate_proj", "up_proj", "down_proj"  # Для MLP слоев
    ],
    lora_dropout=0.05,         # Меньше dropout
    bias="lora_only",
    task_type="SEQ_2_SEQ_LM",  # Не CAUSAL_LM!
    modules_to_save=["lm_head", "embed_tokens"]  # Важно!
)

r=16 вместо 32 - это ключевое изменение. Видео-модели более чувствительны к изменениям весов.

3 Data augmentation для временных последовательностей

Если ваш датасет состоит из коротких описаний - модель научится только им. Нужно искусственно создавать длинные последовательности:

# Пример аугментации для видео-датасета
def augment_video_description(description, min_length=50):
    """Добавляем временные маркеры в описание"""
    sentences = description.split(". ")
    
    if len(sentences) < 3:
        # Добавляем временные отношения
        augmented = []
        for i, sent in enumerate(sentences):
            if i == 0:
                augmented.append(f"First, {sent}")
            elif i == 1:
                augmented.append(f"Then, {sent}")
            else:
                augmented.append(f"After that, {sent}")
        return ". ".join(augmented)
    
    return description

Это учит модель понимать последовательность событий. Без этого она будет описывать каждый кадр отдельно - и зацикливаться.

4 Scheduled learning rate с warmup

lr=5e-5 - это слишком агрессивно для финальных слоев мультимодальной модели. Нужен schedule:

from transformers import get_cosine_schedule_with_warmup

# Конфигурация обучения
training_args = TrainingArguments(
    learning_rate=3e-5,                    # Меньше!
    warmup_steps=100,                      # Обязательно warmup
    weight_decay=0.01,
    num_train_epochs=3,
    logging_steps=10,
    save_steps=500,
    fp16=True,
    gradient_accumulation_steps=2,
    optim="adamw_8bit"
)

# scheduler
scheduler = get_cosine_schedule_with_warmup(
    optimizer,
    num_warmup_steps=100,
    num_training_steps=len(train_dataloader) * 3
)

Warmup позволяет модели адаптироваться к новым весам постепенно. Без этого первые же шаги градиента ломают временные зависимости.

5 Контрастive learning для избежания коллапса

Самый продвинутый метод - добавить контрастную loss функцию:

class ContrastiveLORATrainer(Trainer):
    def compute_loss(self, model, inputs, return_outputs=False):
        # Стандартная loss
        outputs = model(**inputs)
        loss = outputs.loss
        
        # Добавляем контрастную loss
        logits = outputs.logits
        batch_size = logits.shape[0]
        
        # Вычисляем similarity между последовательными токенами
        # Наказываем за слишком высокую similarity
        contrastive_loss = self.compute_contrastive_loss(logits)
        
        # Комбинируем
        total_loss = loss + 0.1 * contrastive_loss
        
        return (total_loss, outputs) if return_outputs else total_loss
    
    def compute_contrastive_loss(self, logits):
        # Упрощенная реализация
        # На практике нужно использовать proper contrastive learning
        return torch.tensor(0.0)  # Заглушка

Это предотвращает коллапс модели в одно состояние - причину петель повторений.

Чего точно не делать

Ошибка Почему это плохо Что делать вместо этого
Использовать только q_proj, v_proj Не затрагивает MLP слои, отвечающие за временные зависимости Добавлять gate_proj, up_proj, down_proj
lr=5e-5 без warmup Резкие изменения весов ломают attention patterns lr=3e-5 с warmup_steps=100
temperature=0.1 Детерминированный выбор токенов ведет к петлям temperature=0.7, do_sample=True
Обучать на коротких описаниях Модель не учится генерировать длинные последовательности Аугментировать данные с временными маркерами

Проверка работоспособности

После применения всех исправлений, проверьте модель на тестовом видео. Идеальный результат должен выглядеть так:

Input: Describe the video: A person enters a kitchen, opens refrigerator, takes out milk.

Good output: First, a person walks into the kitchen. Then, they approach the refrigerator and open it. After that, they reach inside and take out a carton of milk.

Bad output: The person opens the refrigerator. The person opens the refrigerator. The person opens the refrigerator.

Разница очевидна. Хороший вывод содержит временные маркеры и разнообразную лексику. Плохой - зациклен.

Совет: если после всех исправлений петли остаются - уменьшите rank LoRA до 8. Иногда меньше параметров = лучше результаты для видео.

FAQ: частые вопросы от коллег

Петли появляются только на длинных последовательностях. Почему?

Потому что модель не обучена поддерживать контекст. В коротких последовательностях она еще может "помнить" начало. В длинных - забывает и начинает повторять последнее состояние. Решение - учить на длинных примерах с самого начала.

Можно ли использовать repetition_penalty больше 1.5?

Можно, но осторожно. Слишком высокий repetition_penalty (больше 1.8) заставляет модель избегать любых повторов - даже логических. В видео-описаниях иногда нужно повторить субъект: "The person... the person...". С penalty=2.0 модель будет искать синонимы там, где они не нужны.

Какой датасет лучше для video reasoning?

Не существует идеального датасета. Но есть правило: минимум 30% примеров должны быть длиннее 50 токенов. И в каждом примере должны быть временные маркеры (first, then, after, meanwhile). Без этого модель не научится reasoning.

Что делать, если ничего не помогает

Бывает. Иногда петли повторений - симптом более глубокой проблемы: модель просто не способна к video reasoning в ее текущем виде. В этом случае:

  1. Попробуйте другую архитектуру. Qwen2.5-VL-7B может работать лучше
  2. Используйте двухэтапное обучение: сначала language-only, потом multimodal
  3. Добавьте reinforcement learning с reward за разнообразие вывода

И помните: если вы столкнулись с этой проблемой - вы не одиноки. Петли повторений после LoRA - это обряд посвящения в мир мультимодальных моделей. Пройдя его, вы поймете их внутреннее устройство лучше, чем 90% «специалистов».

А если хотите глубже разобраться в создании датасетов для LoRA, посмотрите мой гайд Как создать датасет для LoRA, который действительно учит модель. Там те же принципы, но для текстовых моделей.