Простой блокнот для точной настройки алгоритмов преобразования изображения в текст с использованием LORA

Цель этой статьи — показать на простом примере записной книжки, как применять алгоритмы LORA для тонкой настройки преобразования изображения в текст. Блокнот будет разработан с использованием библиотек Hugging Face и Peft.

Давайте погрузимся!

1. Что такое ЛОРА?

В области больших языковых моделей проблема точной настройки долгое время ставила исследователей в тупик. Однако Microsoft представила инновационное решение под названием Low-Rank Adaptation (LoRA). С появлением гигантских моделей, таких как GPT-3, которые могут похвастаться миллиардами параметров, стоимость их тонкой настройки для конкретных задач или областей стала непомерно высокой.

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

2. Библиотеки

Чтобы начать работу с блокнотом, представлены библиотеки, которые будут использоваться. Для приложения LORA рекомендуется включить графический процессор. Это достигается с помощью последней строки кода.

import torch
from torch.utils.data import DataLoader, Dataset
from PIL import Image
from transformers import ViTFeatureExtractor, VisionEncoderDecoderModel, AutoProcessor

from datasets import load_dataset
from peft import LoraConfig, get_peft_model

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

3. Набор данных и модель

В этом документе будет использоваться модель vit-gpt2-coco-en by ydshieh. Это модель ViT с быстрой работой и хорошими результатами.

loc = "ydshieh/vit-gpt2-coco-en"

feature_extractor = ViTFeatureExtractor.from_pretrained(loc)
model = VisionEncoderDecoderModel.from_pretrained(loc)
processor = AutoProcessor.from_pretrained(loc)

model = model.to(device)

Напротив, ybelkada/football-dataset становится ценным ресурсом для экспериментов. Несмотря на свой скромный размер (6 изображений), этот набор данных оказывается невероятно полезным для проведения экспресс-тестов и первоначальной проверки функциональности модели.

Он служит удобным инструментом для оценки точности модели и легкого подтверждения ее надлежащего функционирования. Несмотря на небольшой масштаб, набор данных ybelkada/football-dataset предлагает эффективные средства оценки эффективности модели, прежде чем углубляться в более обширные и сложные наборы данных.

dataset = load_dataset("ybelkada/football-dataset", split="train")

4. Адаптируйте набор данных

Реализация LORA основана на библиотеке Peft. Однако при возникновении проблем с преобразованием изображения в текст Peft не идеально подходит для этой конкретной задачи. Следовательно, необходимо выполнить ряд корректировок, чтобы обеспечить полную совместимость. Эти модификации необходимы для повышения эффективности платформы при решении уникальных задач, возникающих при преобразовании изображения в текст.

class ImageCaptioningDataset(Dataset):
    def __init__(self, dataset, processor, feature_extractor):
        self.dataset = dataset
        self.processor = processor
        self.feature_extractor = feature_extractor

    def __len__(self):
        return len(self.dataset)

    def __getitem__(self, idx):
        item = self.dataset[idx]
        encoding = self.feature_extractor(images=item["image"], return_tensors="pt")
        encoding = {k: v.squeeze() for k, v in encoding.items()}
        encoding["text"] = item["prompt"]
        return encoding

train_dataset = ImageCaptioningDataset(dataset, processor, feature_extractor)

В этой реализации мы используем расширение "Набор данных", предоставляемое библиотекой PyTorch. Используя наборы данных PyTorch, мы придерживаемся передовой практики обучения моделей, извлекая выгоду из их эффективности, гибкости и возможности повторного использования. Процесс прост: по мере того, как мы перебираем набор данных, мы извлекаем соответствующие изображения, применяем «feature_extractor» для их кодирования и сохраняем закодированные функции вместе с соответствующими подсказками в словаре.

5. Адаптируйте модель

Следующий шаг в нашем процессе включает в себя адаптацию нашей модели для точной настройки LORA. Эта важная корректировка позволяет нашей модели эффективно использовать возможности LORA. Для этого нам нужно создать экземпляр конфигурации LORA и определить соответствующие параметры. Впоследствии мы перечислим и опишем каждый из них, чтобы адаптировать его к каждому варианту использования.

Кроме того, была включена удобная функция, которая позволяет получить представление о проценте весов, подлежащих модификации. Эта функция обеспечивает прозрачность и четкое понимание того, в какой степени параметры модели будут изменены в процессе тонкой настройки LORA.

# Lora configuration
config = LoraConfig(
    r=16,
    lora_alpha=32,
    lora_dropout=0.05,
    bias="none",
    target_modules=["query","value"],
)

