5-rivinen GPT-tyylinen tekstin luominen Pythonissa TensorFlow/Kerasilla

Vaikka Transformers julkaistiin vuonna 2017, ne ovat alkaneet saada merkittävää vetovoimaa vasta parin viime vuoden aikana. Teknologian leviämisen myötä alustat, kuten HuggingFace, NLP ja Suuret kielimallit (LLM) ovat tulleet helpommin saavutettaviksi kuin koskaan.

Silti – vaikka kaikki hype heidän ympärillään ja heidän kanssaan monet teoriasuuntautuneita oppaita, verkossa ei ole paljon mukautettuja toteutuksia, eivätkä resurssit ole yhtä helposti saatavilla kuin joidenkin muiden verkkotyyppien kanssa, jotka ovat olleet olemassa pidempään. Vaikka voit yksinkertaistaa työkiertoasi käyttämällä HuggingFacen valmiiksi rakennettua Transformeria (aihe toisessa oppaassa) – voit päästä tuntea miten se toimii rakentamalla sellainen itse, ennen kuin otat sen pois kirjaston kautta. Keskitymme tässä rakentamiseen teorian ja optimoinnin sijaan.

Tässä oppaassa rakennamme Autoregressiivinen kielimalli että luoda tekstiä. Keskitymme tietojen lataamisen, jakamisen, vektorisoinnin, mallin rakentamisen, mukautetun takaisinkutsun kirjoittamisen ja koulutuksen/päätelmien käytännöllisiin ja minimalistisiin/tiiviisiin näkökohtiin. Jokainen näistä tehtävistä voidaan jakaa yksityiskohtaisempiin oppaisiin, joten pidämme toteutuksen yleisenä, jättäen tilaa mukauttamiselle ja optimoinnille omasta tietojoukostasi riippuen.

LLM-tyypit ja GPT-Fjodor

Vaikka luokittelu voi olla paljon monimutkaisempaa, voit laajasti Luokittele Transformer-pohjaiset kielimallit kolmeen luokkaan:

  • Enkooderiin perustuvat mallit – ALBERT, BERT, DistilBERT, RoBERTa
  • Dekooderipohjainen – GPT, GPT-2, GPT-3, TransformerXL
  • Seq2Seq mallit – BART, mBART, T5

Enkooderipohjainen mallit käyttävät vain Transformer-enkooderia arkkitehtuurissaan (yleensä pinottu) ja ne sopivat erinomaisesti lauseiden ymmärtämiseen (luokittelu, nimetyn kokonaisuuden tunnistus, kysymykseen vastaaminen).

Dekooderipohjainen mallit käyttävät vain Transformer-dekooderia arkkitehtuurissaan (myös tyypillisesti pinottuina), ja ne sopivat hyvin tulevaisuuden ennustamiseen, mikä tekee niistä sopivia tekstin luomiseen.

Seq2Seq malleissa yhdistyvät sekä enkooderit että dekooderit ja ne ovat erinomaisia ​​tekstin luomisessa, yhteenvedossa ja mikä tärkeintä – kääntämisessä.

GPT-malliperhe, joka on saanut paljon pitoa parin viime vuoden aikana, on dekooderipohjaisia ​​muuntajamalleja, ja ne ovat erinomaisia ​​tuottamaan ihmisen kaltaista tekstiä, koulutettuja suuriin tietokokonaisuuksiin ja saanut kehotteen uutena. siemenen aloittaminen sukupolvelle. Esimerkiksi:

generate_text('the truth ultimately is')

Joka konepellin alla syöttää tämän kehotteen GPT:n kaltaiseen malliin ja tuottaa:

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

Tämä on itse asiassa pieni spoileri oppaan lopusta! Toinen pieni spoileri on arkkitehtuuri, joka tuotti tekstin:

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)

Vain 5 riviä tarvitaan vain dekooderin muuntajamallin rakentamiseen – se simuloi pientä GPT:tä. Koska aiomme kouluttaa mallia Fjodor Dostojevskin romaaneissa (jotka voit korvata millä tahansa muulla, Wikipediasta Reddit-kommentteihin), kutsumme mallia alustavasti GPT-Fjodor.

KerasNLP

5-rivisen GPT-Fjodorin temppu piilee siinä KerasNLP, jonka on kehittänyt virallinen Keras-tiimi, vaakasuuntaisena jatkeena Kerasille, joka aidolla Keras-tyylillä pyrkii tuomaan alan vahvan NLP:n sormiesi ulottuville uusilla kerroksilla (kooderit, dekooderit, merkkien upotukset, sijainti upotukset, mittarit, tokenisaattorit jne.).

