5-realine GPT-stiilis teksti genereerimine Pythonis koos TensorFlow/Kerasega

Kuigi transformerid ilmusid 2017. aastal, on need alles viimase paari aasta jooksul hakanud märkimisväärset haaret saavutama. Tehnoloogia levikuga selliste platvormide kaudu nagu HuggingFace, NLP ja Suured keelemudelid (LLM) on muutunud kättesaadavamaks kui kunagi varem.

Ometi – isegi kogu nende ümber ja nendega seotud hüppega palju teooriale orienteeritud juhendid, pole võrgus palju kohandatud rakendusi ja ressursid pole nii kergesti kättesaadavad kui mõne muu võrgutüübi puhul, mis on olnud kasutusel juba pikemat aega. Kuigi saate oma töötsüklit lihtsustada, kasutades HuggingFace'i eelehitatud transformaatorit (teise juhendi teema), saate tundma kuidas see toimib, ehitades selle ise, enne kui teete selle raamatukogu kaudu välja. Siin keskendume pigem ehitamisele kui teooriale ja optimeerimisele.

Selles juhendis ehitame Autoregressiivne keelemudel et teksti genereerida. Keskendume andmete laadimise, tükeldamise, vektoriseerimise, mudeli loomise, kohandatud tagasihelistamise kirjutamise ja koolituse/järelduste praktilistele ja minimalistlikele/kokkuvõtlikele aspektidele. Kõiki neid ülesandeid saab jagada üksikasjalikumateks juhenditeks, nii et jätame juurutamise üldiseks, jättes ruumi kohandamiseks ja optimeerimiseks sõltuvalt teie enda andmestikku.

LLM-ide ja GPT-Fjodori tüübid

Kuigi kategoriseerimine võib olla palju keerulisem, saate seda teha üldjoontes liigitage transformeripõhised keelemudelid kolme kategooriasse:

  • Kodeerijapõhised mudelid – ALBERT, BERT, DistilBERT, RoBERTa
  • Dekoodripõhine – GPT, GPT-2, GPT-3, TransformerXL
  • Seq2Seq mudelid – BART, mBART, T5

Kodeerijapõhine mudelid kasutavad oma arhitektuuris ainult Transformeri kodeerijat (tavaliselt virnastatud) ja sobivad suurepäraselt lausete mõistmiseks (klassifikatsioon, nimega olemi tuvastamine, küsimustele vastamine).

Dekoodripõhine mudelid kasutavad oma arhitektuuris ainult Transformeri dekoodrit (tavaliselt ka virnastatud) ja sobivad suurepäraselt tuleviku ennustamiseks, mistõttu sobivad need teksti genereerimiseks.

Seq2Seq mudelid ühendavad endas nii kodeerijaid kui ka dekoodereid ning on suurepärased teksti genereerimisel, kokkuvõtete tegemisel ja mis kõige tähtsam – tõlkimisel.

GPT mudelite perekond, mis on viimase paari aastaga palju tuntust kogunud, on dekoodril põhinevad trafomudelid ja on suurepärased inimsarnase teksti loomisel, mis on treenitud suurel andmekorpusel ja millele antakse uue viipa. põlvkondade seemne alustamine. Näiteks:

generate_text('the truth ultimately is')

Mis kapoti all annab selle viipa GPT-laadsesse mudelisse ja toodab:

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

See on tegelikult väike spoiler juhendi lõpust! Teine väike spoiler on arhitektuur, mis selle teksti koostas:

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)

Ainult 5 rida on vaid dekoodriga trafomudeli ehitamiseks vaja – simuleerides väikest GPT-d. Kuna me koolitame modelli Fjodor Dostojevski romaanide alal (mida saate asendada kõige muuga, alates Wikipediast kuni Redditi kommentaarideni), kutsume modelli esialgu GPT-Fjodor.

KerasNLP

5-realise GPT-Fjodori trikk peitub selles KerasNLP, mille on välja töötanud Kerase ametlik tiim, Kerase horisontaalse laiendusena, mille eesmärk on Kerase moe järgi tuua teie käeulatusse tööstusharu tugev NLP uute kihtidega (kodeerijad, dekooderid, märgi manused, positsioonimanused, mõõdikud, tokenisaatorid jne).

