TensorFlow/Keras . के साथ पायथन में 5-लाइन GPT- स्टाइल टेक्स्ट जनरेशन

2017 में रिलीज होने के बावजूद, ट्रांसफॉर्मर ने पिछले कुछ वर्षों में केवल महत्वपूर्ण कर्षण प्राप्त करना शुरू कर दिया है। हगिंगफेस, एनएलपी और . जैसे प्लेटफार्मों के माध्यम से प्रौद्योगिकी के प्रसार के साथ बड़े भाषा मॉडल (एलएलएम) पहले से कहीं अधिक सुलभ हो गए हैं।

फिर भी - यहां तक ​​कि उनके आस-पास के सभी प्रचार के साथ और साथ बहुत सिद्धांत-उन्मुख गाइड, ऑनलाइन कई कस्टम कार्यान्वयन नहीं हैं, और संसाधन कुछ अन्य नेटवर्क प्रकारों के साथ आसानी से उपलब्ध नहीं हैं, जो कि लंबे समय से आसपास हैं। जबकि आप हगिंगफेस (एक अन्य गाइड का विषय) से पूर्व-निर्मित ट्रांसफार्मर का उपयोग करके अपने कार्यचक्र को सरल बना सकते हैं - आप प्राप्त कर सकते हैं लग रहा है पुस्तकालय के माध्यम से इसे दूर करने से पहले, यह स्वयं को बनाकर कैसे काम करता है। हम यहां सिद्धांत और अनुकूलन के बजाय निर्माण पर ध्यान केंद्रित करेंगे।

इस गाइड में, हम एक का निर्माण करेंगे ऑटोरेग्रेसिव भाषा मॉडल सेवा मेरे पाठ उत्पन्न करें. हम डेटा लोड करने, इसे विभाजित करने, इसे वेक्टराइज़ करने, एक मॉडल बनाने, एक कस्टम कॉलबैक लिखने और प्रशिक्षण/अनुमान के व्यावहारिक और न्यूनतर/संक्षिप्त पहलुओं पर ध्यान केंद्रित करेंगे। इनमें से प्रत्येक कार्य को अधिक विस्तृत मार्गदर्शिकाओं में शामिल किया जा सकता है, इसलिए हम आपके स्वयं के डेटासेट के आधार पर अनुकूलन और अनुकूलन के लिए जगह छोड़कर, कार्यान्वयन को एक सामान्य के रूप में रखेंगे।

एलएलएम और जीपीटी-फ्योडोर के प्रकार

जबकि वर्गीकरण बहुत अधिक जटिल हो सकता है - आप कर सकते हैं मोटे तौर पर ट्रांसफॉर्मर-आधारित भाषा मॉडल को तीन श्रेणियों में वर्गीकृत करें:

  • एनकोडर-आधारित मॉडल - अल्बर्ट, बर्ट, डिस्टिलबर्ट, रॉबर्ट
  • डिकोडर-आधारित - जीपीटी, जीपीटी-2, जीपीटी-3, ट्रांसफॉर्मरएक्सएल
  • Seq2Seq मॉडल - बार्ट, एमबार्ट, टी5

एनकोडर-आधारित मॉडल केवल अपने आर्किटेक्चर (आमतौर पर, स्टैक्ड) में एक ट्रांसफॉर्मर एन्कोडर का उपयोग करते हैं और वाक्यों (वर्गीकरण, नामित इकाई पहचान, प्रश्न उत्तर) को समझने के लिए महान हैं।

डिकोडर-आधारित मॉडल केवल अपने आर्किटेक्चर में एक ट्रांसफॉर्मर डिकोडर का उपयोग करते हैं (आमतौर पर स्टैक्ड भी होते हैं) और भविष्य की भविष्यवाणी के लिए बहुत अच्छे होते हैं, जो उन्हें टेक्स्ट जनरेशन के लिए उपयुक्त बनाता है।

Seq2Seq मॉडल एन्कोडर और डिकोडर दोनों को जोड़ते हैं और टेक्स्ट जनरेशन, सारांशीकरण और सबसे महत्वपूर्ण - अनुवाद में महान हैं।

मॉडल का GPT परिवार, जिसने पिछले कुछ वर्षों में बहुत अधिक कर्षण प्राप्त किया है, डिकोडर-आधारित ट्रांसफॉर्मर मॉडल हैं, और मानव-सदृश पाठ का निर्माण करने में महान हैं, डेटा के बड़े कॉर्पोरा पर प्रशिक्षित हैं, और एक नए के रूप में एक संकेत दिया है। पीढ़ी के लिए बीज शुरू करना। उदाहरण के लिए:

