Generare de text în stil GPT pe 5 linii în Python cu TensorFlow/Keras

Transformers, deși au fost lansate în 2017, au început să câștige o tracțiune semnificativă abia în ultimii doi ani. Odată cu proliferarea tehnologiei prin platforme precum HuggingFace, NLP și Modele de limbaj mari (LLM) au devenit mai accesibile ca niciodată.

Cu toate acestea, chiar și cu tot hype-ul din jurul lor și cu multe ghiduri orientate către teorie, nu există multe implementări personalizate online, iar resursele nu sunt la fel de ușor disponibile ca în cazul altor tipuri de rețele, care există de mai mult timp. În timp ce vă puteți simplifica ciclul de lucru utilizând un transformator pre-construit de la HuggingFace (subiectul unui alt ghid), puteți ajunge la simţi cum funcționează construind unul singur, înainte de a-l abstrage printr-o bibliotecă. Aici ne vom concentra pe construirea, mai degrabă decât pe teorie și optimizare.

În acest ghid, vom construi un Model de limbaj autoregresiv la genera text. Ne vom concentra pe aspectele practice și minimaliste/concise ale încărcării datelor, împărțirii lor, vectorizării lor, construirii unui model, scrierii unui callback personalizat și antrenamentului/inferenței. Fiecare dintre aceste sarcini poate fi împărțită în ghiduri mai detaliate, așa că vom păstra implementarea ca una generică, lăsând loc pentru personalizare și optimizare în funcție de propriul set de date.

Tipuri de LLM și GPT-Fyodor

În timp ce clasificarea poate deveni mult mai complicată, tu poți in linii mari clasificați modelele de limbaj bazate pe Transformer în trei categorii:

  • Modele bazate pe codificatoare – ALBERT, BERT, DistilBERT, Roberta
  • Bazat pe decodor – GPT, GPT-2, GPT-3, TransformerXL
  • Modele Seq2Seq – BART, mBART, T5

Bazat pe codificator modelele folosesc doar un encoder Transformer în arhitectura lor (de obicei, stivuite) și sunt grozave pentru înțelegerea propozițiilor (clasificare, recunoaștere a entităților numite, răspunsuri la întrebări).

Bazat pe decodor modelele folosesc doar un decodor Transformer în arhitectura lor (de asemenea, de obicei stivuite) și sunt excelente pentru predicții viitoare, ceea ce le face potrivite pentru generarea de text.

Seq2Seq modelele combină atât codificatoare, cât și decodoare și sunt excelente la generarea de text, rezumatul și cel mai important – traducerea.

Familia de modele GPT, care a câștigat multă acțiune în ultimii doi ani, sunt modele de transformatoare bazate pe decodor și sunt excelente în producerea de text asemănător omului, instruite pe corpuri mari de date și primite un prompt ca un nou sămânță de pornire pentru generație. De exemplu:

generate_text('the truth ultimately is')

Care sub capotă alimentează acest prompt într-un model asemănător GPT și produce:

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

Acesta este, de fapt, un mic spoiler de la sfârșitul ghidului! Un alt mic spoiler este arhitectura care a produs acel text:

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 linii este tot ce este nevoie pentru a construi un model de transformator numai pentru decodor - simulând un GPT mic. Deoarece vom instrui modelul pe romanele lui Fiodor Dostoievski (pe care le puteți înlocui cu orice altceva, de la Wikipedia la comentariile Reddit) - vom numi provizoriu modelul GPT-Fyodor.

KerasNLP

Trucul pentru un GPT-Fyodor cu 5 linii constă în KerasNLP, care este dezvoltat de echipa oficială Keras, ca o extensie orizontală a Keras, care, în adevărata modă Keras, își propune să aducă la îndemână NLP-ul puternic din industrie, cu noi straturi (encodere, decodore, încorporare de token, încorporare de poziții, metrici, jetoane etc.).

