Przejdź do treści

DevStyle - Strona Główna
Moje własne AI, czyli jak wytrenować GPT-2 na własnym komputerze (pre-training i fine-tuning) – zwycięski artykuł konkursowy

Moje własne AI, czyli jak wytrenować GPT-2 na własnym komputerze (pre-training i fine-tuning) – zwycięski artykuł konkursowy

Wojciech Bargiel

7 lipca 2025

Backend

Artykuł powstał w ramach konkursu z okazji Dnia Informatyka, w którym zaprosiliśmy do dzielenia się autorskimi tekstami o IT.

🏆 Konkurs wygrał Wojciech Bargiel z Politechniki Śląskiej. 

Jego praca to praktyczny i szczegółowy poradnik: „Moje własne AI, czyli jak wytrenować GPT-2 na własnym komputerze (pre-training i fine-tuning)

To konkretny tekst, który krok po kroku pokazuje, jak samodzielnie przejść przez cały proces: od tokenizacji i przygotowania danych po fine-tuning i uruchomienie modelu. Wszystko lokalnie, z jasno opisanym kodem i realnymi wymaganiami sprzętowymi.

📩 A jeśli też piszesz o szeroko pojętym IT – odezwij się. Szukamy świeżych głosów i ciekawych perspektyw.

📝 No to czytamy:

Witaj czytelniku!

 

W tym artykule opowiem Ci, jak całkowicie od podstaw wytrenować własny model sztucznej inteligencji GPT-2, czyli prekursora współczesnych modeli ChatGPT, w domu na własnym komputerze. Dowiesz się nie tylko, jak stworzyć i rozwijać własną sztuczną inteligencję generującą tekst, ale także lepiej zrozumiesz sposób działania tej technologii. Wiedza ta jest coraz bardziej przydatna w branży IT.

 

Trudno zaprzeczyć faktowi, że generatywna sztuczna inteligencja zmieniła świat na zawsze. Od premiery usługi ChatGPT stworzonej przez OpenAI w 2022 roku, generatywna sztuczna inteligencja typu LLM (Large Language Model – Duży Model Językowy) stała się bardzo istotnym narzędziem dla ludzi na całym świecie. Ta rewolucja technologiczna doprowadziła też do powstania wielu konkurencyjnych rozwiązań, takich jak Claude firmy Anthropic, Llama od korporacji Meta, Gemini od Google’a czy R1 od DeepSeek.

 

W tym artykule będziemy jednak pracować z modelem GPT-2 (skrót od Generative Pre-trained Transformer 2) stworzonym przez OpenAI w 2019 roku. Choć jest to stosunkowo stary model, który jest z założenia przewidziany jako czysty generator tekstu a nie model do prowadzenia konwersacji, jest on dobry do nauki jak działa generatywna sztuczna inteligencja. Dla najmniejszego rodzaju modelu GPT-2 oraz ilości danych rzędu kilkuset megabajtów, możliwe jest jego wytrenowanie w czasie od kilku godzin do kilku dni na dostępnym komercyjnie komputerze do gier. Poznanie związanych z tym procesów dla jednego modelu znacząco uprości ich zrozumienie dla wszystkich innych. Na końcu opowiem, jak można uzyskać efekt konwersacji z użytkownikiem.

 

Zanim jednak przejdę do praktyki, opowiem jak działa ta technologia. Pozwoli Ci to lepiej zrozumieć ten poradnik. Nie będę jednak wchodzić w szczegóły, takie jak dokładne algorytmy użyte wewnątrz GPT czy stojąca za jego działaniem matematyka. Opisanie tego wszystkiego wymagałoby osobnego artykułu, dłuższego niż ten.

 

LLMy, czyli duże modele językowe, operują na tokenach. Tokenami mogą być:

  • Całe słowa, np. “komputer”, “budynek”.
  • Fragmenty słów, np. sylaby (“kom”, “pu”, “ter” | “bu”, “dy”, “nek”).
  • Pojedyncze znaki (litery, cyfry, znaki specjalne i interpunkcyjne).

 

Programy i algorytmy, które dzielą tekst na tokeny nazywają się tokenizerami. Wybór najlepszego tokenizera zależy od wykorzystywanego modelu LLM oraz jego późniejszego zastosowania i oczekiwanych rezultatów. Najczęściej stosuje się tokenizery, które dzielą słowa na fragmenty pozwalające na zachowanie reguł gramatycznych (np. odmiany), oraz tworzące jednoznakowe tokeny ze znaków interpunkcyjnych czy matematycznych.

 