model = get_peft_model(model, config)

## Trainable Params
def print_trainable_parameters(model):
    """
    Prints the number of trainable parameters in the model.
    """
    trainable_params, all_param = 0, 0
    for _, param in model.named_parameters():
        all_param += param.numel()
        if param.requires_grad: trainable_params += param.numel()
    print(f"trainable params: {trainable_params} || all params: {all_param} || trainable %: {100 * trainable_params / all_param}")

print_trainable_parameters(model)

## ------------------------------------------------------------------------------------
## trainable params: 589824 || all params: 239785728 || trainable %: 0.2459796105963404
## ------------------------------------------------------------------------------------

Далее описаны некоторые из основных гиперпараметров, которые можно использовать в конфигурации LORA.

  • r (`int`): параметр внимания Лоры.
  • target_modules(`Union[List[str],str]`): имена модулей, к которым применяется Lora.
  • lora_alpha (`int`):альфа-параметр для масштабирования Lora.
  • lora_dropout (`float`): вероятность выпадения для слоев Lora.
  • fan_in_fan_out (`bool`): установите значение True, если заменяемый слой хранит вес, например (fan_in, fan_out).
  • bias (`str`): тип смещения для Лоры. Может быть «нет», «все» или «lora_only».
  • layers_to_transform (`Union[List[int],int]`): Преобразуемые индексы слоев. Если указан этот аргумент, будут применены преобразования LoRA к индексам слоев, указанным в этом списке. . Если передано одно целое число, оно применит преобразования LoRA к слою с этим индексом.
  • layers_pattern (`str`): имя шаблона слоя, используемое, только если `layers_to_transform` отличается от `None` и если шаблон слоя не входит в общий шаблон слоев.

6. Загрузчик данных

Перед началом тренировки необходимо внести несколько небольших корректировок. Во-первых, функция «собрать» позволяет нам адаптировать ранее адаптированный набор данных для обучения. Здесь вы устанавливаете такие параметры, как batch_size или shuffle среди прочих. Эта функция включает в себя такие вещи, как токенизированный текст или маски внимания. С помощью «процессора» подсказки преобразуются в их токенизированную версию.

def collator(batch):
    processed_batch = {}
    for key in batch[0].keys():
        if key != "text":
            processed_batch[key] = torch.stack([example[key] for example in batch])
        else:
            text_inputs = processor([example["text"] for example in batch], padding=True, return_tensors="pt")
            processed_batch["input_ids"] = text_inputs["input_ids"]
            processed_batch["attention_mask"] = text_inputs["attention_mask"]
    return processed_batch

train_dataloader = DataLoader(train_dataset, shuffle=True, batch_size=3, collate_fn=collator)
optimizer = torch.optim.AdamW(model.parameters(), lr=5e-5)
epochs = 100

В этом случае был применен уменьшенный batch_size из-за небольшого количества изображений. Выбран оптимизатор AdamW с общим количеством 100 эпох Обучение должно занять около 1 минуты.

7. Поезд

Наконец, модель проходит обучение, восстанавливая потери в конце каждой эпохи. Используя эту методологию обучения, мы можем эффективно отслеживать и оптимизировать ход модели, что в конечном итоге приводит к повышению производительности и более точным прогнозам.

loss_list = []
model.train()
for epoch in range(1, epochs+1):
    for idx, batch in enumerate(train_dataloader):
        input_ids = batch.pop("input_ids").to(device)
        pixel_values = batch.pop("pixel_values").to(device, torch.float16)

        outputs = model(pixel_values=pixel_values, labels=input_ids)
        loss = outputs.loss
        
        loss.backward()
        optimizer.step()
        optimizer.zero_grad()

    if epoch % 10 == 0: print(f"Epoch {epoch} done!, Loss: {loss.item()}")
    loss_list.append(loss.item())

С этим последним фрагментом кода блокнот готов. Важно помнить, что код должен быть адаптирован для каждого конкретного случая использования. Кроме того, включите проверочные и тестовые файлы, чтобы убедиться в правильном функционировании модели.

Это простой блокнот, который можно использовать во многих контекстах. Если вы хотите более подробно узнать, как применять LORA к другим алгоритмам, не стесняйтесь посетить репозиторий Peft.

Спасибо за прочтение!

Большое спасибо за прочтение статьи. Если вам понравилось, подписывайтесь на меня в Linkedin.

#глубокоеобучение #python #машинноеобучение #huggingface