5-Raders GPT-stil textgenerering i Python med TensorFlow/Keras

Transformers, även om de släpptes 2017, har bara börjat få betydande dragkraft under de senaste åren. Med spridningen av tekniken genom plattformar som HuggingFace, NLP och Stora språkmodeller (LLMs) har blivit mer tillgänglig än någonsin.

Ändå – även med all hype runt dem och med många teoriorienterade guider, det finns inte många anpassade implementeringar online och resurserna är inte lika lättillgängliga som med vissa andra nätverkstyper som har funnits längre. Även om du kan förenkla din arbetscykel genom att använda en förbyggd transformator från HuggingFace (ämnet i en annan guide) – kan du komma till känna hur det fungerar genom att bygga en själv, innan du abstraherar bort den genom ett bibliotek. Vi kommer att fokusera på att bygga, snarare än teori och optimering här.

I den här guiden kommer vi att bygga en Autoregressiv språkmodell till skapa text. Vi kommer att fokusera på de praktiska och minimalistiska/koncisa aspekterna av att ladda data, dela upp den, vektorisera den, bygga en modell, skriva en anpassad återuppringning och utbildning/inferens. Var och en av dessa uppgifter kan delas ut i mer detaljerade guider, så vi kommer att behålla implementeringen som en generisk sådan, vilket ger utrymme för anpassning och optimering beroende på din egen datauppsättning.

Typer av LLM och GPT-Fyodor

Även om kategorisering kan bli mycket mer intrikat – det kan du brett kategorisera transformatorbaserade språkmodeller i tre kategorier:

  • Encoder-baserade modeller – ALBERT, BERT, DistilBERT, Roberta
  • Dekoderbaserad – GPT, GPT-2, GPT-3, TransformerXL
  • Seq2Seq-modeller – BART, mBART, T5

Encoder-baserad modeller använder bara en transformatorkodare i sin arkitektur (vanligtvis staplade) och är utmärkta för att förstå meningar (klassificering, namngiven enhetsigenkänning, frågesvar).

Dekoderbaserad modeller använder bara en Transformer-avkodare i sin arkitektur (också vanligtvis staplade) och är utmärkta för framtida förutsägelse, vilket gör dem lämpliga för textgenerering.

Seq2Seq modeller kombinerar både kodare och avkodare och är fantastiska på textgenerering, sammanfattning och viktigast av allt – översättning.

GPT-modellfamiljen, som vunnit mycket dragkraft under de senaste åren, är avkodarbaserade transformatormodeller och är fantastiska på att producera människoliknande text, tränade på stora datakorpora och får en uppmaning som en ny startfrö för generation. Till exempel:

generate_text('the truth ultimately is')

Som under huven matar in denna prompt till en GPT-liknande modell och producerar:

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

Detta är faktiskt en liten spoiler från slutet av guiden! En annan liten spoiler är arkitekturen som producerade den texten:

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 linjer är allt som krävs för att bygga en transformatormodell med endast avkodare – som simulerar en liten GPT. Eftersom vi kommer att träna modellen på Fjodor Dostojevskijs romaner (som du kan ersätta med allt annat, från Wikipedia till Reddit-kommentarer) – kommer vi preliminärt att kalla modellen GPT-Fyodor.

KerasNLP

Tricket till en 5-linjers GPT-Fyodor ligger i KerasNLP, som är utvecklad av det officiella Keras-teamet, som en horisontell förlängning av Keras, som på sant Keras-manér syftar till att ge branschstark NLP till dina fingertoppar, med nya lager (kodare, avkodare, token-inbäddningar, positionsinbäddningar, mätvärden, tokenizers, etc.).

KerasNLP är inte en modellzoo. Det är en del av Keras (som ett separat paket), som sänker inträdesbarriären för NLP-modellutveckling, precis som den sänker inträdesbarriären för allmän djupinlärningsutveckling med huvudpaketet.

Notera: I skrivande stund produceras KerasNLP fortfarande, och i tidiga skeden. Subtila skillnader kan förekomma i framtida versioner. Skrivningen använder versionen 0.3.0.

För att kunna använda KerasNLP måste du installera det via pip:

$ pip install keras_nlp

Och du kan verifiera versionen med:

keras_nlp.__version__

Implementering av en modell i GPT-stil med Keras

Låt oss börja med att importera biblioteken vi kommer att använda – TensorFlow, Keras, KerasNLP och NumPy:

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

Laddar data

Låt oss ladda in några av Dostojevskijs romaner – en skulle vara alldeles för kort för att en modell skulle passa, utan en hel del överanpassad från de tidiga stadierna och framåt. Vi kommer graciöst att använda råtextfilerna från Project Gutenberg, på grund av enkelheten att arbeta med sådana data:

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

