Я столкнулся с ошибкой IndexError при попытке дообучения модели Qwen 2.5 3B VLM на наборе данных Trelis/chess_pieces с Hugging Face. Ошибка возникает на строке trainer.train() со следующим трейсбэком:
IndexError: index 2 is out of bounds for dimension 0 with size 2
Ошибка происходит в файле processing_qwen2_5_vl.py на строке 177:
num_image_tokens = image_grid_thw[index].prod() // merge_length
Вот моя функция collate:
def collate_fn(samples):
texts = []
images = []
for sample in samples:
prompt_text = processor.apply_chat_template(sample['text'], tokenize=False)
texts.append(prompt_text)
images.append(sample['image'])
inputs = processor(
text=texts,
images=images,
return_tensors='pt',
padding=True
)
labels=inputs['input_ids'].clone()
labels[labels == processor.tokenizer.pad_token_id] = -100
inputs['labels'] = labels
return inputs
Я пробовал различные решения, но не смог решить эту проблему с индексацией. Может кто-нибудь помочь мне определить причину этой ошибки и как её исправить при дообучении Qwen 2.5 3B VLM на наборах изображений?
IndexError, с которым вы сталкиваетесь при тонкой настройке Qwen 2.5 3B VLM, является распространенной проблемой, связанной с несоответствием размерностей тензора image_grid_thw. Эта ошибка обычно возникает, когда модель ожидает определенную структуру тензора, но получает данные с несовместимыми размерностями, что приводит к сбою операции индексации.
Содержание
- Понимание происхождения ошибки
- Анализ основных причин
- Решения и исправления
- Стратегии предотвращения
- Подход к отладке
- Полный пример реализации
Понимание происхождения ошибки
Ошибка index 2 is out of bounds for dimension 0 with size 2 происходит в скрипте обработки на строке 177:
num_image_tokens = image_grid_thw[index].prod() // merge_length
Как указано в GitHub issue, это происходит потому, что тензор image_grid_thw не имеет ожидаемой формы. Модель ожидает, что image_grid_thw будет содержать размеры сетки в формате (T, H, W), но ваш тензор может содержать только 2 элемента вместо ожидаемых 3.
Анализ основных причин
1. Отсутствие размеров сетки изображения
Тензор image_grid_thw критически важен для Qwen2.5-VL, так как он содержит пространственные размеры сетки, которые модель использует для обработки изображений. Когда этот тензор отсутствует или имеет неправильную форму, операция индексации завершается ошибкой.
2. Ограничения функции collate
Ваша текущая функция collate явно не обрабатывает image_grid_thw:
def collate_fn(samples):
texts = []
images = []
for sample in samples:
prompt_text = processor.apply_chat_template(sample['text'], tokenize=False)
texts.append(prompt_text)
images.append(sample['image'])
inputs = processor(
text=texts,
images=images,
return_tensors='pt',
padding=True
)
3. Проблемы с разрешением изображений
Изображения должны быть правильно изменены до размеров, кратных 14 (размер патча для Qwen2.5-VL). Если изображения имеют несовместимые размеры, расчет сетки даст неверные результаты.
4. Несогласованность пакетной обработки
Ошибка может возникать при обработке пакетов со смешанными типами изображений или когда некоторые выборки не содержат действительных данных изображений.
Решения и исправления
Решение 1: Улучшенная функция collate с обработкой image_grid_thw
Измените вашу функцию collate для правильной обработки image_grid_thw:
def collate_fn(samples):
texts = []
images = []
valid_samples = []
# Сначала отфильтровываем недействительные выборки
for sample in samples:
try:
if 'image' in sample and sample['image'] is not None:
prompt_text = processor.apply_chat_template(sample['text'], tokenize=False)
texts.append(prompt_text)
images.append(sample['image'])
valid_samples.append(sample)
except Exception as e:
print(f"Пропуск недействительной выборки: {e}")
if not valid_samples:
raise ValueError("В пакете не найдено действительных выборок")
# Обработка с помощью процессора
inputs = processor(
text=texts,
images=images,
return_tensors='pt',
padding=True
)
# Рассчитываем image_grid_thw вручную, если он не предоставлен
if 'image_grid_thw' not in inputs:
batch_size = len(images)
image_grid_thw = []
for img in images:
# Получаем размеры изображения
if hasattr(img, 'size'): # PIL Image
w, h = img.size
else: # Tensor
h, w = img.shape[-2:]
# Рассчитываем размеры сетки (T=1 для одиночных изображений, H//14, W//14)
grid_h = h // 14
grid_w = w // 14
image_grid_thw.append([1, grid_h, grid_w])
inputs['image_grid_thw'] = torch.tensor(image_grid_thw, dtype=torch.long)
# Настраиваем метки
labels = inputs['input_ids'].clone()
labels[labels == processor.tokenizer.pad_token_id] = -100
inputs['labels'] = labels
return inputs
Решение 2: Предварительная обработка и валидация изображений
Добавьте этапы валидации и предварительной обработки:
def preprocess_image(image):
"""Убедимся, что изображение имеет совместимые размеры для Qwen2.5-VL"""
if hasattr(image, 'size'): # PIL Image
w, h = image.size
else: # Tensor
h, w = image.shape[-2:]
# Проверяем, кратны ли размеры 14
if h % 14 != 0 or w % 14 != 0:
# Изменяем размер до ближайшего кратного 14
new_h = ((h + 13) // 14) * 14
new_w = ((w + 13) // 14) * 14
image = image.resize((new_w, new_h)) if hasattr(image, 'resize') else F.interpolate(image.unsqueeze(0), size=(new_h, new_w)).squeeze(0)
return image
Решение 3: Обработка размера пакета и смешанной точности
# В вашем скрипте обучения
training_args = TrainingArguments(
output_dir="./output",
per_device_train_batch_size=1, # Начните с размера пакета 1
gradient_accumulation_steps=4,
fp16=True, # Смешанная точность может помочь с проблемами памяти
remove_unused_columns=False,
... # другие аргументы
)
# Переопределяем функцию сборки данных
data_collator = collate_fn # Ваша улучшенная функция collate
Стратегии предотвращения
1. Валидация набора данных
Перед обучением валидируйте ваш набор данных:
def validate_dataset(dataset):
issues = []
for i, sample in enumerate(dataset):
try:
if 'image' not in sample or sample['image'] is None:
issues.append(f"Выборка {i}: Отсутствует изображение")
continue
img = sample['image']
if hasattr(img, 'size'):
w, h = img.size
else:
h, w = img.shape[-2:]
if h % 14 != 0 or w % 14 != 0:
issues.append(f"Выборка {i}: Размеры изображения {h}x{w} не кратны 14")
except Exception as e:
issues.append(f"Выборка {i}: {str(e)}")
if issues:
print("Проблемы валидации набора данных:")
for issue in issues[:10]: # Показываем первые 10 проблем
print(f" {issue}")
if len(issues) > 10:
print(f" ... и еще {len(issues) - 10} проблем")
else:
print("Валидация набора данных прошла успешно!")
return len(issues) == 0
2. Управление памятью
# Используем контрольные точки градиента для экономии памяти
model.gradient_checkpointing_enable()
# Включаем эффективное внимание к памяти
from transformers import AutoModelForVision2Seq
model = AutoModelForVision2Seq.from_pretrained(
"Qwen/Qwen2.5-VL-3B-Instruct",
torch_dtype=torch.float16,
device_map="auto",
use_cache=False # Отключаем кэш для обучения
)
Подход к отладке
Пошаговая отладка
- Проверьте состав пакета:
# Добавьте отладку в вашу функцию collate
def debug_collate_fn(samples):
print(f"Обработка пакета из {len(samples)} выборок")
for i, sample in enumerate(samples):
if 'image' in sample:
img = sample['image']
if hasattr(img, 'size'):
print(f"Выборка {i}: Размер изображения {img.size}")
else:
print(f"Выборка {i}: Форма тензора {img.shape}")
- Исследуйте тензор image_grid_thw:
# Добавьте это после вызова вашей функции collate
batch = collate_fn(dataset[:2]) # Тестируем с небольшим пакетом
print(f"Форма image_grid_thw: {batch['image_grid_thw'].shape}")
print(f"Значения image_grid_thw: {batch['image_grid_thw']}")
- Проверьте вывод процессора:
# Тестируем процессор индивидуально
test_samples = dataset[:2]
processor_outputs = processor(
text=[sample['text'] for sample in test_samples],
images=[sample['image'] for sample in test_samples],
return_tensors='pt'
)
print("Ключи процессора:", list(processor_outputs.keys()))
Полный пример реализации
Вот полный рабочий пример, включающий все исправления:
import torch
from transformers import AutoProcessor, AutoModelForVision2Seq, TrainingArguments, Trainer
from torch.utils.data import DataLoader
from PIL import Image
import torchvision.transforms as transforms
# Улучшенная функция collate
def safe_collate_fn(samples):
texts = []
images = []
valid_indices = []
# Фильтруем действительные выборки
for i, sample in enumerate(samples):
try:
if ('image' in sample and sample['image'] is not None and
'text' in sample and sample['text'] is not None):
# Валидируем изображение
img = sample['image']
if hasattr(img, 'size'):
w, h = img.size
if h % 14 != 0 or w % 14 != 0:
# Изменяем размер изображения
new_h = ((h + 13) // 14) * 14
new_w = ((w + 13) // 14) * 14
img = img.resize((new_w, new_h))
sample['image'] = img
texts.append(processor.apply_chat_template(sample['text'], tokenize=False))
images.append(img)
valid_indices.append(i)
except Exception as e:
print(f"Пропуск выборки {i}: {e}")
if not valid_indices:
raise ValueError("В пакете нет действительных выборок")
# Обработка с помощью процессора
inputs = processor(
text=texts,
images=images,
return_tensors='pt',
padding=True,
truncation=True,
max_length=2048
)
# Убеждаемся, что image_grid_thw присутствует
if 'image_grid_thw' not in inputs:
batch_size = len(images)
image_grid_thw = []
for img in images:
if hasattr(img, 'size'):
w, h = img.size
else:
h, w = img.shape[-2:]
grid_h = h // 14
grid_w = w // 14
image_grid_thw.append([1, grid_h, grid_w])
inputs['image_grid_thw'] = torch.tensor(image_grid_thw, dtype=torch.long)
# Настраиваем метки
labels = inputs['input_ids'].clone()
labels[labels == processor.tokenizer.pad_token_id] = -100
inputs['labels'] = labels
return inputs
# Настройка модели и процессора
model_name = "Qwen/Qwen2.5-VL-3B-Instruct"
processor = AutoProcessor.from_pretrained(model_name)
model = AutoModelForVision2Seq.from_pretrained(
model_name,
torch_dtype=torch.float16,
device_map="auto",
use_cache=False
)
# Конфигурация обучения
training_args = TrainingArguments(
output_dir="./chess_finetuned",
per_device_train_batch_size=1,
gradient_accumulation_steps=8,
learning_rate=2e-5,
num_train_epochs=3,
fp16=True,
logging_steps=10,
save_steps=500,
remove_unused_columns=False,
report_to="none"
)
# Создаем тренер
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset,
data_collator=safe_collate_fn,
)
# Начинаем обучение
trainer.train()
Источники
- vLLM Forums - IndexError: list index out of range (Qwen/Qwen2.5-VL-3B-Instruct)
- QwenLM GitHub - Fine-tuning Qwen2.5-VL-7B using Llamafactory fails with IndexError
- F22 Labs - Complete Guide to Fine-tuning Qwen2.5 VL Model
- Roboflow - How to Fine-Tune Qwen2.5-VL with a Custom Dataset
- HuggingFace Transformers - Fine tuning qwen2.5 error
Заключение
IndexError, с которым вы сталкиваетесь при тонкой настройке Qwen 2.5 3B VLM, в основном вызван неправильной обработкой тензора image_grid_thw и несоответствием размерностей при обработке изображений. Реализовав улучшенную функцию collate, добавив правильную валидацию изображений и используя методы отладки, вы можете решить эту проблему и успешно настроить модель на вашем наборе данных шахматных фигур.
Ключевые выводы:
- Всегда валидируйте ваш набор данных перед обучением, чтобы убедиться, что размеры изображений совместимы
- Реализуйте правильную обработку ошибок в вашей функции collate для пропуска недействительных выборок
- Рассчитывайте
image_grid_thwвручную, если процессор не предоставляет его - Начинайте с меньших размеров пакетов и постепенно увеличивайте их по мере валидации процесса
- Используйте методы смешанной точности и оптимизации памяти для эффективной обработки 3B модели
С этими исправлениями вы должны успешно настроить модель Qwen 2.5 3B VLM на вашем наборе данных шахматных фигур без проблем с IndexError.