Прост бележник за фина настройка на алгоритми за преобразуване на изображение в текст с помощта на LORA

Целта на тази статия е да покрие прост пример за тетрадка как да приложите LORA за фина настройка на изображение към текст алгоритми. Бележникът ще бъде разработен с помощта на библиотеките Hugging Faceи Peft.

Да се ​​потопим!

1. Какво е LORA?

В областта на големите езикови модели предизвикателството за фина настройка отдавна обърква изследователите. Microsoft обаче представи иновативно решение, наречено Адаптация от нисък ранг (LoRA). С появата на гигантски модели като GPT-3, които могат да се похвалят с милиарди параметри, разходите за фината им настройка за конкретни задачи или домейни станаха прекомерни.

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

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

Като начало с бележника са представени библиотеките, които ще се използват. За приложението LORA се препоръчва GPU да е активиран. Това се постига с последния ред на кода.

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 от 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. Може да бъде „няма“, „всички“ или „lora_only“ modules_to_save (`List[str]`): Списък на модулите, освен LoRA слоевете, които да бъдат зададени като обучаеми и запазени в крайната контролна точка.
  • layers_to_transform (`Union[List[int],int]`): Индексите на слоя за трансформиране, ако този аргумент е указан, той ще приложи LoRA трансформациите върху индексите на слоя, които са посочени в този списък . Ако бъде предадено едно цяло число, то ще приложи LoRA трансформациите върху слоя при този индекс.
  • layers_pattern (`str`): Името на шаблона на слоя, използвано само ако `layers_to_transform` е различно от `None` и ако шаблонът на слоя не е в общия шаблон на слоевете.

6. Зареждане на данни

Преди да започнете обучението, е необходимо да направите няколко малки корекции. Първо, функцията “collect” ни позволява да адаптираме предварително адаптирания набор от данни за обучение. Тук задавате параметри като 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 repository.

Благодаря за четенето!

Благодаря ви много, че прочетохте статията. Ако ви е харесало, не се колебайте да ме последвате в Linkedin.

#deeplearning #python #machinelearning #huggingface