Vi har helt enkelt laddat ner alla filer, gått igenom dem och sammanfogat dem ovanpå varandra. Detta inkluderar en viss mångfald i språket som används, samtidigt som det behåller det distinkt Fyodor! För varje fil har vi hoppat över de första 10 500 tecknen, vilket är ungefär den genomsnittliga längden på förordet och Gutenberg-introt, så vi har en i stort sett intakt del av boken för varje iteration. Låt oss ta en titt på några slumpmässiga XNUMX tecken i texts sträng nu:


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'

Låt oss dela upp strängen i meningar innan vi gör någon annan bearbetning:

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

Vi har 69 XNUMX meningar. När du byter ut n tecken med blanksteg och räkna orden:

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

Notera: Du vill i allmänhet ha minst en miljon ord i en datauppsättning, och helst mycket mycket mer än så. Vi arbetar med några megabyte data (~5MB) medan språkmodeller är vanligare tränade på tiotals gigabyte text. Detta kommer naturligtvis att göra det väldigt lätt att överanpassa textinmatningen och svårt att generalisera (hög förvirring utan överanpassning, eller låg förvirring med mycket överanpassning). Ta resultaten med en nypa salt.

Ändå, låt oss dela upp dessa i en utbildning, testa och godkännande uppsättning. Låt oss först ta bort de tomma strängarna och blanda meningarna:


text_list = list(filter(None, text_list))

import random
random.shuffle(text_list)

Sedan gör vi en uppdelning 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):]

Detta är ett enkelt men ändå effektivt sätt att utföra en tåg-test-valideringsdelning. Låt oss ta en titt på 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', ...

Dags för standardisering och vektorisering!

Textvektorisering

Nätverk förstår inte ord – de förstår siffror. Vi vill symbolisera orden:

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

Dessutom, eftersom meningar skiljer sig i längd – läggs utfyllnad vanligtvis till vänster eller höger för att säkerställa samma form över meningar som matas in. Säg att vår längsta mening är 5-ord (tokens) lång. I så fall skulle Wall-E-satsen fyllas ut med två nollor så att vi säkerställer samma inmatningsform:

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

Traditionellt gjordes detta med ett TensorFlow Tokenizer och Keras' pad_sequences() metoder – dock ett mycket smidigare lager, TextVectorization, kan användas, vilket symboliserar och förstärker din inmatning, så att du kan extrahera ordförrådet och dess storlek, utan att känna till ordförrådet i förväg!

Kolla in vår praktiska, praktiska guide för att lära dig Git, med bästa praxis, branschaccepterade standarder och medföljande fuskblad. Sluta googla Git-kommandon och faktiskt lära Det!

Låt oss anpassa och passa en TextVectorization lager:

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

Smakämnen custom_standardization() metoden kan bli mycket längre än så här. Vi har helt enkelt förminskat all inmatning och ersatt n med " ". Det är här du verkligen kan lägga in det mesta av din förbearbetning för text – och leverera den till vektoriseringslagret genom det valfria standardize argument. När du adapt() lagret till texten (NumPy-array eller lista med texter) – du kan hämta vokabulären, såväl som dess storlek därifrån:

vocab_size = len(vocab)
vocab_size 

Slutligen, för att de-tokenisera ord, skapar vi en index_lookup ordbok:

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

Den kartlägger alla tokens ([1, 2, 3, 4, ...]) till ord i vokabulären (['a', 'the', 'i', ...]). Genom att skicka in en nyckel (token index) kan vi enkelt få tillbaka ordet. Du kan nu köra vectorize_layer() på vilken inmatning som helst och observera de vektoriserade meningarna:

vectorize_layer(['hello world!'])

Vilket resulterar i:

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

Hej har indexet på 1 medan världen har indexet på 7509! Resten är stoppningen till maxlen vi har räknat ut.

Vi har möjligheten att vektorisera text – låt oss nu skapa datamängder från text_train, text_test och text_valid, med vårt vektoriseringslager som ett omvandlingsmedium mellan ord och vektorer som kan matas in i GPT-Fyodor.

Skapande av datamängder

Vi kommer att skapa en tf.data.Dataset för var och en av våra uppsättningar, med hjälp av from_tensor_slices() och tillhandahålla en lista över, ja, tensorskivor (meningar):

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)

När vi väl har skapat och blandat (igen, för gott skull) – kan vi använda en förbearbetningsfunktion (vektorisering och sekvensdelning):

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)

Smakämnen preprocess_text() funktionen expanderar helt enkelt med den sista dimensionen, vektoriserar texten med vår vectorize_layer och skapar ingångarna och målen, kompenserade av en enda token. Modellen kommer att använda [0..n] att antyda n+1, vilket ger en förutsägelse för varje ord, som står för alla ord innan dess. Låt oss ta en titt på en enskild post i någon av datamängderna:

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

När vi undersöker de returnerade ingångarna och målen, i omgångar om 64 (med en längd på 30 vardera), kan vi tydligt se hur de kompenseras av ett:

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