KerasNLP ei ole näidisloomaaed. See on Kerase osa (eraldi paketina), mis alandab sisenemisbarjääri NLP-mudelite arendamiseks, nagu ka põhipaketiga üldise süvaõppe arendamise sisenemise barjääri.

Märge: Kirjutamise seisuga KerasNLP-d alles toodetakse ja alles algusjärgus. Tulevastes versioonides võivad esineda väikesed erinevused. Kirjutamine kasutab versiooni 0.3.0.

KerasNLP kasutamiseks peate selle installima pip:

$ pip install keras_nlp

Ja versiooni saate kontrollida, kasutades:

keras_nlp.__version__

GPT-stiilis mudeli rakendamine Kerasega

Alustame kasutatavate teekide importimisega – TensorFlow, Keras, KerasNLP ja NumPy:

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

Andmete laadimine

Laadime sisse mõned Dostojevski romaanid – üks oleks liiga lühike, et modell ära mahuks, ilma et oleks varajases staadiumis parajalt liialdatud. Kasutame graatsiliselt toortekstifaile Project Gutenberg, tänu selliste andmetega töötamise lihtsusele:

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

Oleme lihtsalt kõik failid alla laadinud, need läbi käinud ja üksteise peale liitnud. See hõlmab mõningast mitmekesisust kasutatavas keeles, säilitades samas selgelt Fjodori! Iga faili puhul jätsime vahele esimesed 10 500 tähemärki, mis on ligikaudu eessõna ja Gutenbergi sissejuhatuse keskmine pikkus, nii et meil on iga iteratsiooni jaoks jäänud suures osas puutumata raamatu põhiosa. Vaatame mõnda juhuslikku XNUMX tähemärki texts string nüüd:


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'

Enne mis tahes muud töötlemist eraldame stringi lauseteks:

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

Meil on 69 tuhat lauset. Kui asendate n tähemärki tühikutega ja loe sõnad kokku:

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

Märge: Tavaliselt soovite, et andmekogus oleks vähemalt miljon sõna ja ideaaljuhul palju rohkem. Töötame mõne megabaidise andmemahuga (~ 5 MB), samas kui keelemudeleid treenitakse sagedamini kümnete gigabaidide tekstiga. See muudab tekstisisestuse ülepaigutamise loomulikult lihtsaks ja üldistamise raskeks (suur segadus ilma ülepaigutamiseta või väike segadus suure ülepaigutusega). Võtke tulemusi soolateraga.

Sellegipoolest jagame need a-ks koolitus, test ja kinnitamine seatud. Kõigepealt eemaldame tühjad stringid ja segame lauseid:


text_list = list(filter(None, text_list))

import random
random.shuffle(text_list)

Seejärel jagame 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):]

See on lihtne, kuid tõhus viis rongikatsete kinnitamise jaotamiseks. Heidame pilgu peale 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', ...

Aeg standardiseerimiseks ja vektoriseerimiseks!

Teksti vektoriseerimine

Võrgustikud ei mõista sõnu – nad mõistavad numbreid. Tahame sõnad sümboolseks muuta:

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

Kuna laused on erineva pikkusega, lisatakse täidis tavaliselt vasakule või paremale, et tagada sisestatavate lausete sama kuju. Oletame, et meie pikim lause on 5 sõna (märke) pikk. Sel juhul oleks Wall-E lause polsterdatud kahe nulliga, nii et tagame sama sisendkuju:

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

Traditsiooniliselt tehti seda TensorFlow abil Tokenizer ja Keras' pad_sequences() meetodid – aga palju käepärasem kiht, TextVectorization, saab kasutada, mis märgistab ja polsterdab teie sisendit, võimaldades teil sõnavara ja selle suurust välja võtta, ilma sõnasõna ette teadmata!

Tutvuge meie praktilise ja praktilise Giti õppimise juhendiga, mis sisaldab parimaid tavasid, tööstusharus aktsepteeritud standardeid ja kaasas olevat petulehte. Lõpetage Giti käskude guugeldamine ja tegelikult õppima seda!