generate_text('the truth ultimately is')

जो हुड के तहत इस संकेत को GPT- जैसे मॉडल में फीड करता है, और उत्पादन करता है:

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

यह वास्तव में, गाइड के अंत से एक छोटा सा स्पॉइलर है! एक और छोटा स्पॉइलर वह आर्किटेक्चर है जिसने उस टेक्स्ट को तैयार किया है:

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 लाइनें होती हैं - एक छोटे से GPT का अनुकरण करना। चूंकि हम मॉडल को फ्योडोर दोस्तोयेव्स्की के उपन्यासों पर प्रशिक्षण देंगे (जिसे आप विकिपीडिया से लेकर रेडिट टिप्पणियों तक किसी और चीज़ से बदल सकते हैं) - हम मॉडल को अस्थायी रूप से कहेंगे जीपीटी-फ्योडोर.

केरसएनएलपी

5-लाइन जीपीटी-फ्योडोर की चाल में निहित है केरसएनएलपी, जिसे आधिकारिक केरस टीम द्वारा विकसित किया गया है, केरस के क्षैतिज विस्तार के रूप में, जो कि वास्तव में केरस फैशन में, नई परतों (एनकोडर, डिकोडर, टोकन एम्बेडिंग, स्थिति एम्बेडिंग, मेट्रिक्स) के साथ उद्योग-शक्ति एनएलपी को आपकी उंगलियों पर लाना है। टोकन, आदि)।

KerasNLP एक मॉडल चिड़ियाघर नहीं है. यह केरस (एक अलग पैकेज के रूप में) का एक हिस्सा है, जो एनएलपी मॉडल के विकास के लिए प्रवेश की बाधा को कम करता है, जैसे यह मुख्य पैकेज के साथ सामान्य गहन शिक्षण विकास के लिए प्रवेश की बाधा को कम करता है।

नोट: लेखन के रूप में KerasNLP अभी भी तैयार किया जा रहा है, और प्रारंभिक अवस्था में। भविष्य के संस्करणों में सूक्ष्म अंतर मौजूद हो सकते हैं। राइटअप संस्करण का उपयोग कर रहा है 0.3.0.

KerasNLP का उपयोग करने में सक्षम होने के लिए, आपको इसे इसके माध्यम से स्थापित करना होगा pip:

$ pip install keras_nlp

और आप इसके साथ संस्करण को सत्यापित कर सकते हैं:

keras_nlp.__version__

केरास के साथ जीपीटी-शैली मॉडल लागू करना

आइए उन पुस्तकालयों को आयात करके शुरू करें जिनका हम उपयोग करेंगे - TensorFlow, Keras, KerasNLP और NumPy:

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

डेटा लोड हो रहा है

आइए डोस्टॉयव्स्की के कुछ उपन्यासों को लोड करें - एक मॉडल के लिए फिट होने के लिए एक रास्ता बहुत छोटा होगा, शुरुआती चरणों से थोड़ा अधिक ओवरफिटिंग के बिना। हम इनायत से कच्ची पाठ फ़ाइलों का उपयोग करेंगे प्रोजेक्ट गुटेनबर्ग, ऐसे डेटा के साथ काम करने की सरलता के कारण:

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

हमने बस सभी फाइलों को डाउनलोड कर लिया है, उनके माध्यम से चले गए हैं और उन्हें एक के ऊपर एक जोड़ दिया है। इसमें इस्तेमाल की जाने वाली भाषा में कुछ विविधता शामिल है, जबकि इसे अभी भी स्पष्ट रूप से रखते हुए फ्योडोर! प्रत्येक फ़ाइल के लिए, हमने पहले 10k वर्णों को छोड़ दिया है, जो कि प्रस्तावना और गुटेनबर्ग परिचय की औसत लंबाई के आसपास है, इसलिए हमारे पास प्रत्येक पुनरावृत्ति के लिए पुस्तक के एक बड़े पैमाने पर अक्षुण्ण शरीर के साथ छोड़ दिया गया है। आइए कुछ यादृच्छिक 500 वर्णों पर एक नज़र डालें texts अब स्ट्रिंग:


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'

किसी अन्य प्रक्रिया को करने से पहले स्ट्रिंग को वाक्यों में अलग करें:

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

हमारे पास 69k वाक्य हैं। जब आप को प्रतिस्थापित करते हैं n रिक्त स्थान वाले वर्ण और शब्दों को गिनें:

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