W czasie trenowania modelu, ten uczy się prawdopodobieństwa wystąpienia poszczególnych tokenów w zależności od wszystkich poprzednich. Zilustruję to na przykładzie:

 

Wytrenowany model otrzymał na wejściu tekst “Cześć” i ma kontynuować jego pisanie. Na podstawie danych treningowych nauczył się wzorca, że po “Cześć” najczęściej występuje przecinek, więc takowy dodaje. Teraz ma tekst “Cześć,” i najbardziej prawdopodobnym kolejnym tokenem jest “co”, więc dodaje to słowo. W ten sposób model buduje po kolei całą wypowiedź:

“Cześć”
“Cześć,”
“Cześć, co”
“Cześć, co u”
“Cześć, co u ciebie”
“Cześć, co u ciebie?”

 

Proces ten bazuje na wyuczonym wcześniej prawdopodobieństwie. Jeżeli na przykład wg. danych treningowych po tekście “Cześć, co u” jest 1/4 szans na token “was” oraz 3/4 szans na token “ciebie”, ten zostanie wybrany zgodnie z tym prawdopodobieństwem wystąpienia (dodatkowy wpływ na to mają jeszcze inne parametry i ustawienia AI, takie jak Temperatura, ale wspomnę o nich później).

 

Generowanie zwykle kończy się, kiedy zostanie osiągnięty odgórny limit tokenów. Można także analizować znaki białe, jak koniec linii, lub zdefiniować token specjalny, np. <STOP> i wytrenować model na danych z tym tokenem w taki sposób, aby ten sam “stwierdzał”, kiedy zakończyć dalsze generowanie poprzez napisanie go, co w programie korzystającym z LLM wymusi zatrzymanie procesu. W modelach GPT token stopu to “eos_token” o ID 50256, nie posiada on symbolu czytelnego dla człowieka. To ten token należy wykorzystywać w tym celu zamiast definiować własny.

 

Przejdę teraz do procesu trenowania modelu GPT-2 od podstaw. Składa się on z następujących kroków:

  1. Zebranie danych treningowych.
  2. Przetworzenie danych treningowych przed tokenizacją (oczyszczenie i sformatowanie).
  3. Tokenizacja.
  4. Pierwotne trenowanie modelu (pre-training). Wykonuje się je na danych ogólnych, ponieważ celem tego kroku jest nauczenie modelu języka i jego gramatyki.
  5. Fine-tuning, czyli dalsze trenowanie. Można je wykonywać dowolną ilość razy.

 

To na etapie fine-tuningu uczy się znający już język model na konkretnych przypadkach, aby ukształtować jego styl i format odpowiedzi. To wtedy także najlepiej uczy się AI korzystania z tokenów specjalnych. Można także uczyć modelu nowych informacji, czy wykonywać fine-tuning na jego wcześniejszych prawidłowych odpowiedziach aby zwiększyć szansę ich ponownego wystąpienia w przyszłości (zmniejszyłoby to jednak różnorodność odpowiedzi).

 

Warto także zaznaczyć, że gotowe zestawy danych treningowych oraz wytrenowane GPT-2 są dostępne w internecie na stronach takich jak Hugging Face. Można więc pobrać gotowy, ogólny, wytrenowany model a następnie tylko dokonać jego fine-tuningu do zadania, jakie ma pełnić. Bez dostępu do potężnego komputera chmurowego, zalecany jest tylko fine-tuning gotowych modeli ze względu na wymogi i długi czas potrzebny do pre-trainingu dobrego modelu.

 

Skoro już omówiliśmy całą potrzebną teorię, możemy przejść do praktyki i wytrenować własny model GPT-2 od podstaw.

 