KerasNLP nu este o grădină zoologică model. Este o parte a Keras (ca pachet separat), care reduce bariera de intrare pentru dezvoltarea modelului NLP, la fel cum scade bariera de intrare pentru dezvoltarea generală a învățării profunde cu pachetul principal.

Notă: În momentul scrierii, KerasNLP este încă produs și în stadii incipiente. Diferențele subtile ar putea fi prezente în versiunile viitoare. Scrisul folosește versiunea 0.3.0.

Pentru a putea folosi KerasNLP, va trebui să îl instalați prin pip:

$ pip install keras_nlp

Și puteți verifica versiunea cu:

keras_nlp.__version__

Implementarea unui model în stil GPT cu Keras

Să începem prin a importa bibliotecile pe care le vom folosi - TensorFlow, Keras, KerasNLP și NumPy:

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

Încărcare date

Să încarcăm câteva dintre romanele lui Dostoievski – unul ar fi mult prea scurt pentru ca un model să se potrivească, fără un pic de supraadaptare încă din primele etape. Vom folosi cu grație fișierele text brut de la Proiectul Gutenberg, datorită simplității lucrului cu astfel de date:

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:]

Pur și simplu am descărcat toate fișierele, le-am parcurs și le-am concatenat unul peste altul. Aceasta include o oarecare diversitate în limbajul folosit, păstrându-l în același timp distinct Fiodor! Pentru fiecare fișier, am omis primele 10 de caractere, care este în jur de lungimea medie a prefeței și a introducerii lui Gutenberg, așa că am rămas cu un corp în mare parte intact al cărții pentru fiecare iterație. Să aruncăm o privire la unele 500 de caractere aleatorii din texts string acum:


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'

Să separăm șirul în propoziții înainte de a face orice altă procesare:

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

Avem 69 de propoziții. Când înlocuiți n caractere cu spații albe și numărați cuvintele:

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

Notă: În general, veți dori să aveți cel puțin un milion de cuvinte într-un set de date și, în mod ideal, mult mai mult decât atât. Lucrăm cu câțiva megaocteți de date (~5MB), în timp ce modelele de limbă sunt mai frecvent antrenate pe zeci de gigaocteți de text. Acest lucru, desigur, va face cu adevărat ușoară supraadaptarea textului introdus și greu de generalizat (perplexitate mare fără supraadaptare sau perplexitate scăzută cu multă supraadaptare). Luați rezultatele cu un sâmbure de sare.

Cu toate acestea, să le împărțim în a pregătire, test și validare a stabilit. Mai întâi, să eliminăm șirurile goale și să amestecăm propozițiile:


text_list = list(filter(None, text_list))

import random
random.shuffle(text_list)

Apoi, vom face o împărțire 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):]

Acesta este o modalitate simplă, dar eficientă de a efectua o împărțire de validare a testului trenului. Să aruncăm o privire la 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', ...

E timpul pentru standardizare și vectorizare!

Vectorizarea textului

Rețelele nu înțeleg cuvintele – ele înțeleg numerele. Vom dori să simbolizăm cuvintele:

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

De asemenea, deoarece propozițiile diferă în lungime – umplutura este de obicei adăugată la stânga sau la dreapta pentru a asigura aceeași formă în propozițiile introduse. Să spunem că cea mai lungă propoziție a noastră are 5 cuvinte (tokens). În acest caz, propoziția Wall-E ar fi completată cu două zerouri, așa că ne asigurăm aceeași formă de intrare:

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

În mod tradițional, acest lucru a fost făcut folosind un TensorFlow Tokenizer și a lui Keras pad_sequences() metode – cu toate acestea, un strat mult mai util, TextVectorization, poate fi folosit, care tokenizează și vă completează introducerea, permițându-vă să extrageți vocabularul și dimensiunea acestuia, fără să cunoașteți vocabularul dinainte!