नोट: आप आमतौर पर किसी डेटासेट में कम से कम दस लाख शब्द रखना चाहेंगे, और आदर्श रूप से, उससे कहीं अधिक। हम कुछ मेगाबाइट डेटा (~5MB) के साथ काम कर रहे हैं, जबकि भाषा मॉडल आमतौर पर दसियों गीगाबाइट टेक्स्ट पर प्रशिक्षित होते हैं। यह, स्वाभाविक रूप से, टेक्स्ट इनपुट को ओवरफिट करना और सामान्यीकरण करना कठिन बना देगा (ओवरफिटिंग के बिना उच्च परेशानी, या बहुत अधिक ओवरफिटिंग के साथ कम परेशानी)। नमक के एक दाने के साथ परिणाम लें।

फिर भी, आइए इन्हें a . में विभाजित करें ट्रेनिंग, परीक्षण और सत्यापन समूह। सबसे पहले, खाली स्ट्रिंग्स को हटा दें और वाक्यों को फेरबदल करें:


text_list = list(filter(None, text_list))

import random
random.shuffle(text_list)

फिर, हम 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):]

ट्रेन-परीक्षण-सत्यापन विभाजन करने का यह एक सरल, लेकिन प्रभावी तरीका है। आइए एक नज़र डालते हैं 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', ...

मानकीकरण और वैश्वीकरण का समय!

पाठ वैश्वीकरण

नेटवर्क शब्दों को नहीं समझते - वे संख्याओं को समझते हैं। हम शब्दों को टोकन देना चाहेंगे:

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

इसके अलावा, चूंकि वाक्य लंबाई में भिन्न होते हैं - पैडिंग को आम तौर पर बाएं या दाएं जोड़ा जाता है ताकि यह सुनिश्चित हो सके कि सभी वाक्यों में समान आकार दिया जा रहा है। कहें कि हमारा सबसे लंबा वाक्य 5-शब्द (टोकन) लंबा है। उस स्थिति में, वॉल-ई वाक्य दो शून्य से गद्देदार होगा, इसलिए हम एक ही इनपुट आकार सुनिश्चित करते हैं:

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

परंपरागत रूप से, यह एक TensorFlow का उपयोग करके किया गया था Tokenizer और केरस' pad_sequences() विधियाँ - हालाँकि, एक बहुत आसान परत, TextVectorization, इस्तेमाल किया जा सकता है, जो टोकन करता है और आपके इनपुट को पैड करता है, आपको शब्दावली और उसके आकार को निकालने की अनुमति देता है, वोकैब को पहले से जाने बिना!

सर्वोत्तम प्रथाओं, उद्योग-स्वीकृत मानकों और शामिल चीट शीट के साथ, Git सीखने के लिए व्यावहारिक मार्गदर्शिका देखें। Googling Git कमांड को रोकें और वास्तव में सीखना यह!

आइए अनुकूलित करें और फिट करें a TextVectorization परत:

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

RSI custom_standardization() विधि इससे बहुत अधिक लंबी हो सकती है। हमने बस सभी इनपुट को कम कर दिया है और बदल दिया है n साथ में " ". यह वह जगह है जहां आप वास्तव में टेक्स्ट के लिए अपने अधिकांश प्रीप्रोसेसिंग में डाल सकते हैं - और इसे वैकल्पिक के माध्यम से वेक्टराइज़ेशन परत पर आपूर्ति कर सकते हैं standardize बहस। आप एक बार adapt() पाठ की परत (NumPy सरणी या ग्रंथों की सूची) - आप वहां से शब्दावली, साथ ही उसका आकार प्राप्त कर सकते हैं:

vocab_size = len(vocab)
vocab_size 

अंत में, शब्दों को डी-टोकनाइज़ करने के लिए, हम एक बनाएँगे index_lookup शब्दकोश:

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

यह सभी टोकन को मैप करता है ([1, 2, 3, 4, ...]) शब्दावली में शब्दों के लिए (['a', 'the', 'i', ...]) एक कुंजी (टोकन इंडेक्स) में पास करके, हम आसानी से शब्द वापस पा सकते हैं। अब आप चला सकते हैं vectorize_layer() किसी भी इनपुट पर और सदिश वाक्यों का निरीक्षण करें:

vectorize_layer(['hello world!'])

जिसके परिणामस्वरूप:

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

नमस्ते का सूचकांक है 1 जबकि दुनिया का सूचकांक है 7509! बाकी के लिए गद्दी है maxlen हमने गणना की है।

हमारे पास टेक्स्ट को वेक्टराइज़ करने के साधन हैं - अब, आइए से डेटासेट बनाते हैं text_train, text_test और text_valid, शब्दों और सदिशों के बीच रूपांतरण माध्यम के रूप में हमारी सदिशीकरण परत का उपयोग करते हुए जिसे GPT-Fyodor में फीड किया जा सकता है।