Äntligen – det är dags att bygga modellen!

Modelldefinition

Vi kommer att använda oss av KerasNLP-lager här. Efter en Input, kodar vi ingången genom a TokenAndPositionEmbedding lager, passerar i vår vocab_size, maxlen och embed_dim. Det samma embed_dim att detta lager matar ut och matar in i TransformerDecoder kommer vara kvar i avkodaren. När avkodaren skrivs bibehåller avkodaren automatiskt ingångsdimensionaliteten och låter dig inte projicera den till en annan utgång, men den låter dig definiera de latenta dimensionerna genom intermediate_dim argument.

Vi multiplicerar inbäddningsdimensionerna med två för den latenta representationen, men du kan behålla den oförändrad eller använda en siffra som är lös från de inbäddade nedtoningarna:

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

Ovanpå dekodern har vi en Dense lager för att välja nästa ord i sekvensen, med en softmax aktivering (som producerar sannolikhetsfördelningen för varje nästa token). Låt oss ta en titt på sammanfattningen av modellen:

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 staplar många avkodare – GPT-2 Small har 12 staplade avkodare (117M params), medan GPT-2 Extra Large har 48 staplade avkodare (1.5B params). Vår enkeldekodermodell med enkla 13M parametrar borde fungera tillräckligt bra för utbildningsändamål. Med LLMs – uppskalning har visat sig vara en mycket bra strategi, och Transformers möjliggör bra skalning, vilket gör det möjligt att träna extremt stora modeller.

GPT-3 har en "mager" 175B parametrar. Google Brains team utbildade en 1.6T-parametermodell för att utföra sparsamhetsforskning samtidigt som beräkningen hölls på samma nivå som mycket mindre modeller.

Faktum är att om vi ökade antalet avkodare från 1 till 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)

Vårt parameterantal skulle ökas med 400k:

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

De flesta parametrarna i vårt nätverk kommer från TokenAndPositionEmbedding och Dense skikten!

Prova olika djup på dekodern – från 1 till hur din maskin kan hantera och notera resultaten. Hur som helst – vi är nästan redo att träna modellen! Låt oss skapa en anpassad återuppringning som producerar ett urval av text för varje epok, så att vi kan se hur modellen lär sig att bilda meningar genom träning.

Anpassad återuppringning

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

Träna modellen

Äntligen dags att träna! Låt oss slänga i oss train_dataset och validation_dataset med återuppringningar på plats:

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

Provtagaren valde en olycklig mening som börjar med slutcitatet och startcitatet, men den ger fortfarande intressanta resultat under träning:

# 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

Det börjar med:

"Vad hade du inte varit jag hade varit densamma"...

Vilket egentligen inte är så vettigt. I slutet av de tio korta epokerna producerar den något i stil med:

"Vad menar du att det är den vanligaste mannen av en man såklart"...

Även om den andra meningen fortfarande inte är så meningsfull – den är mycket mer vettig än den första. Längre träning på mer data (med mer intrikata förbearbetningssteg) skulle ge bättre resultat. Vi har bara tränat det på 10 epoker med högt avhopp för att bekämpa den lilla datasetstorleken. Om den fick träna mycket längre skulle den producera mycket Fyodor-liknande text, eftersom den skulle ha memorerat stora bitar av den.

Notera: Eftersom utgången är ganska mångsidig kan du justera verbose argument samtidigt som modellen anpassas för att minska mängden text på skärmen.

Modellinferens

För att göra slutledning vill vi replikera gränssnittet för TextSampler – en metod som accepterar ett frö och en response_length (max_tokens). Vi kommer att använda samma metoder som inom samplern:

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

Nu kan du köra metoden på nya prover:

generate_text('the truth ultimately is')


generate_text('the truth ultimately is')

Förbättra resultat?

Så hur kan du förbättra resultaten? Det finns några ganska praktiska saker du kan göra:

  • Datarensning (rensa indata mer noggrant, vi trimmade bara ett ungefärligt antal från början och tog bort nyradstecken)
  • Få mer data (vi arbetade bara med några få megabyte textdata)
  • Skala modellen tillsammans med data (stapla avkodare är inte svårt!)

Slutsats

Även om förbearbetningspipelinen är minimalistisk och kan förbättras - den pipeline som beskrivs i den här guiden producerade en anständig GPT-modell, med bara 5 rader kod som krävs för att bygga en anpassad transformator med endast avkodare, med hjälp av Keras!

Transformatorer är populära och allmänt användbara för generisk sekvensmodellering (och många saker kan uttryckas som sekvenser). Hittills var det främsta hindret för inträde en besvärlig implementering, men med KerasNLP – utövare av djupinlärning kan utnyttja implementeringarna för att snabbt och enkelt bygga modeller.

Tidsstämpel:

Mer från Stackabuse