Consultați ghidul nostru practic și practic pentru a învăța Git, cu cele mai bune practici, standarde acceptate de industrie și fisa de cheat incluse. Opriți căutarea pe Google a comenzilor Git și de fapt învăţa aceasta!

Să ne adaptăm și să ne potrivim a TextVectorization strat:

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()

custom_standardization() metoda poate fi mult mai lungă decât aceasta. Pur și simplu am micșorat toate datele introduse și am înlocuit n cu " ". Aici puteți pune cu adevărat cea mai mare parte din preprocesarea textului - și o puteți furniza stratului de vectorizare prin intermediul opționalului standardize argument. Odata ce tu adapt() stratul la text (matrice NumPy sau listă de texte) – puteți obține vocabularul, precum și dimensiunea acestuia de acolo:

vocab_size = len(vocab)
vocab_size 

În cele din urmă, pentru a de-tokeniza cuvintele, vom crea un index_lookup dicţionar:

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

Mapează toate jetoanele ([1, 2, 3, 4, ...]) la cuvintele din vocabular (['a', 'the', 'i', ...]). Transmițând o cheie (index token), putem obține cu ușurință cuvântul înapoi. Acum puteți rula vectorize_layer() pe orice intrare și observați propozițiile vectorizate:

vectorize_layer(['hello world!'])

Ceea ce are ca rezultat:

<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 are indexul de 1 în timp ce lumea are indicele de 7509! Restul este umplutura la maxlen am calculat.

Avem mijloacele de a vectoriza text – acum, să creăm seturi de date din text_train, text_test și text_valid, folosind stratul nostru de vectorizare ca mediu de conversie între cuvinte și vectori care pot fi introduși în GPT-Fyodor.

Crearea setului de date

Vom crea un tf.data.Dataset pentru fiecare dintre seturile noastre, folosind from_tensor_slices() și oferind o listă de, ei bine, felii tensoare (propoziții):

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)

Odată creat și amestecat (din nou, pentru o bună măsură) - putem aplica o funcție de preprocesare (vectorizare și divizare secvență):

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)

preprocess_text() Funcția pur și simplu se extinde cu ultima dimensiune, vectorizează textul folosind our vectorize_layer și creează intrările și țintele, compensate cu un singur simbol. Modelul va folosi [0..n] a deduce n+1, dând o predicție pentru fiecare cuvânt, luând în considerare toate cuvintele înainte de acesta. Să aruncăm o privire la o singură intrare din oricare dintre seturile de date:

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

Investigand intrările și țintele returnate, în loturi de 64 (cu o lungime de 30 fiecare), putem vedea clar cum sunt compensate de unul:

(<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)>)

În sfârșit – este timpul să construim modelul!

Definiția modelului

Vom folosi straturi KerasNLP aici. După o Input, vom codifica intrarea prin a TokenAndPositionEmbedding strat, trecând în nostru vocab_size, maxlen și embed_dim. La fel embed_dim că acest strat iese și introduce în TransformerDecoder va fi reţinute în Decodor. În momentul scrierii, decodorul menține automat dimensionalitatea de intrare și nu vă permite să o proiectați într-o ieșire diferită, dar vă permite să definiți dimensiunile latente prin intermediul intermediate_dim a susținut.

Vom înmulți dimensiunile de încorporare cu două pentru reprezentarea latentă, dar le puteți păstra la fel sau puteți utiliza un număr detașat din dimurile de încorporare:

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()

Pe deasupra decodorului, avem un Dense strat pentru a alege următorul cuvânt din secvență, cu a softmax activare (care produce distribuția probabilității pentru fiecare jeton următor). Să aruncăm o privire la rezumatul modelului:

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 stivuiește multe decodoare – GPT-2 Small are 12 decodoare stivuite (117M parametri), în timp ce GPT-2 Extra Large are 48 decodoare stivuite (1.5B parametri). Modelul nostru cu un singur decodor cu parametri umili de 13M ar trebui să funcționeze suficient de bine pentru scopuri educaționale. Cu LLMs – extinderea s-a dovedit a fi o strategie extrem de bună, iar Transformers permite o bună scalare, făcând posibilă antrenarea modelelor extrem de mari.