डेटासेट निर्माण

हम एक बना रहे होंगे tf.data.Dataset हमारे प्रत्येक सेट के लिए, का उपयोग कर from_tensor_slices() और, अच्छी तरह से, टेंसर स्लाइस (वाक्य) की एक सूची प्रदान करना:

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)

एक बार बनाया और फेरबदल (फिर से, अच्छे उपाय के लिए) - हम एक प्रीप्रोसेसिंग (वेक्टराइजेशन और अनुक्रम विभाजन) फ़ंक्शन लागू कर सकते हैं:

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)

RSI preprocess_text() फ़ंक्शन केवल अंतिम आयाम से फैलता है, हमारे . का उपयोग करके टेक्स्ट को वेक्टर करता है vectorize_layer और एक टोकन द्वारा ऑफसेट, इनपुट और लक्ष्य बनाता है। मॉडल का उपयोग करेगा [0..n] अनुमान लगाना n+1, प्रत्येक शब्द के लिए एक भविष्यवाणी देना, उससे पहले के सभी शब्दों का हिसाब देना। आइए किसी भी डेटासेट में एकल प्रविष्टि पर एक नज़र डालें:

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

64 (प्रत्येक की लंबाई 30 की लंबाई के साथ) के बैचों में लौटाए गए इनपुट और लक्ष्यों की जांच करते हुए, हम स्पष्ट रूप से देख सकते हैं कि वे एक से कैसे ऑफसेट होते हैं:

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

अंत में - यह मॉडल बनाने का समय है!

मॉडल परिभाषा

हम यहाँ KerasNLP लेयर्स का उपयोग करेंगे। एक के बाद Input, हम इनपुट को a . के माध्यम से एन्कोड करेंगे TokenAndPositionEmbedding परत, हमारे में गुजर रहा है vocab_size, maxlen और embed_dim। जो उसी embed_dim कि यह परत आउटपुट और इनपुट करती है TransformerDecoder होगा डिकोडर में रखा गया. लेखन के रूप में, डिकोडर स्वचालित रूप से इनपुट आयाम बनाए रखता है, और आपको इसे एक अलग आउटपुट में प्रोजेक्ट करने की अनुमति नहीं देता है, लेकिन यह आपको गुप्त आयामों को परिभाषित करने देता है intermediate_dim तर्क।

हम अव्यक्त प्रतिनिधित्व के लिए एम्बेडिंग आयामों को दो से गुणा करेंगे, लेकिन आप इसे वही रख सकते हैं या एम्बेडिंग डिम से अलग की गई संख्या का उपयोग कर सकते हैं:

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

डिकोडर के ऊपर, हमारे पास a Dense अनुक्रम में अगला शब्द चुनने के लिए परत, a . के साथ softmax सक्रियण (जो प्रत्येक अगले टोकन के लिए संभाव्यता वितरण उत्पन्न करता है)। आइए मॉडल के सारांश पर एक नज़र डालें:

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 कई डिकोडर्स को स्टैक करता है - GPT-2 स्मॉल में 12 स्टैक्ड डिकोडर (117M पैरा) होते हैं, जबकि GPT-2 एक्स्ट्रा लार्ज में 48 स्टैक्ड डिकोडर (1.5B पैरा) होते हैं। 13M मापदंडों के साथ हमारा सिंगल-डिकोडर मॉडल शैक्षिक उद्देश्यों के लिए पर्याप्त रूप से काम करना चाहिए। एलएलएम के साथ - स्केलिंग अप एक बहुत अच्छी रणनीति साबित हुई है, और ट्रांसफॉर्मर अच्छे स्केलिंग की अनुमति देते हैं, जिससे बहुत बड़े मॉडल को प्रशिक्षित करना संभव हो जाता है।

GPT-3 में a . है "अल्प" 175B पैरामीटर। Google ब्रेन की टीम ने 1.6T पैरामीटर मॉडल को बहुत छोटे मॉडल के समान स्तर पर गणना करते हुए विरल अनुसंधान करने के लिए प्रशिक्षित किया।

वास्तव में, अगर हमने डिकोडर्स की संख्या 1 से बढ़ाकर 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)

हमारी पैरामीटर गिनती 400k तक बढ़ाई जाएगी:

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

हमारे नेटवर्क में अधिकांश पैरामीटर से आते हैं TokenAndPositionEmbedding और Dense परतें!