Pre-training, szczególnie na dużej ilości danych rzędów dziesiątek lub setek gigabajtów (co jest wymagane, aby stworzyć dobry model), może trwać nawet wiele tygodni i wymaga ogromnej mocy obliczeniowej (szczególnie wielu GPU), dlatego zalecam przeprowadzić go w chmurze (np. AWS, Microsoft Azure, Google Cloud). Fine-tuning oraz pre-training na bardzo małej ilości danych da się jednak wykonać w przyzwoitym czasie na własnym komputerze w domu, zalecam do tego następującą specyfikację minimalną:

 

  • GPU GeForce RTX 3070 lub lepsze, ze wsparciem CUDA.
  • CPU Intel Core i7, i9 lub lepsze (minimum 12-16 wątków i prędkość ponad 3 GHz).
  • Dysk SSD, minimum 50 GB wolnej przestrzeni + trzykrotność wielkości danych treningowych.
  • Minimum 32 GB pamięci RAM.
  • Zasilacz awaryjny UPS, aby nie dopuścić do wyłączenia się komputera i nie utracić danych.

 

W tym poradniku będziemy pracować lokalnie w systemie Windows (ten kod zadziała także na Linuxie) i z użyciem Python 3.11 dla szybkiego efektu na bardzo małej ilości danych (praktycznie zbyt małej, aby stworzyć model, który by się do czegoś nadawał, ale pozwalającej pokazać całą procedurę trenowania).

 

Na samym końcu tego artykułu umieściłem link do repozytorium GitHub z całym kodem z tego poradnika oraz linki do repozytoriów GPT-2 na GitHub i Hugging Face.

 

1. Zebranie danych

 

Jeżeli zdecydujemy się na trenowanie modelu od zera, potrzebujemy danych treningowych pozwalających mu na zrozumienie języka. To jeszcze nie będą konkretne przypadki mające na celu ukształtowanie odpowiedzi, to dopiero robi się na etapie fine-tuningu.

 

Można znaleźć i wykorzystać gotowe zbiory treningowe albo samemu pobrać wiele tekstów z różnych stron internetowych. Należy zawsze przestrzegać praw autorskich i użytkowania, najbezpieczniej pod tym względem jest wykorzystywać treści znajdujące się w domenie publicznej. Należy jednak nadal pamiętać, że nawet gdy oryginalne dzieła literackie mogą już nie być chronione same w sobie, ewentualne tłumaczenia, dodatki, czy przypisy do nich mogą dalej podlegać prawu autorskiemu.

 

Następnym krokiem jest oczyszczenie danych treningowych. Należy usunąć zbędne dane mogące mieć negatywny wpływ na trening (np. symbole HTML w danych pobranych ze stron internetowych). Dane należy zapisać w plikach .txt kodowanych w UTF-8, zalecane jest aby w miarę możliwości każdy miał od 100 do 500 MB. Poszczególne osobne bloki tekstu należy rozdzielić wewnątrz pliku podwójnym znakiem nowej linii, poza tym należy usuwać zbędne białe znaki. Odradzam segmentowania tekstu na pojedyncze zdania, jednym blokiem tekstu powinien być jeden pełny tekst, jak cały dokument lub książka.

 

Napisałem przykładową funkcję w Python, która odpowiednio formatuje i dodaje blok tekstu do pliku treningowego:

 

import re

def przetworz_i_zapisz(tekst: str, nazwa_pliku: str, dodaj_dwa_newline = True):

    tekst = tekst.strip()

    tekst = tekst.replace("\t", " ")

    tekst = re.sub(r"+", "", tekst)

    tekst = re.sub(r" {2,}", " ", tekst)

    if dodaj_dwa_newline:

        tekst += ""

    plik = open(nazwa_pliku, mode="a", encoding="utf-8")

    plik.write(tekst)

    plik.close()

 

Funkcja ta usuwa białe znaki z początku i końca tekstu, zastępuje wielokrotne spacje i znaki nowych linii jednymi oraz zastępuje tabulacje spacjami. Następnie, jeżeli ostatni argument funkcji jest ustawiony na domyślne dla niego True, dodaje na końcu podwójny znak nowej linii. Po przetworzeniu tak tekstu ten jest dodawany do pliku tekstowego (należy pamiętać o rozszerzeniu .txt).

 

Agregację tekstu polecam jednak wykonywać w szybszym języku programowania, takim jak C++, ze względu na wydajność.

 

Załóżmy, że zagregowaliśmy cały tekst do odpowiednio sformatowanych plików .txt, które są zapisane w folderze “gotowe_dane”.

 

2. Tokenizacja

Skoro już mamy gotowe dane, przyszła pora na przetworzenie ich na tokeny. GPT-2 korzysta z tokenizera ByteLevelBPETokenizer dostępnego w bibliotece Python tokenizers. Stwórzmy w folderze, w którym pracujemy folder “modele” a w nim podfolder “tokenizer”.

 