Kohandame ja sobitame a TextVectorization kiht:

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() meetod võib sellest palju pikemaks minna. Oleme lihtsalt kogu sisendi väiketähtedega muutnud ja asendanud n koos " ". See on koht, kus saate teha suurema osa oma teksti eeltöötlusest – ja edastada see vektoriseerimiskihile läbi valikulise standardize argument. Ükskord sa adapt() kiht tekstile (NumPy massiiv või tekstide loend) – sealt saad sõnavara ja ka suuruse:

vocab_size = len(vocab)
vocab_size 

Lõpuks, sõnade detokeniseerimiseks loome index_lookup sõnastik:

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

See kaardistab kõik märgid ([1, 2, 3, 4, ...]) sõnadele sõnavaras (['a', 'the', 'i', ...]). Võtme (märgiindeksi) edastamisega saame sõna hõlpsalt tagasi. Nüüd saate käivitada vectorize_layer() mis tahes sisendil ja jälgige vektoriseeritud lauseid:

vectorize_layer(['hello world!'])

Mille tulemuseks on:

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

Tere on indeks 1 samas kui maailmas on indeks 7509! Ülejäänud on polsterdus maxlen oleme välja arvutanud.

Meil on vahendid teksti vektoriseerimiseks – nüüd loome nendest andmekogumid text_train, text_test ja text_valid, kasutades meie vektoriseerimiskihti teisendusmeediumina sõnade ja vektorite vahel, mida saab sisestada GPT-Fyodorisse.

Andmestiku loomine

Loome a tf.data.Dataset iga meie komplekti jaoks, kasutades from_tensor_slices() ja tensorlõikude (lausete) loendi esitamine:

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)

Kui see on loodud ja segatud (jällegi hea mõõtmise huvides), saame rakendada eeltöötlusfunktsiooni (vektoriseerimine ja järjestuse tükeldamine):

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() funktsioon lihtsalt laieneb viimase mõõtme võrra, vektoriseerib teksti kasutades meie vectorize_layer ning loob sisendid ja sihtmärgid, mis kompenseeritakse ühe märgiga. Mudel kasutab [0..n] järeldada n+1, mis annab ennustuse iga sõna kohta, võttes arvesse kõiki sõnu enne seda. Vaatame ühte kirjet mis tahes andmekogumis:

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

Uurides tagastatud sisendeid ja sihtmärke 64 partiidena (igaüks pikkusega 30), näeme selgelt, kuidas need kompenseeritakse ühega:

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

Lõpuks ometi – on aeg mudel ehitada!

Mudeli definitsioon

Kasutame siin KerasNLP kihte. Pärast an Input, kodeerime sisendi läbi a TokenAndPositionEmbedding kiht, läbides meie vocab_size, maxlen ja embed_dim. Sama embed_dim et see kiht väljastab ja sisestab TransformerDecoder on säilitatakse dekoodris. Kirjutamise seisuga säilitab dekooder automaatselt sisendi dimensiooni ega võimalda teil seda teise väljundisse projitseerida, kuid see võimaldab teil määratleda varjatud mõõtmed intermediate_dim argument.

Varjatud esituse jaoks korrutame manustamise mõõtmed kahega, kuid võite selle jätta samaks või kasutada manustamishämarusest eraldatud arvu:

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

Dekoodri peal on meil a Dense kiht, et valida jada järgmine sõna koos a-ga softmax aktiveerimine (mis loob iga järgmise märgi tõenäosusjaotuse). Vaatame mudeli kokkuvõtet:

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 virnastab palju dekoodreid – GPT-2 Smallil on 12 virnastatud dekoodrit (117 miljonit parameetrit), samas kui GPT-2 Extra Large'il on 48 virnastatud dekoodrit (1.5 B parameetrit). Meie tagasihoidlike 13M parameetritega ühe dekoodriga mudel peaks hariduslikel eesmärkidel piisavalt hästi töötama. LLM-ide puhul on suurendamine osutunud ülimalt heaks strateegiaks ja transformerid võimaldavad head skaleerimist, muutes äärmiselt suurte mudelite koolitamise võimalikuks.