डिकोडर की अलग-अलग गहराई का प्रयास करें - 1 से लेकर सभी तरह से आपकी मशीन संभाल सकती है और परिणामों को नोट कर सकती है। किसी भी मामले में - हम मॉडल को प्रशिक्षित करने के लिए लगभग तैयार हैं! आइए एक कस्टम कॉलबैक बनाएं जो प्रत्येक युग पर पाठ का एक नमूना तैयार करेगा, ताकि हम देख सकें कि मॉडल प्रशिक्षण के माध्यम से वाक्य बनाना कैसे सीखता है।

कस्टम कॉलबैक

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

मॉडल को प्रशिक्षित करना

अंत में, प्रशिक्षण का समय! चलो हमारे में चक train_dataset और validation_dataset कॉलबैक के साथ जगह में:

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

सैम्पलर ने एक दुर्भाग्यपूर्ण वाक्य चुना जो अंतिम उद्धरण से शुरू होता है और उद्धरण शुरू करता है, लेकिन यह अभी भी प्रशिक्षण के दौरान दिलचस्प परिणाम देता है:

# 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

इसके साथ शुरू होता है:

"तुम क्या नहीं थे मैं वही था"...

जो वास्तव में ज्यादा समझ में नहीं आता है। दस छोटे युगों के अंत तक, यह कुछ इस प्रकार उत्पन्न करता है:

"आपका क्या मतलब है कि निश्चित रूप से एक आदमी का सबसे साधारण आदमी है" ...

जबकि दूसरा वाक्य अभी भी बहुत अधिक समझ में नहीं आता है - यह पहले की तुलना में बहुत अधिक कामुक है। अधिक डेटा पर लंबे समय तक प्रशिक्षण (अधिक जटिल प्रीप्रोसेसिंग चरणों के साथ) बेहतर परिणाम देगा। हमने इसे छोटे डेटासेट आकार से निपटने के लिए केवल 10 युगों में उच्च ड्रॉपआउट के साथ प्रशिक्षित किया है। यदि इसे अधिक समय तक प्रशिक्षण के लिए छोड़ दिया जाता है, तो यह बहुत ही फ्योडोर जैसा पाठ उत्पन्न करेगा, क्योंकि इसने इसके बड़े हिस्से को याद कर लिया होगा।

नोट: चूंकि आउटपुट काफी वर्बोज़ है, आप इसे ट्वीक कर सकते हैं verbose स्क्रीन पर टेक्स्ट की मात्रा को कम करने के लिए मॉडल को फिट करते समय तर्क।

मॉडल अनुमान

अनुमान लगाने के लिए, हम के इंटरफ़ेस को दोहराना चाहेंगे TextSampler - एक विधि जो एक बीज और एक को स्वीकार करती है response_length (max_tokens) हम सैम्पलर के समान विधियों का उपयोग करेंगे:

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

अब, आप विधि को नए नमूनों पर चला सकते हैं:

generate_text('the truth ultimately is')


generate_text('the truth ultimately is')

परिणामों में सुधार?

तो, आप परिणाम कैसे सुधार सकते हैं? कुछ सुंदर क्रियात्मक चीजें हैं जो आप कर सकते हैं:

  • डेटा की सफाई (इनपुट डेटा को अधिक सावधानी से साफ करें, हमने शुरुआत से एक अनुमानित संख्या को छंटनी की और न्यूलाइन वर्णों को हटा दिया)
  • अधिक डेटा प्राप्त करें (हमने केवल कुछ मेगाबाइट टेक्स्ट डेटा के साथ काम किया है)
  • डेटा के साथ मॉडल को स्केल करें (डिकोडर्स को स्टैक करना कठिन नहीं है!)

निष्कर्ष

जबकि प्रीप्रोसेसिंग पाइपलाइन न्यूनतर है और इसमें सुधार किया जा सकता है - इस गाइड में उल्लिखित पाइपलाइन ने एक अच्छा जीपीटी-शैली मॉडल तैयार किया, जिसमें केरस का उपयोग करके कस्टम डिकोडर-केवल ट्रांसफार्मर बनाने के लिए कोड की केवल 5 पंक्तियों की आवश्यकता होती है!

सामान्य अनुक्रम मॉडलिंग के लिए ट्रांसफॉर्मर लोकप्रिय और व्यापक रूप से लागू होते हैं (और कई चीजों को अनुक्रम के रूप में व्यक्त किया जा सकता है)। अब तक, प्रवेश के लिए मुख्य बाधा एक बोझिल कार्यान्वयन था, लेकिन KerasNLP के साथ - गहन शिक्षण अभ्यासकर्ता जल्दी और आसानी से मॉडल बनाने के लिए कार्यान्वयन का लाभ उठा सकते हैं।

समय टिकट:

से अधिक स्टैकब्यूज