Wykorzystajmy następujący kod:

 

from tokenizers import ByteLevelBPETokenizer




tokenizer = ByteLevelBPETokenizer()




tokenizer.train(

    files=["gotowe-dane/tekst1.txt", "gotowe-dane/tekst2.txt"],

    vocab_size=50257,

    min_frequency=1,

    special_tokens=["<s>", "<pad>", "</s>", "<unk>", "<mask>"]

)




tokenizer.save_model("modele/tokenizer")



W tym kodzie na początku importujemy i inicjujemy tokenizer, następnie wykorzystujemy metodę train() do wygenerowania danych, po czym zapisujemy je do folderu tokenizer w folderze modele.

Metoda tokenizer.train() ma następujące argumenty:

  • files – tablica zawierająca ścieżki do plików wejściowych.
  • vocab_size – rozmiar słownika, czyli maksymalna ilość zapamiętanych tokenów, dla GPT-2 wynosi ona 50257.
  • min_frequency – minimalna ilość wystąpień tokenu, aby dodać go do słownika. Pozwala to pominąć tokeny, które pojawiły się w tekście zbyt rzadko, aby miały znaczenie. Zalecam ustawić tą wartość na minimum 2, choć tutaj ustawiłem 1 ze względu na niezwykle mały rozmiar danych treningowych.
  • special_tokens – tablica tokenów specjalnych, jeżeli jakieś słowo się w niej pojawi, tokenizer nie będzie próbował rozbijać go na mniejsze części. Należy na pewno wpisać tam co najmniej to, co w powyższym przykładzie.

 

Jeżeli proces się uda, w folderze tokenizer znajdziemy pliki merges.txt oraz vocab.json

 

3. Pre-training, czyli trenowanie pierwotne tworzące pierwszą wersję modelu

 

Teraz możemy wykonać pre-training. Najpierw zainstalujmy potrzebne biblioteki Python:

pip install transformers datasets accelerate

 

Teraz możemy uruchomić ten kod:

 

import os

from transformers import (

    GPT2Config,

    GPT2LMHeadModel,

    GPT2TokenizerFast,

    DataCollatorForLanguageModeling,

    Trainer,

    TrainingArguments,

)

from datasets import load_dataset