GPT-3 are un „slab” parametrii 175B. Echipa Google Brain a antrenat un model cu parametri de 1.6 T pentru a efectua cercetări de dispersie, menținând în același timp calculul la același nivel cu modelele mult mai mici.

De fapt, dacă am mărit numărul decodoarelor de la 1 la 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)

Numărul parametrilor noștri ar fi crescut cu 400k:

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

Majoritatea parametrilor din rețeaua noastră provin din TokenAndPositionEmbedding și Dense straturi!

Încercați diferite adâncimi ale decodorului – de la 1 până la tot felul în care mașina dvs. poate gestiona și nota rezultatele. În orice caz – suntem aproape gata să antrenăm modelul! Să creăm un callback personalizat care va produce un eșantion de text în fiecare epocă, astfel încât să putem vedea cum modelul învață să formeze propoziții prin antrenament.

Reapel personalizat

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')

Instruirea modelului

În sfârșit, e timpul să te antrenezi! Hai să ne aruncăm train_dataset și validation_dataset cu apelurile inapoi la loc:

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

Eșantionul a ales o propoziție nefericită care începe cu citatul de final și citatul de început, dar totuși produce rezultate interesante în timpul antrenamentului:

# 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

Începe cu:

„Ce nu ai fost, am fost la fel”…

Ceea ce nu prea are sens. Până la sfârșitul celor zece epoci scurte, produce ceva de genul:

„Ce vrei să spui că este cel mai obișnuit om dintre un om, desigur”...

Deși a doua propoziție încă nu are prea mult sens – este mult mai sensibilă decât prima. Un antrenament mai lung pe mai multe date (cu pași de preprocesare mai complicati) ar produce rezultate mai bune. L-am antrenat doar pe 10 epoci cu abandon mare pentru a combate dimensiunea mică a setului de date. Dacă ar fi lăsat antrenamentul pentru mult mai mult timp, ar produce un text foarte asemănător lui Fiodor, pentru că ar fi memorat bucăți mari din el.

Notă: Deoarece rezultatul este destul de verbos, puteți modifica verbose argument în timp ce potriviți modelul pentru a reduce cantitatea de text de pe ecran.

Inferența modelului

Pentru a efectua inferențe, vom dori să replicăm interfața TextSampler – o metodă care acceptă o sămânță și a response_length (max_tokens). Vom folosi aceleași metode ca în eșantioner:

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

Acum, puteți rula metoda pe mostre noi:

generate_text('the truth ultimately is')


generate_text('the truth ultimately is')

Îmbunătățirea rezultatelor?

Deci, cum puteți îmbunătăți rezultatele? Există câteva lucruri destul de utile pe care le puteți face:

  • Curățarea datelor (curățați datele de intrare mai meticulos, doar am tăiat un număr aproximativ de la început și am eliminat caracterele newline)
  • Obțineți mai multe date (am lucrat doar cu câțiva megaocteți de date text)
  • Scalați modelul alături de date (stivuirea decodoarelor nu este dificilă!)

Concluzie

În timp ce conducta de preprocesare este minimalistă și poate fi îmbunătățită - conducta prezentată în acest ghid a produs un model decent în stil GPT, cu doar 5 linii de cod necesare pentru a construi un transformator personalizat numai pentru decodor, folosind Keras!

Transformatoarele sunt populare și aplicabile pe scară largă pentru modelarea secvențelor generice (și multe lucruri pot fi exprimate ca secvențe). Până acum, principala barieră în calea intrării a fost o implementare greoaie, dar cu KerasNLP – practicanții de deep learning pot folosi implementările pentru a construi modele rapid și ușor.

Timestamp-ul:

Mai mult de la Stackabuse