GPT-3-l on a "nõrk" 175B parameetrid. Google Braini meeskond koolitas 1.6T parameetrimudelit hõreduse uurimiseks, hoides arvutusi palju väiksemate mudelitega samal tasemel.

Tegelikult, kui me suurendaksime dekoodrite arvu 1-lt 3-le:

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)

Meie parameetrite arv suureneks 400 XNUMX võrra:

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

Enamik meie võrgu parameetritest pärineb TokenAndPositionEmbedding ja Dense kihid!

Proovige dekoodri erinevaid sügavusi – 1-st kuni selleni, kuidas teie masin hakkama saab ja tulemusi märkige. Igal juhul – oleme peaaegu valmis modelli koolitama! Loome kohandatud tagasihelistamise, mis loob iga epohhi kohta tekstinäidise, et saaksime näha, kuidas mudel õpib koolituse kaudu lauseid moodustama.

Kohandatud tagasihelistamine

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

Modelli koolitamine

Lõpuks ometi on aeg treenida! Paneme end sisse train_dataset ja validation_dataset kui tagasihelistamised on paigas:

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

Proovivõtja valis kahetsusväärse lause, mis algab lõpu- ja algustsitaadiga, kuid annab siiski treenides huvitavaid tulemusi:

# 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

See algab järgmisega:

"Mida sa poleks olnud, ma oleksin olnud samasugune"…

Millel pole tegelikult erilist mõtet. Kümne lühikese ajajärgu lõpuks toodab see midagi järgmiselt:

"Mis sa sellega mõtled, et see on muidugi kõige tavalisem mees?"...

Kuigi teisel lausel pole veel liiga palju mõtet, on see palju mõttekam kui esimene. Pikem koolitus suurema hulga andmete saamiseks (keerukamate eeltöötlusetappidega) annaks paremaid tulemusi. Oleme seda koolitanud vaid 10 suure väljalangevuse ajastul, et võidelda väikese andmekogumahuga. Kui see jäetaks treenima palju pikemaks ajaks, annaks see väga Fjodorilaadse teksti, sest oleks sellest suured jupid pähe jätnud.

Märge: Kuna väljund on üsna paljusõnaline, saate seda muuta verbose mudeli kohandamisel, et vähendada ekraanil kuvatava teksti hulka.

Mudeli järeldus

Järelduste tegemiseks tahame kopeerida liidest TextSampler – meetod, mis võtab vastu seemne ja a response_length (max_tokens). Kasutame samu meetodeid, mis proovivõtturis:

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

Nüüd saate seda meetodit uutel proovidel käivitada:

generate_text('the truth ultimately is')


generate_text('the truth ultimately is')

Tulemuste parandamine?

Niisiis, kuidas saate tulemusi parandada? Siin on mõned üsna praktilised asjad, mida saate teha:

  • Andmete puhastamine (puhastage sisendandmeid hoolikamalt, kärpisime algusest peale ligikaudse arvu ja eemaldasime reavahetuse märgid)
  • Hankige rohkem andmeid (töötasime vaid mõne megabaidi tekstiandmetega)
  • Skaleerige mudelit andmete kõrval (dekooderite virnastamine pole keeruline!)

Järeldus

Kuigi eeltöötluskonveier on minimalistlik ja seda saab täiustada, andis selles juhendis kirjeldatud konveier korraliku GPT-stiilis mudeli, mille jaoks on Kerast kasutades vaja ainult 5 koodirida kohandatud dekoodriga trafo ehitamiseks!

Trafod on populaarsed ja laialdaselt kasutatavad üldiseks jada modelleerimiseks (ja paljusid asju saab väljendada jadadena). Seni oli peamiseks sisenemisbarjääriks tülikas juurutamine, kuid KerasNLP-ga – süvaõppe praktikud saavad rakendusi kasutada, et mudeleid kiiresti ja lihtsalt luua.

Ajatempel:

Veel alates Stackabus