def main():

    #Ładujemy tokenizer z wcześniej wytrenowanego modelu

    tokenizer = GPT2TokenizerFast.from_pretrained("modele/tokenizer", add_prefix_space=True)




    #Dodaj pad_token, to taki token wypełniacza przydatny modelowi aby wyrównać długość batchy

    tokenizer.add_special_tokens({"pad_token": "<|pad|>"})




    #Konfiguracja modelu (117M: 12 warstw, 12 głów (analizują tekst), dim=768)

    config = GPT2Config(

        vocab_size=len(tokenizer), #Liczba tokenów w słowniku

        n_positions=1024, #Maksymalna długość tekstu do przetwarzania

        n_ctx=1024, #Długość kontekstu, który model może "widzieć" naraz

        n_embd=768, #Wymiar reprezentacji każdego tokena

        n_layer=12, #Liczba warstw w modelu

        n_head=12, #Liczba głów w warstwie uwagi

        pad_token_id=tokenizer.pad_token_id, #ID tokenu paddingu

        bos_token_id=tokenizer.bos_token_id, #ID tokenu początku sekwencji

        eos_token_id=tokenizer.eos_token_id, #ID tokenu końca sekwencji

    )

    model = GPT2LMHeadModel(config) #Tworzymy model GPT-2 z powyższą konfiguracją




    #Wczytanie surowych tekstów

    dataset = load_dataset("text", data_files={"train": "gotowe-dane/*.txt"})

    

    #Tokenizacja (funkcja mapująca na tokeny) - Tokenizujemy dane wejściowe na tokeny

    def tokenize_batch(data):

        return tokenizer(

            data["text"],

            truncation=True, #Obcinamy zbyt długie sekwencje

            max_length=1024, #Maksymalna długość sekwencji w tokenach dla GPT-2

            return_special_tokens_mask=False, #Nie zwracamy maski dla specjalnych tokenów

        )




    tokenized = dataset.map(

        tokenize_batch, #Używamy zdefiniowanej wyżej funkcji do tokenizacji

        batched=True, #Przetwarzanie wsadowe (większe partie danych)

        remove_columns=["text"], #Usuwamy oryginalną kolumnę tekstową

        num_proc=14, #Liczba procesów do równoległego przetwarzania

    )




    #Data collator - przygotowuje dane do treningu

    data_collator = DataCollatorForLanguageModeling(

        tokenizer=tokenizer,

        mlm=False, #Używamy auto-regresyjnego modelu języka (GPT nie używa MLM)

        pad_to_multiple_of=8 #Ustalamy długość batcha, by dopasować do GPU

    )




    #Argumenty treningowe - Konfiguracja procesu treningowego

    training_args = TrainingArguments(

        output_dir="modele/gpt2-pretrained-tmp", #Katalog, w którym będą przechowywane wyniki tymczasowe

        overwrite_output_dir=True, #Nadpisanie istniejącego katalogu wyników

        num_train_epochs=3, #Liczba epok (iteracji)

        per_device_train_batch_size=4, #Rozmiar batcha na jednym urządzeniu (GPU/CPU)

        gradient_accumulation_steps=8, #Symulacja większego batcha bez zwiększania pamięci GPU

        learning_rate=5e-5, #Współczynnik uczenia, czyli prędkość

        weight_decay=0.01, #Współczynnik decay, zapobiega przeuczeniu

        logging_steps=500, #Co ile kroków logować wyniki

        save_steps=2000, #Co ile kroków zapisywać model

        fp16=True, #Użycie obliczeń w połówkowej precyzji (wymaga kompatybilnego GPU)

        dataloader_num_workers=4, #Liczba procesów ładujących dane

        run_name="gpt2-pretraining", #Nazwa eksperymentu

    )




    #Tworzymy trenera, który zarządza procesem treningu

    trainer = Trainer(

        model=model,

        args=training_args,

        data_collator=data_collator,

        train_dataset=tokenized["train"], #Dane treningowe

    )




    #Rozpoczynamy trening i zapisujemy ostateczny model

    trainer.train()

    trainer.save_model("modele/gpt2-pretrained")




if __name__ == "__main__":

    main()



Kod ten trenuje nasz model od podstaw. Najpierw wczytuje wcześniej przygotowany tokenizer i dodaje specjalny token służący jako wypełniacz. Następnie konfiguruje minimalną architekturę GPT-2 Small (117 milionów parametrów). Dane są następnie wczytywane z plików tekstowych, tokenizowane i przygotowane do procesu uczenia przez tzw. collator. Następnie konfigurowane są parametry treningu, wykorzystywana jest do tego biblioteka Trainer. Model uczy się przewidywać tokeny na podstawie poprzednich (autoregresja). Dane tymczasowe są zapisywane w folderze modele/gpt2-pretrained-tmp, a ostateczny model w gpt2-pretrained.

 

W wyniku uruchomienia tego kodu powstaną pliki modelu, które łącznie będą miały ok. 345 MB:

  • config.json
  • generation_config.json
  • pytorch_model.bin
  • training_args.bin

 

4. Uruchomienie modelu.

 

Aby użyć wytrenowanego przez nas modelu, możemy wykorzystać taki kod:

 

import torch

from transformers import GPT2LMHeadModel, GPT2TokenizerFast




#Wczytaj tokenizer i model

tokenizer = GPT2TokenizerFast.from_pretrained("modele/tokenizer")

model = GPT2LMHeadModel.from_pretrained("modele/gpt2-pretrained")

model.eval()




#Wykonuj obliczenia na GPU z użyciem CUDA, chyba że jest niedostępne to na CPU

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

model.to(urzadzenie)




print("Model wczytany.")




while True:

    #Wpisywanie tekstu

    prompt = input("Podaj prompt (lub naciśnij Enter, aby zakończyć): ").strip()

    if not prompt:

        print("Zakończono.")

        break




    #Tokenizacja wejścia

    wejscia = tokenizer(prompt, return_tensors="pt").to(urzadzenie)




    #Wyjście

    wyjscia = model.generate(

        wejscia["input_ids"], #Identyfikatory tokenów wejściowych

        max_length=100, #Długość tekstu wynikowego w tokenach

        do_sample=True, #Wybieraj tokeny losowo na podstawie prawdopodobieństw wystąpienia, wymagane dla GPT

        top_k=10, #Ogranicza wybór do 10 najwyżej ocenianych tokenów, co zwiększa różnorodność generowanego tekstu

        top_p=0.95, #Używa techniki nucleus sampling, wybierając tokeny, które łącznie mają prawdopodobieństwo co najmniej 0.95

        temperature=0.8, #Kontroluje losowość generowania; niższe wartości prowadzą do bardziej deterministycznych wyników

        num_return_sequences=1 #Liczba generowanych sekwencji; w tym przypadku model zwróci jedną sekwencję

    )





    generated_text = tokenizer.decode(wyjscia[0], skip_special_tokens=True)

    print("Wygenerowany tekst:" + generated_text + "")