KerasNLP ei ole mallieläintarha. Se on osa Kerasta (erillisenä pakettina), joka alentaa pääsyn estettä NLP-mallin kehittämiseen, aivan kuten se alentaa pääsyn estettä yleiseen syväoppimisen kehittämiseen pääpaketin kanssa.

Huomautus: KerasNLP:tä tuotetaan kirjoitettaessa edelleen ja alkuvaiheessa. Tulevissa versioissa saattaa esiintyä hienoisia eroja. Kirjoitus käyttää versiota 0.3.0.

Jotta voit käyttää KerasNLP:tä, sinun on asennettava se kautta pip:

$ pip install keras_nlp

Ja voit tarkistaa version seuraavasti:

keras_nlp.__version__

GPT-tyylisen mallin käyttöönotto Kerasilla

Aloitetaan tuomalla käyttämämme kirjastot – TensorFlow, Keras, KerasNLP ja NumPy:

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

Ladataan tietoja

Ladataanpa muutama Dostojevskin romaaneista – yksi olisi liian lyhyt malliin sopimaan ilman melkoista ylisovitusta alkuvaiheesta lähtien. Käytämme kauniisti raakatekstitiedostoja osoitteesta Project Gutenbergtällaisten tietojen kanssa työskentelyn yksinkertaisuuden vuoksi:

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

Olemme yksinkertaisesti ladaneet kaikki tiedostot, käyneet ne läpi ja ketjuttaneet ne päällekkäin. Tämä sisältää jonkin verran käytetyn kielen monimuotoisuutta, mutta pitää sen silti selvästi Fjodorina! Jokaisen tiedoston kohdalla olemme ohittaneet ensimmäiset 10 500 merkkiä, mikä on suunnilleen esipuheen ja Gutenbergin johdannon keskimääräinen pituus, joten kirjan runko on jätetty pääosin ehjänä jokaiselle iteraatiolle. Katsotaanpa joitain satunnaisia ​​XNUMX merkkiä texts merkkijono nyt:


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'

Erotetaan merkkijono lauseiksi ennen kuin teet mitään muuta käsittelyä:

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

Meillä on 69 XNUMX lausetta. Kun vaihdat n merkkejä välilyönneillä ja laske sanat:

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

Huomautus: Yleensä haluat, että tietojoukossa on vähintään miljoona sanaa, ja mieluiten paljon enemmän. Työskentelemme muutaman megatavun datan (~ 5 Mt) kanssa, kun taas kielimallit ovat yleisemmin koulutettuja kymmenien gigatavujen tekstille. Tämä tekee luonnollisesti todella helpoksi tekstinsyötön ylisovittamisen ja vaikeaksi yleistää (suuri hämmennys ilman ylisovitusta tai pieni hämmennys, kun on paljon ylisovitusta). Ota tulokset suolalla.

Jaetaan nämä kuitenkin a koulutus, testi ja validointi aseta. Poistetaan ensin tyhjät merkkijonot ja sekoitetaan lauseet:


text_list = list(filter(None, text_list))

import random
random.shuffle(text_list)

Sitten jaetaan 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):]

Tämä on yksinkertainen, mutta tehokas tapa suorittaa junatestin validoinnin jako. Katsotaanpa 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', ...

Standardoinnin ja vektorisoinnin aika!

Tekstin vektorointi

Verkot eivät ymmärrä sanoja – ne ymmärtävät numeroita. Haluamme tokenisoida sanat:

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

Lisäksi, koska lauseiden pituus on erilainen, täyte lisätään yleensä vasemmalle tai oikealle, jotta varmistetaan sama muoto syötettävien lauseiden välillä. Oletetaan, että pisin lauseemme on 5 sanaa (tunnisteita) pitkä. Siinä tapauksessa Wall-E-lause täytetään kahdella nollalla, joten varmistamme saman syötemuodon:

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

Perinteisesti tämä tehtiin TensorFlow'lla Tokenizer ja Keras' pad_sequences() menetelmät – kuitenkin paljon kätevämpi kerros, TextVectorization, voidaan käyttää, mikä tokenisoi ja tyynyt syötteesi, jolloin voit poimia sanaston ja sen koon tietämättä sanaa etukäteen!

