5-vrstično generiranje besedila v slogu GPT v Pythonu s TensorFlow/Keras

Transformerji, čeprav so bili izdani leta 2017, so začeli pridobivati ​​veliko pozornosti šele v zadnjih nekaj letih. S širjenjem tehnologije prek platform, kot so HuggingFace, NLP in Veliki jezikovni modeli (LLM) so postale bolj dostopne kot kdaj koli prej.

Pa vendar – kljub vsemu pompu okoli njih in z njimi več teoretično usmerjenih vodnikov, na spletu ni veliko implementacij po meri in viri niso tako hitro dostopni kot pri nekaterih drugih vrstah omrežij, ki so prisotna že dlje. Medtem ko bi lahko poenostavili svoj delovni cikel z uporabo vnaprej pripravljenega transformerja HuggingFace (tema drugega vodnika) – lahko pridete do občutek kako deluje tako, da ga zgradite sami, preden ga abstrahirate skozi knjižnico. Tu se bomo osredotočili na gradnjo, ne pa na teorijo in optimizacijo.

V tem priročniku bomo gradili Avtoregresivni jezikovni model do ustvarite besedilo. Osredotočili se bomo na praktične in minimalistične/jedrnate vidike nalaganja podatkov, njihovega razdeljevanja, vektorizacije, gradnje modela, pisanja povratnega klica po meri in usposabljanja/sklepanja. Vsako od teh nalog je mogoče razdeliti v podrobnejše vodnike, zato bomo izvedbo ohranili kot generično, pri čemer bomo pustili prostor za prilagajanje in optimizacijo glede na vaš nabor podatkov.

Vrste LLM in GPT-Fjodor

Medtem ko je lahko kategorizacija veliko bolj zapletena - lahko splošno kategorizirajte jezikovne modele, ki temeljijo na Transformerju, v tri kategorije:

  • Modeli, ki temeljijo na kodirniku – ALBERT, BERT, DistilBERT, RoBERTa
  • Na osnovi dekoderja – GPT, GPT-2, GPT-3, TransformerXL
  • Modeli Seq2Seq – BART, mBART, T5

Na osnovi kodirnika modeli uporabljajo le kodirnik Transformer v svoji arhitekturi (običajno zloženi) in so odlični za razumevanje stavkov (razvrščanje, prepoznavanje imenovanih entitet, odgovarjanje na vprašanja).

Na osnovi dekoderja modeli v svoji arhitekturi uporabljajo samo dekoder Transformer (tudi običajno zloženi) in so odlični za napovedovanje prihodnosti, zaradi česar so primerni za generiranje besedila.

Seq2Seq modeli združujejo kodirnike in dekodirnike in so odlični pri generiranju besedila, povzemanju in kar je najpomembnejše – prevajanju.

Družina modelov GPT, ki je v zadnjih nekaj letih pridobila veliko pozornosti, so transformatorski modeli, ki temeljijo na dekoderju, in so odlični pri izdelavi besedila, podobnega človeku, ki so usposobljeni za velike korpuse podatkov in so pozvani kot novi začetno seme za generacijo. Na primer:

generate_text('the truth ultimately is')

Ki pod pokrovom vnese ta poziv v model, podoben GPT, in ustvari:

'the truth ultimately is really a joy in history, this state of life through which is almost invisible, superfluous  teleological...'

To je pravzaprav majhen spojler s konca vodnika! Še en majhen spojler je arhitektura, ki je ustvarila to besedilo:

inputs = layers.Input(shape=(maxlen,))
embedding_layer = keras_nlp.layers.TokenAndPositionEmbedding(vocab_size, maxlen, embed_dim)(inputs)
transformer_block = keras_nlp.layers.TransformerDecoder(embed_dim, num_heads)(embedding_layer)
outputs = layers.Dense(vocab_size, activation='softmax')(transformer_block)
    
model = keras.Model(inputs=inputs, outputs=outputs)