Na początku wczytywany jest tokenizer oraz sam model AI, następnie kod sprawdza dostępność technologii CUDA, wybierając, czy wykonać kod na GPU czy CPU. Następnie pobierane jest wejście i generowana odpowiedź. Dwa najważniejsze parametry metody generate() to długość maksymalna w tokenach i temperatura. Ten drugi parametr definiuje losowość wybierania tokenów, jego zmniejszenie zwiększa deterministyczność (przewidywalność) odpowiedzi.

 

Uruchommy więc nasz model. zacznijmy tekst od “Pewnego razu”, a on niech kontynuuje:

Model zadziałał! Ale wygenerowany tekst nie ma sensu. Było to jednak do przewidzenia – tak jak napisałem wcześniej, wytrenowanie modelu, który by się do czegoś nadawał, wymaga dziesiątek

gigabajtów danych treningowych. Tymczasem, dla natychmiastowego rezultatu, ten model został wytrenowany tylko na ok. 20 KB treści. 

 

5. Fine-tuning, czyli dalsze trenowanie

 

Mając gotowy model, czy to własny, czy pobrany z Internetu, możemy wykonać na nim Fine-tuning, czyli dalsze trenowanie. Kod wykonujący to wygląda tak:

 

import os

from transformers import (

    GPT2LMHeadModel,

    GPT2TokenizerFast,

    DataCollatorForLanguageModeling,

    Trainer,

    TrainingArguments,

)

from datasets import load_dataset




def main():

    #Ładujemy tokenizer z wcześniej wytrenowanego modelu

    tokenizer = GPT2TokenizerFast.from_pretrained("modele/tokenizer", add_prefix_space=True)




    #Dodaj pad_token, to taki token wypełniacza przydatny modelowi aby wyrównać długość batchy

    tokenizer.add_special_tokens({"pad_token": "<|pad|>"})




    #Wczytujemy wstępnie wytrenowany model GPT-2

    model = GPT2LMHeadModel.from_pretrained("modele/gpt2-pretrained")




    #Dostosowujemy macierz embeddingów do nowego rozmiaru słownika (po dodaniu pad_token)

    model.resize_token_embeddings(len(tokenizer))




    #Ustawiamy ID pad_tokenu w konfiguracji modelu

    model.config.pad_token_id = tokenizer.pad_token_id




    #Wczytanie surowych tekstów do fine-tuningu (nie ma ich w tym repozytorium)

    dataset = load_dataset("text", data_files={"train": "dane-fine-tuning/*.txt"})

    

    #Tokenizacja (funkcja mapująca na tokeny) - Tokenizujemy dane wejściowe na tokeny

    def tokenize_batch(data):

        return tokenizer(

            data["text"],

            truncation=True, #Obcinamy zbyt długie sekwencje

            max_length=1024, #Maksymalna długość sekwencji w tokenach dla GPT-2

        )




    tokenized = dataset.map(

        tokenize_batch, #Używamy zdefiniowanej wyżej funkcji do tokenizacji

        batched=True, #Przetwarzanie wsadowe (większe partie danych)

        remove_columns=["text"], #Usuwamy oryginalną kolumnę tekstową

        num_proc=14, #Liczba procesów do równoległego przetwarzania

    )




    #Data collator

    data_collator = DataCollatorForLanguageModeling(

        tokenizer=tokenizer,

        mlm=False, #GPT-2 jest modelem auto-regresyjnym, nie MLM

    )




    #Argumenty treningowe - konfiguracja procesu fine-tuningu

    training_args = TrainingArguments(

        output_dir="modele/gpt2-finetuned-tmp", #Katalog tymczasowy na model po fine-tuningu

        overwrite_output_dir=True, #Nadpisanie istniejącego katalogu wyników

        num_train_epochs=2, #Liczba epok (iteracji) fine-tuningu

        per_device_train_batch_size=4, #Rozmiar batcha na jednym urządzeniu

        gradient_accumulation_steps=4, #Symulacja większego batcha

        learning_rate=3e-5, #Mniejszy learning rate na fine-tuning

        weight_decay=0.01, #Zapobieganie przeuczeniu

        logging_steps=100, #Co ile kroków logować metryki

        save_steps=500, #Co ile kroków zapisywać checkpoint

        save_total_limit=2, #Ile ostatnich checkpointów trzymać

        fp16=True, #Użycie half-precision jeśli GPU wspiera

        dataloader_num_workers=0, #Na Windowsie często 0 lub 1

        run_name="gpt2-finetuning", #Nazwa eksperymentu fine-tuningowego

    )




    #Tworzymy trenera, który zarządza procesem fine-tuningu

    trainer = Trainer(

        model=model,

        args=training_args,

        data_collator=data_collator,

        train_dataset=tokenized["train"], #Dane do fine-tuningu

    )




    #Rozpoczynamy fine-tuning i zapisujemy ostateczny model oraz tokenizer

    trainer.train()

    trainer.save_model("modele/gpt2-finetuned")

    tokenizer.save_pretrained("modele/gpt2-finetuned")