Tutustu käytännönläheiseen, käytännölliseen Gitin oppimisoppaaseemme, jossa on parhaat käytännöt, alan hyväksymät standardit ja mukana tuleva huijauslehti. Lopeta Git-komentojen googlailu ja oikeastaan oppia se!

Sopeudutaan ja sovitetaan a TextVectorization kerros:

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() menetelmä voi olla paljon pidempi kuin tämä. Olemme yksinkertaisesti pienentäneet kaikki syötteet ja korvanneet ne n with " ". Tässä voit todella tehdä suurimman osan tekstin esikäsittelystäsi – ja toimittaa sen vektorointitasolle valinnaisen standardize Perustelu. Kerran sinä adapt() tekstin kerros (NumPy-taulukko tai tekstiluettelo) – sieltä löydät sanaston ja sen koon:

vocab_size = len(vocab)
vocab_size 

Lopuksi sanojen poistamiseksi luomme an index_lookup sanakirja:

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

Se kartoittaa kaikki tunnukset ([1, 2, 3, 4, ...]) sanaston sanoihin (['a', 'the', 'i', ...]). Välittämällä avaimen (tunnusindeksi), saamme sanan helposti takaisin. Nyt voit ajaa vectorize_layer() millä tahansa syötteellä ja tarkkaile vektorisoituja lauseita:

vectorize_layer(['hello world!'])

Mikä johtaa:

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

Hellolla on indeksi 1 kun taas maailmalla on indeksi 7509! Loput on pehmuste maxlen olemme laskeneet.

Meillä on keinot vektorisoida tekstiä – nyt luodaan tietojoukkoja text_train, text_test ja text_valid, käyttämällä vektorointikerrostamme muunnosvälineenä sanojen ja vektoreiden välillä, jotka voidaan syöttää GPT-Fyodoriin.

Tietojoukon luominen

Luomme a tf.data.Dataset jokaiselle sarjallemme käyttämällä from_tensor_slices() ja luettelon antaminen tensoriviipaleista (lauseista):

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)

Kun se on luotu ja sekoitettu (jälleen hyvä mitta), voimme käyttää esikäsittelytoimintoa (vektorisointi ja sekvenssin jakaminen):

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() funktio yksinkertaisesti laajenee viimeisen ulottuvuuden verran, vektorisoi tekstin käyttämällä meidän vectorize_layer ja luo syötteet ja tavoitteet yhdellä tunnuksella korvattuina. Malli tulee käyttämään [0..n] päätellä n+1, joka tuottaa ennusteen jokaiselle sanalle, mikä vastaa kaikkia sitä edeltäviä sanoja. Tarkastellaan yksittäistä merkintää missä tahansa tietojoukossa:

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

Tutkimalla palautettuja syötteitä ja kohteita 64 kappaleen erissä (joiden kunkin pituus on 30), voimme selvästi nähdä, kuinka ne korvataan yhdellä:

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

Lopuksi – on aika rakentaa malli!

Mallin määritelmä

Käytämme tässä KerasNLP-kerroksia. Jälkeen an Input, koodaamme syötteen a:n kautta TokenAndPositionEmbedding kerros, joka kulkee sisään vocab_size, maxlen ja embed_dim. Sama embed_dim että tämä kerros tulostaa ja syöttää sisään TransformerDecoder on säilytetään dekooderissa. Kirjoittamisesta lähtien dekooderi säilyttää automaattisesti syötteen ulottuvuuden, eikä anna sinun projisoida sitä eri lähtöön, mutta sen avulla voit määrittää piilevät mitat intermediate_dim Perustelu.

Kerromme upotusmitat kahdella piilevää esitystä varten, mutta voit pitää sen ennallaan tai käyttää lukua, joka on irrotettu upottamisen himmennyksistä:

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

Dekooderin päällä meillä on a Dense kerros valitaksesi sekvenssin seuraavan sanan a:lla softmax aktivointi (joka tuottaa todennäköisyysjakauman jokaiselle seuraavalle tunnukselle). Katsotaanpa mallin yhteenvetoa:

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 pinoaa monia dekoodeja – GPT-2 Smallissa on 12 pinottua dekooderia (117 M parametria), kun taas GPT-2 Extra Largessa on 48 pinottua dekooderia (1.5 B parametria). Yhden dekooderin mallimme vaatimattomilla 13M-parametreilla pitäisi toimia tarpeeksi hyvin opetustarkoituksiin. LLM:ien avulla skaalaus on osoittautunut erittäin hyväksi strategiaksi, ja Transformers mahdollistaa hyvän skaalauksen, mikä mahdollistaa erittäin suurten mallien kouluttamisen.