5 vrstic je vse, kar je potrebno za izdelavo modela transformatorja samo za dekoder – simulacija majhnega GPT. Ker bomo model učili na romanih Fjodorja Dostojevskega (ki jih lahko nadomestite s čim drugim, od Wikipedije do komentarjev na Redditu) – bomo model pogojno poimenovali GPT-Fjodor.

KerasNLP

Trik za 5-vrstični GPT-Fyodor je v KerasNLP, ki ga je razvila uradna ekipa Keras, kot horizontalno razširitev Kerasa, ki v pravem Kerasovem slogu želi prinesti NLP, ki je močan v industriji, na dosegu roke z novimi plastmi (kodirniki, dekoderji, vdelave žetonov, vdelave pozicij, metrike, tokenizerji itd.).

KerasNLP ni vzorčni živalski vrt. Je del Kerasa (kot ločen paket), ki znižuje vstopno oviro za razvoj modela NLP, tako kot z glavnim paketom znižuje vstopno oviro za razvoj splošnega globokega učenja.

Opomba: V času pisanja se KerasNLP še vedno proizvaja in je v zgodnjih fazah. V prihodnjih različicah so lahko prisotne manjše razlike. Zapis uporablja različico 0.3.0.

Če želite uporabljati KerasNLP, ga boste morali namestiti prek pip:

$ pip install keras_nlp

Različico lahko preverite z:

keras_nlp.__version__

Implementacija modela v slogu GPT s Kerasom

Začnimo z uvozom knjižnic, ki jih bomo uporabljali – TensorFlow, Keras, KerasNLP in NumPy:

import tensorflow as tf
from tensorflow import keras
import keras_nlp
import numpy as np

Nalaganje podatkov

Naložimo nekaj romanov Dostojevskega – eden bi bil veliko prekratek, da bi se prilegal modelu, brez poštenega pretiranega opremljanja od zgodnjih faz naprej. Neobdelane besedilne datoteke iz Projekt Gutenberg, zaradi enostavnosti dela s takimi podatki:

crime_and_punishment_url = 'https://www.gutenberg.org/files/2554/2554-0.txt'
brothers_of_karamazov_url = 'https://www.gutenberg.org/files/28054/28054-0.txt'
the_idiot_url = 'https://www.gutenberg.org/files/2638/2638-0.txt'
the_possessed_url = 'https://www.gutenberg.org/files/8117/8117-0.txt'

paths = [crime_and_punishment_url, brothers_of_karamazov_url, the_idiot_url, the_possessed_url]
names = ['Crime and Punishment', 'Brothers of Karamazov', 'The Idiot', 'The Possessed']
texts = ''
for index, path in enumerate(paths):
    filepath = keras.utils.get_file(f'{names[index]}.txt', origin=path)
    text = ''
    with open(filepath, encoding='utf-8') as f:
        text = f.read()
        
        
        
        texts += text[10000:]

Preprosto smo prenesli vse datoteke, jih pregledali in združili eno na drugo. To vključuje nekaj raznolikosti v uporabljenem jeziku, hkrati pa ohranja izrazito Fjodor! Za vsako datoteko smo preskočili prvih 10 znakov, kar je približno povprečna dolžina predgovora in Gutenbergovega uvoda, tako da nam za vsako ponovitev ostane večinoma nedotaknjeno telo knjige. Oglejmo si nekaj naključnih 500 znakov v texts niz zdaj:


texts[25000:25500]
'nd that was whynI addressed you at once. For in unfolding to you the story of my life, Indo not wish to make myself a laughing-stock before these idle listeners,nwho indeed know all about it already, but I am looking for a mannof feeling and education. Know then that my wife was educated in anhigh-class school for the daughters of noblemen, and on leaving shendanced the shawl dance before the governor and other personages fornwhich she was presented with a gold medal and a certificate of merit.n'

Pred kakršno koli drugo obdelavo razdelimo niz na stavke:

text_list = texts.split('.')
len(text_list) 

Imamo 69k stavkov. Ko zamenjate n znake s presledki in preštejte besede:

len(texts.replace('n', ' ').split(' ')) 

Opomba: Na splošno boste želeli imeti vsaj milijon besed v naboru podatkov, v idealnem primeru pa veliko več kot to. Delamo z nekaj megabajti podatkov (~5 MB), medtem ko se jezikovni modeli pogosteje urijo na desetinah gigabajtov besedila. To bo seveda zelo olajšalo pretiravanje vnosa besedila in težko posploševanje (visoka zapletenost brez pretiravanja ali nizka zapletenost z veliko pretiravanja). Rezultate jemljite z rezervo.

Kljub temu jih razdelimo na a trening, Test in potrjevanje set. Najprej odstranimo prazne nize in premešajmo stavke:


text_list = list(filter(None, text_list))

import random
random.shuffle(text_list)

Nato bomo naredili razdelitev 70/15/15:

length = len(text_list)
text_train = text_list[:int(0.7*length)]
text_test = text_list[int(0.7*length):int(0.85*length)]
text_valid = text_list[int(0.85*length):]

To je preprost, a učinkovit način za izvedbo razdelitve vlak-test-validacija. Pa pokukajmo text_train:

[' It was a dull morning, but the snow had ceased',
 'nn"Pierre, you who know so much of what goes on here, can you really havenknown nothing of this business and have heard nothing about it?"nn"What? What a set! So it's not enough to be a child in your old age,nyou must be a spiteful child too! Varvara Petrovna, did you hear what hensaid?"nnThere was a general outcry; but then suddenly an incident took placenwhich no one could have anticipated', ...

Čas je za standardizacijo in vektorizacijo!

Vektorizacija besedila

Omrežja ne razumejo besed – razumejo številke. Želeli bomo tokenizirati besede:

...
sequence = ['I', 'am', 'Wall-E']
sequence = tokenize(sequence)
print(sequence) # [4, 26, 472]
...

Poleg tega se stavki razlikujejo po dolžini – oblazinjenje se običajno doda na levo ali desno, da se zagotovi enaka oblika vseh stavkov, ki jih dodajamo. Recimo, da je naš najdaljši stavek dolg 5 besed (žetonov). V tem primeru bi bil stavek Wall-E obložen z dvema ničlama, tako da zagotovimo enako obliko vnosa:

sequence = pad_sequence(sequence)
print(sequence) # [4, 26, 472, 0, 0]

Tradicionalno se je to izvajalo z uporabo TensorFlow Tokenizer in Keras' pad_sequences() metode – vendar veliko bolj priročen sloj, TextVectorization, se lahko uporablja, kar tokenizira in podloži vaš vnos, kar vam omogoča, da izvlečete besedišče in njegovo velikost, ne da bi vnaprej poznali besedišče!

Oglejte si naš praktični, praktični vodnik za učenje Gita z najboljšimi praksami, standardi, sprejetimi v panogi, in priloženo goljufijo. Nehajte Googlati ukaze Git in pravzaprav naučiti it!

Prilagodimo in opremimo a TextVectorization plast:

from tensorflow.keras.layers import TextVectorization

def custom_standardization(input_string):
    sentence = tf.strings.lower(input_string)
    sentence = tf.strings.regex_replace(sentence, "n", " ")
    return sentence

maxlen = 50



vectorize_layer = TextVectorization(
    standardize = custom_standardization,
    output_mode="int",
    output_sequence_length=maxlen + 1,
)

vectorize_layer.adapt(text_list)
vocab = vectorize_layer.get_vocabulary()

O custom_standardization() metoda lahko traja veliko dlje od tega. Vse vnose smo preprosto napisali z malimi črkami in jih zamenjali n z " ". Tukaj lahko resnično vložite večino predprocesiranja za besedilo – in ga posredujete sloju za vektorizacijo prek neobveznega standardize prepir. Enkrat ti adapt() plast do besedila (matrika NumPy ali seznam besedil) – od tam lahko dobite besedišče in njegovo velikost:

vocab_size = len(vocab)
vocab_size 

Nazadnje bomo za detokenizacijo besed ustvarili index_lookup slovar:

index_lookup = dict(zip(range(len(vocab)), vocab))    
index_lookup[5] 

Preslika vse žetone ([1, 2, 3, 4, ...]) besedam v besedišču (['a', 'the', 'i', ...]). S posredovanjem ključa (indeksa žetona) lahko preprosto dobimo besedo nazaj. Zdaj lahko zaženete vectorize_layer() pri katerem koli vnosu in opazujte vektorizirane stavke:

vectorize_layer(['hello world!'])

Posledica tega je:

<tf.Tensor: shape=(1, 51), dtype=int64, numpy=
array([[   1, 7509,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0]], dtype=int64)>

Hello ima indeks 1 medtem ko ima svet indeks 7509! Ostalo je oblazinjenje maxlen smo izračunali.

Imamo sredstva za vektorizacijo besedila – zdaj pa ustvarimo nize podatkov iz text_train, text_test in text_valid, z uporabo naše vektorizacijske plasti kot pretvorbenega medija med besedami in vektorji, ki jih je mogoče vnesti v GPT-Fyodor.

Ustvarjanje nabora podatkov

Ustvarili bomo a tf.data.Dataset za vsak naš sklop z uporabo from_tensor_slices() in zagotavljanje seznama, no, tenzorskih rezin (stavkov):

batch_size = 64

train_dataset = tf.data.Dataset.from_tensor_slices(text_train)
train_dataset = train_dataset.shuffle(buffer_size=256)
train_dataset = train_dataset.batch(batch_size)

test_dataset = tf.data.Dataset.from_tensor_slices(text_test)
test_dataset = test_dataset.shuffle(buffer_size=256)
test_dataset = test_dataset.batch(batch_size)

valid_dataset = tf.data.Dataset.from_tensor_slices(text_valid)
valid_dataset = valid_dataset.shuffle(buffer_size=256)
valid_dataset = valid_dataset.batch(batch_size)

Ko smo enkrat ustvarjeni in premešani (spet za dobro mero) – lahko uporabimo funkcijo predprocesiranja (vektorizacija in delitev zaporedja):

def preprocess_text(text):
    text = tf.expand_dims(text, -1)
    tokenized_sentences = vectorize_layer(text)
    x = tokenized_sentences[:, :-1]
    y = tokenized_sentences[:, 1:]
    return x, y


train_dataset = train_dataset.map(preprocess_text)
train_dataset = train_dataset.prefetch(tf.data.AUTOTUNE)

test_dataset = test_dataset.map(preprocess_text)
test_dataset = test_dataset.prefetch(tf.data.AUTOTUNE)

valid_dataset = valid_dataset.map(preprocess_text)
valid_dataset = valid_dataset.prefetch(tf.data.AUTOTUNE)

O preprocess_text() funkcija preprosto razširi za zadnjo dimenzijo, vektorizira besedilo z uporabo našega vectorize_layer in ustvari vnose in cilje, izravnane z enim žetonom. Model bo uporabljal [0..n] sklepati n+1, ki daje napoved za vsako besedo, pri čemer upošteva vse besede pred tem. Oglejmo si en sam vnos v katerem koli od naborov podatkov:

for entry in train_dataset.take(1):
    print(entry)

Če preiščemo vrnjene vnose in cilje v serijah po 64 (z dolžino vsakega 30), lahko jasno vidimo, kako so izravnani z enim:

(<tf.Tensor: shape=(64, 50), dtype=int64, numpy=
array([[17018,   851,     2, ...,     0,     0,     0],
       [  330,    74,     4, ...,     0,     0,     0],
       [   68,   752, 30273, ...,     0,     0,     0],
       ...,
       [    7,    73,  2004, ...,     0,     0,     0],
       [   44,    42,    67, ...,     0,     0,     0],
       [  195,   252,   102, ...,     0,     0,     0]], dtype=int64)>, <tf.Tensor: shape=(64, 50), dtype=int64, numpy=
array([[  851,     2,  8289, ...,     0,     0,     0],
       [   74,     4,    34, ...,     0,     0,     0],
       [  752, 30273,  7514, ...,     0,     0,     0],
       ...,
       [   73,  2004,    31, ...,     0,     0,     0],
       [   42,    67,    76, ...,     0,     0,     0],
       [  252,   102,  8596, ...,     0,     0,     0]], dtype=int64)>)

Končno – čas je za izdelavo modela!

Opredelitev modela

Tukaj bomo uporabili plasti KerasNLP. Po an Input, bomo vnos kodirali prek a TokenAndPositionEmbedding plast, ki poteka v našem vocab_size, maxlen in embed_dim. Enako embed_dim ki jih ta plast oddaja in vnaša v TransformerDecoder bo shranjene v dekoderju. V času pisanja dekoder samodejno vzdržuje vhodno dimenzijo in vam ne dovoljuje, da bi jo projicirali v drug izhod, vendar vam omogoča, da definirate latentne dimenzije prek intermediate_dim prepir.

Za latentno predstavitev bomo vdelane dimenzije pomnožili z dvema, vendar lahko ohranite enako ali uporabite številko, ki ni ločena od vdelanih zatemnitev:

embed_dim = 128
num_heads = 4

def create_model():
    inputs = keras.layers.Input(shape=(maxlen,), dtype=tf.int32)
    embedding_layer = keras_nlp.layers.TokenAndPositionEmbedding(vocab_size, maxlen, embed_dim)(inputs)
    decoder = keras_nlp.layers.TransformerDecoder(intermediate_dim=embed_dim, 
                                                            num_heads=num_heads, 
                                                            dropout=0.5)(embedding_layer)
    
    outputs = keras.layers.Dense(vocab_size, activation='softmax')(decoder)
    
    model = keras.Model(inputs=inputs, outputs=outputs)
    
    model.compile(
        optimizer="adam", 
        loss='sparse_categorical_crossentropy',
        metrics=[keras_nlp.metrics.Perplexity(), 'accuracy']
    )
    return model

model = create_model()
model.summary()

Na vrhu dekoderja imamo a Dense sloj za izbiro naslednje besede v zaporedju, z a softmax aktivacijo (ki ustvari porazdelitev verjetnosti za vsak naslednji žeton). Oglejmo si povzetek modela:

Model: "model_5"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_6 (InputLayer)        [(None, 30)]              0         
                                                                 
 token_and_position_embeddin  (None, 30, 128)          6365824   
 g_5 (TokenAndPositionEmbedd                                     
 ing)                                                            
                                                                 
 transformer_decoder_5 (Tran  (None, 30, 128)          132480    
 sformerDecoder)                                                 
                                                                 
 dense_5 (Dense)             (None, 30, 49703)         6411687   
                                                                 
=================================================================
Total params: 13,234,315
Trainable params: 13,234,315
Non-trainable params: 0
_________________________________________________________________

GPT-2 združuje veliko dekoderjev – GPT-2 Small ima 12 zloženih dekoderjev (117M parametrov), GPT-2 Extra Large pa 48 zloženih dekoderjev (1.5B parametrov). Naš model z enim dekoderjem s skromnimi 13M parametri bi moral delovati dovolj dobro za izobraževalne namene. Pri magistrskih študijih – povečevanje se je izkazalo za izjemno dobro strategijo, transformatorji pa omogočajo dobro skaliranje, zaradi česar je mogoče usposobiti izjemno velike modele.

GPT-3 ima a “pičma” 175B parametri. Ekipa Google Brain je usposobila model parametrov 1.6T za izvajanje raziskav redkosti, pri čemer je izračune ohranil na enaki ravni kot veliko manjši modeli.

Pravzaprav, če povečamo število dekoderjev z 1 na 3:

def create_model():
    inputs = keras.layers.Input(shape=(maxlen,), dtype=tf.int32)
    x = keras_nlp.layers.TokenAndPositionEmbedding(vocab_size, maxlen, embed_dim)(inputs)
    for i in range(4):
        x = keras_nlp.layers.TransformerDecoder(intermediate_dim=embed_dim*2, num_heads=num_heads,                                                             dropout=0.5)(x)
    do = keras.layers.Dropout(0.4)(x)
    outputs = keras.layers.Dense(vocab_size, activation='softmax')(do)
    
    model = keras.Model(inputs=inputs, outputs=outputs)

Število naših parametrov bi se povečalo za 400k:

Total params: 13,631,755
Trainable params: 13,631,755
Non-trainable params: 0

Večina parametrov v našem omrežju prihaja iz TokenAndPositionEmbedding in Dense plasti!

Preizkusite različne globine dekoderja – od 1 do vseh, ki jih zmore vaša naprava, in zabeležite rezultate. V vsakem primeru – skoraj smo pripravljeni na šolanje modela! Ustvarimo povratni klic po meri, ki bo proizvedel vzorec besedila za vsako obdobje, da bomo lahko videli, kako se model skozi usposabljanje nauči oblikovati stavke.

Povratni klic po meri

class TextSampler(keras.callbacks.Callback):
    def __init__(self, start_prompt, max_tokens):
        self.start_prompt = start_prompt
        self.max_tokens = max_tokens
        
    
    
    def sample_token(self, logits):
        logits, indices = tf.math.top_k(logits, k=5, sorted=True)
        indices = np.asarray(indices).astype("int32")
        preds = keras.activations.softmax(tf.expand_dims(logits, 0))[0]
        preds = np.asarray(preds).astype("float32")
        return np.random.choice(indices, p=preds)

    def on_epoch_end(self, epoch, logs=None):
        decoded_sample = self.start_prompt
        
        for i in range(self.max_tokens-1):
            tokenized_prompt = vectorize_layer([decoded_sample])[:, :-1]
            predictions = self.model.predict([tokenized_prompt], verbose=0)
            
            
            
            
            sample_index = len(decoded_sample.strip().split())-1
            
            sampled_token = self.sample_token(predictions[0][sample_index])
            sampled_token = index_lookup[sampled_token]
            decoded_sample += " " + sampled_token
            
        print(f"nSample text:n{decoded_sample}...n")


random_sentence = ' '.join(random.choice(text_valid).replace('n', ' ').split(' ')[:4])
sampler = TextSampler(random_sentence, 30)
reducelr = keras.callbacks.ReduceLROnPlateau(patience=10, monitor='val_loss')

Izobraževanje modela

Končno je čas za trening! Vstavimo se train_dataset in validation_dataset z vzpostavljenimi povratnimi klici:

model = create_model()
history = model.fit(train_dataset, 
                    validation_data=valid_dataset,
                    epochs=10, 
                    callbacks=[sampler, reducelr])

Vzorčevalnik je izbral neposrečen stavek, ki se začne s končnim narekovajem in začetnim narekovajem, vendar kljub temu med treningom daje zanimive rezultate:

# Epoch training
Epoch 1/10
658/658 [==============================] - ETA: 0s - loss: 2.7480 - perplexity: 15.6119 - accuracy: 0.6711
# on_epoch_end() sample generation
Sample text:
”  “What do you had not been i had been the same man was not be the same eyes to been a whole man and he did a whole man to the own...
# Validation
658/658 [==============================] - 158s 236ms/step - loss: 2.7480 - perplexity: 15.6119 - accuracy: 0.6711 - val_loss: 2.2130 - val_perplexity: 9.1434 - val_accuracy: 0.6864 - lr: 0.0010
...
Sample text:
”  “What do you know it is it all this very much as i should not have a great impression  in the room to be  able of it in my heart...

658/658 [==============================] - 149s 227ms/step - loss: 1.7753 - perplexity: 5.9019 - accuracy: 0.7183 - val_loss: 2.0039 - val_perplexity: 7.4178 - val_accuracy: 0.7057 - lr: 0.0010

Začne se z:

"Kaj nisi bil, jaz sem bil isti" ...

Kar pravzaprav nima pravega smisla. Do konca desetih kratkih obdobij proizvede nekaj v skladu z:

"Kako to misliš, da je najbolj običajen človek od človeka seveda" ...

Čeprav drugi stavek še vedno nima preveč smisla – je veliko bolj smiseln kot prvi. Daljše usposabljanje na več podatkih (z bolj zapletenimi koraki predprocesiranja) bi prineslo boljše rezultate. Usposabljali smo ga samo na 10 obdobjih z velikim osipom, da bi se spopadli z majhno velikostjo nabora podatkov. Če bi ga pustili trenirati dlje časa, bi ustvaril zelo Fjodorjevo besedilo, ker bi si zapomnil velike dele tega.

Opomba: Ker je rezultat dokaj podroben, lahko prilagodite verbose argument med prilagajanjem modela za zmanjšanje količine besedila na zaslonu.

Sklepanje modela

Za izvedbo sklepanja bomo želeli posnemati vmesnik TextSampler – metoda, ki sprejme seme in a response_length (max_tokens). Uporabili bomo iste metode kot v vzorčevalniku:

def sample_token(logits):
        logits, indices = tf.math.top_k(logits, k=5, sorted=True)
        indices = np.asarray(indices).astype("int32")
        preds = keras.activations.softmax(tf.expand_dims(logits, 0))[0]
        preds = np.asarray(preds).astype("float32")
        return np.random.choice(indices, p=preds)

def generate_text(prompt, response_length=20):
    decoded_sample = prompt
    for i in range(response_length-1):
        tokenized_prompt = vectorize_layer([decoded_sample])[:, :-1]
        predictions = model.predict([tokenized_prompt], verbose=0)
        sample_index = len(decoded_sample.strip().split())-1

        sampled_token = sample_token(predictions[0][sample_index])
        sampled_token = index_lookup[sampled_token]
        decoded_sample += " " + sampled_token
    return decoded_sample

Zdaj lahko izvajate metodo na novih vzorcih:

generate_text('the truth ultimately is')


generate_text('the truth ultimately is')

Izboljšanje rezultatov?

Kako lahko torej izboljšate rezultate? Obstaja nekaj zelo uporabnih stvari, ki jih lahko storite:

  • Čiščenje podatkov (bolj natančno očistite vhodne podatke, od začetka smo le obrezali približno število in odstranili znake za novo vrstico)
  • Pridobite več podatkov (delali smo samo z nekaj megabajti besedilnih podatkov)
  • Povečajte model skupaj s podatki (zlaganje dekoderjev ni težko!)

zaključek

Medtem ko je cevovod za predprocesiranje minimalističen in ga je mogoče izboljšati – je cevovod, opisan v tem priročniku, proizvedel spodoben model v slogu GPT, s samo 5 vrsticami kode, potrebnimi za izdelavo transformatorja samo za dekoder po meri z uporabo Kerasa!

Transformatorji so priljubljeni in široko uporabni za generično modeliranje sekvenc (in marsikaj je mogoče izraziti kot sekvence). Doslej je bila glavna ovira za vstop okorna izvedba, toda s KerasNLP – strokovnjaki za globoko učenje lahko izkoristijo izvedbe za hitro in enostavno izdelavo modelov.

Časovni žig:

Več od Stackabuse