if __name__ == "__main__":

    main()



Kod ten jest w wielu miejscach podobny do tego wykonującego pre-training. Na początku jest ładowany wcześniej wytrenowany tokenizer GPT-2 i dodawany do niego specjalny token wypełniający. Następnie są wczytywane surowe pliki tekstowe przeznaczone do fine-tuningu, a potem są one mapowane wsadowo na tokeny, obcinane są dłuższe sekwencje do maksymalnej długości 1024 tokenów. Jest tworzony tzw. collator, który przygotuje dane do procesu trenowania. Potem są definiowane argumenty treningowe: gdzie będą zapisywane checkpointy, ile epok będzie trenowanych, batch size, akumulacja gradientów, learning rate, zapis co ile kroków, limit checkpointów, użycie FP16 itp. (szczegóły, co one oznaczają są w komentarzach w kodzie). Na koniec jest inicjalizowany obiekt Trainer z modelem, danymi i konfiguracją, jest wywoływany trainer.train(), a po zakończeniu jest zapisywany finalny model i tokenizer do katalogu modele/gpt2-finetuned. Pliki txt do fine-tuningu powinny mieć taki sam format jak dla pre-trainingu, oraz tak samo mieć wygenerowany już tokenizer.

 

Czy da się zrobić czat z GPT-2? Oczywiście że tak! Trzeba stworzyć i wykorzystać tokeny specjalne, np. <BOT-MESSAGE-START>, <BOT-MESSAGE-END>, <USER-MESSAGE-START>, <USER-MESSAGE-END>. Następnie w procesie Fine-tuningu trzeba wytrenować model na danych w stylu konwersacji opatrzonymi tymi tokenami. Dzięki temu wysyłając wiadomość na wejściu będzie ona między tagami START i END wiadomości użytkownika, po czym GPT-2 doda tekst odpowiedzi pomiędzy własnymi tagami początku i końca. W aplikacji można wykorzystać te tagi, aby rozpoznawać wiadomości i np. rysować bańki w chacie.

 

Dziękuję Ci za przeczytanie mojego artykułu. Mam nadzieję, że dzięki temu lepiej rozumiesz jak działa sztuczna inteligencja generująca tekst oraz jak ją tworzyć i trenować. Z użyciem tej technologii można stworzyć tak wiele, nie tylko standardowe generatory tekstu czy chatboty. Może Twój GPT będzie generował sekwencje dźwięków i tym samym muzykę, albo tworzył modele 3D generując pozycje wierzchołków? Możliwości są niezliczone!

 

Powodzenia we własnych projektach!

 

Linki:

Repozytorium GitHub z kodem z tego artykułu (bez wynikowych modeli, są za duże):

https://github.com/Wojtekb30/Trenowanie-GPT2 

Repozytorium GPT-2 na GitHub:

https://github.com/openai/gpt-2 

Repozytorium GPT-2 na Hugging Face:

https://huggingface.co/openai-community/gpt2 

 

Zobacz również