GPT-3:ssa on a "niukka" 175B parametrit. Google Brainin tiimi koulutti 1.6 T:n parametrimallin suorittamaan harvalukututkimusta ja pitämään laskennan samalla tasolla kuin paljon pienemmät mallit.

Itse asiassa, jos lisäsimme dekooderien määrää yhdestä kolmeen:

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)

Parametrimme määrä kasvaisi 400 XNUMX:lla:

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

Suurin osa verkostomme parametreista on peräisin TokenAndPositionEmbedding ja Dense kerroksia!

Kokeile dekooderin eri syvyyksiä – 1:stä aina siihen asti, kun koneesi pystyy käsittelemään ja kirjaamaan tulokset. Joka tapauksessa – olemme melkein valmiita kouluttamaan mallia! Luodaan mukautettu takaisinsoitto, joka tuottaa näytetekstiä jokaiselta aikakaudelta, jotta voimme nähdä, kuinka malli oppii muodostamaan lauseita harjoittelun kautta.

Mukautettu takaisinsoitto

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

Mallin kouluttaminen

Viimeinkin on aika treenata! Hyppääkäämme sisään train_dataset ja validation_dataset takaisinsoittojen kanssa:

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

Näytteenotto valitsi valitettavan lauseen, joka alkaa loppulainaus- ja aloituslainauksella, mutta tuottaa silti mielenkiintoisia tuloksia harjoittelun aikana:

# 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

Se alkaa sanoilla:

"Mitä sinä et olisi ollut, minä olisin ollut sama"…

Missä ei oikeastaan ​​ole juurikaan järkeä. Kymmenen lyhyen aikakauden loppuun mennessä se tuottaa jotain seuraavaa:

"Mitä tarkoitat, että se on tietysti miehen tavallisin mies"…

Vaikka toisessa lauseessa ei vieläkään ole liikaa järkeä - se on paljon järkevämpi kuin ensimmäinen. Pidempi datan koulutus (monimutkaisemmilla esikäsittelyvaiheilla) antaisi parempia tuloksia. Olemme kouluttaneet sitä vain 10 aikakaudella, joissa keskeyttäminen on suuri, jotta voimme torjua pientä tietojoukkoa. Jos se jätettäisiin harjoittelemaan paljon pidempään, se tuottaisi hyvin Fjodorin kaltaista tekstiä, koska se olisi muistanut siitä suuria paloja.

Huomautus: Koska tulos on melko monisanainen, voit säätää verbose argumenttia sovittamalla mallia tekstin määrän vähentämiseksi näytöllä.

Mallin päättely

Suorittaaksemme johtopäätöksen haluamme replikoida sovelluksen käyttöliittymän TextSampler – menetelmä, joka hyväksyy siemenen ja a response_length (max_tokens). Käytämme samoja menetelmiä kuin näytteenottimessa:

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

Nyt voit suorittaa menetelmän uusille näytteille:

generate_text('the truth ultimately is')


generate_text('the truth ultimately is')

Tulosten parantaminen?

Joten miten voit parantaa tuloksia? Voit tehdä joitain melko toimivia asioita:

  • Tietojen puhdistus (siivoa syöttötiedot huolellisemmin, leikkasimme vain likimääräisen luvun alusta ja poistimme rivinvaihtomerkit)
  • Hanki lisää dataa (työskentelimme vain muutaman megatavun tekstidatan kanssa)
  • Skaalaa mallia tietojen rinnalla (dekoodereiden pinoaminen ei ole vaikeaa!)

Yhteenveto

Vaikka esikäsittelyprosessi on minimalistinen ja sitä voidaan parantaa – tässä oppaassa kuvattu prosessi tuotti kunnollisen GPT-tyylisen mallin, jossa tarvitaan vain 5 koodiriviä mukautetun vain dekooderin muuntajan rakentamiseen Kerasin avulla!

Muuntajat ovat suosittuja ja laajalti sovellettavissa yleiseen sekvenssimallinnukseen (ja monia asioita voidaan ilmaista sekvensseinä). Toistaiseksi pääsyn esteenä oli hankala toteutus, mutta KerasNLP:n avulla syväoppimisen ammattilaiset voivat hyödyntää toteutuksia rakentaakseen malleja nopeasti ja helposti.

Aikaleima:

Lisää aiheesta Stackabus