Ta strona została przetłumaczona przez Cloud Translation API.
Switch to English

Generowanie tekstu z numerem RNN

Zobacz na TensorFlow.org Uruchom w Google Colab Wyświetl źródło na GitHub Pobierz notatnik

W tym samouczku przedstawiono sposób generowania tekstu przy użyciu RNN opartego na znakach. Będziemy pracować z zestawem danych dzieł Szekspira z książki Andreja Karpathy'ego The Unreasonable Effectiveness of Recurrent Neural Networks . Mając sekwencję znaków z tych danych („Szekspir”), wytrenuj model do przewidywania następnego znaku w sekwencji („e”). Dłuższe sekwencje tekstu można generować przez wielokrotne wywoływanie modelu.

Ten samouczek zawiera uruchamialny kod zaimplementowany przy użyciu tf.keras i szybkie wykonanie . Poniżej przedstawiono przykładowe dane wyjściowe, gdy model w tym samouczku był szkolony przez 30 epok i rozpoczynał się od ciągu „Q”:

QUEENE:
I had thought thou hadst a Roman; for the oracle,
Thus by All bids the man against the word,
Which are so weak of care, by old care done;
Your children were in your holy love,
And the precipitation through the bleeding throne.

BISHOP OF ELY:
Marry, and will, my lord, to weep in such a one were prettiest;
Yet now I was adopted heir
Of the world's lamentable day,
To watch the next way with his father with his face?

ESCALUS:
The cause why then we are all resolved more sons.

VOLUMNIA:
O, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, it is no sin it should be dead,
And love and pale as any will to that word.

QUEEN ELIZABETH:
But how long have I heard the soul for this world,
And show his hands of life be proved to stand.

PETRUCHIO:
I say he look'd on, if I must be content
To stay him from the fatal of our country's bliss.
His lordship pluck'd from this sentence then for prey,
And then let us twain, being the moon,
were she such a case as fills m

Chociaż niektóre zdania są gramatyczne, większość z nich nie ma sensu. Model nie nauczył się znaczenia słów, ale rozważ:

  • Model jest oparty na postaci. Kiedy rozpoczął się trening, model nie wiedział, jak przeliterować angielskie słowo lub że słowa były nawet jednostką tekstu.

  • Struktura danych wyjściowych przypomina sztukę - bloki tekstu zwykle rozpoczynają się od nazwiska mówcy, pisanego wielkimi literami, podobnie jak w zestawie danych.

  • Jak pokazano poniżej, model jest szkolony na małych partiach tekstu (po 100 znaków każdy) i nadal jest w stanie wygenerować dłuższą sekwencję tekstu o spójnej strukturze.

Ustawiać

Importuj TensorFlow i inne biblioteki

 import tensorflow as tf

import numpy as np
import os
import time
 

Pobierz zbiór danych Szekspira

Zmień poniższy wiersz, aby uruchomić ten kod na własnych danych.

 path_to_file = tf.keras.utils.get_file('shakespeare.txt', 'https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt')
 
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt
1122304/1115394 [==============================] - 0s 0us/step

Przeczytaj dane

Najpierw spójrz na tekst:

 # Read, then decode for py2 compat.
text = open(path_to_file, 'rb').read().decode(encoding='utf-8')
# length of text is the number of characters in it
print ('Length of text: {} characters'.format(len(text)))
 
Length of text: 1115394 characters

 # Take a look at the first 250 characters in text
print(text[:250])
 
First Citizen:
Before we proceed any further, hear me speak.

All:
Speak, speak.

First Citizen:
You are all resolved rather to die than to famish?

All:
Resolved. resolved.

First Citizen:
First, you know Caius Marcius is chief enemy to the people.


 # The unique characters in the file
vocab = sorted(set(text))
print ('{} unique characters'.format(len(vocab)))
 
65 unique characters

Przetwórz tekst

Wektoryzuj tekst

Przed rozpoczęciem szkolenia musimy odwzorować ciągi znaków na reprezentację liczbową. Utwórz dwie tabele przeglądowe: jedną przypisującą znaki do liczb, a drugą dla liczb do znaków.

 # Creating a mapping from unique characters to indices
char2idx = {u:i for i, u in enumerate(vocab)}
idx2char = np.array(vocab)

text_as_int = np.array([char2idx[c] for c in text])
 

Teraz mamy reprezentację liczb całkowitych dla każdego znaku. Zwróć uwagę, że zamapowaliśmy znak jako indeksy od 0 do len(unique) .

 print('{')
for char,_ in zip(char2idx, range(20)):
    print('  {:4s}: {:3d},'.format(repr(char), char2idx[char]))
print('  ...\n}')
 
{
  '\n':   0,
  ' ' :   1,
  '!' :   2,
  '$' :   3,
  '&' :   4,
  "'" :   5,
  ',' :   6,
  '-' :   7,
  '.' :   8,
  '3' :   9,
  ':' :  10,
  ';' :  11,
  '?' :  12,
  'A' :  13,
  'B' :  14,
  'C' :  15,
  'D' :  16,
  'E' :  17,
  'F' :  18,
  'G' :  19,
  ...
}

 # Show how the first 13 characters from the text are mapped to integers
print ('{} ---- characters mapped to int ---- > {}'.format(repr(text[:13]), text_as_int[:13]))
 
'First Citizen' ---- characters mapped to int ---- > [18 47 56 57 58  1 15 47 58 47 64 43 52]

Zadanie przewidywania

Biorąc pod uwagę znak lub sekwencję znaków, jaki jest najbardziej prawdopodobny następny znak? To jest zadanie, do wykonania którego trenujemy model. Dane wejściowe do modelu będą sekwencją znaków, a my trenujemy model do przewidywania wyniku - następny znak w każdym kroku czasowym.

Ponieważ RNN utrzymują stan wewnętrzny, który zależy od wcześniej widzianych elementów, biorąc pod uwagę wszystkie znaki obliczone do tego momentu, jaki jest następny znak?

Twórz przykłady i cele treningowe

Następnie podziel tekst na przykładowe sekwencje. Każda sekwencja wejściowa będzie zawierała znaki seq_length z tekstu.

Dla każdej sekwencji wejściowej odpowiednie cele zawierają tę samą długość tekstu, z wyjątkiem przesunięcia o jeden znak w prawo.

Więc seq_length+1 tekst na fragmenty o seq_length+1 . Na przykład powiedz, że seq_length to 4, a nasz tekst to „Hello”. Sekwencja wejściowa to „Piekło”, a sekwencja docelowa „ello”.

Aby to zrobić, najpierw użyj funkcji tf.data.Dataset.from_tensor_slices aby przekształcić wektor tekstowy w strumień indeksów znaków.

 # The maximum length sentence we want for a single input in characters
seq_length = 100
examples_per_epoch = len(text)//(seq_length+1)

# Create training examples / targets
char_dataset = tf.data.Dataset.from_tensor_slices(text_as_int)

for i in char_dataset.take(5):
  print(idx2char[i.numpy()])
 
F
i
r
s
t

Metoda batch pozwala nam łatwo konwertować te pojedyncze znaki na sekwencje o pożądanym rozmiarze.

 sequences = char_dataset.batch(seq_length+1, drop_remainder=True)

for item in sequences.take(5):
  print(repr(''.join(idx2char[item.numpy()])))
 
'First Citizen:\nBefore we proceed any further, hear me speak.\n\nAll:\nSpeak, speak.\n\nFirst Citizen:\nYou '
'are all resolved rather to die than to famish?\n\nAll:\nResolved. resolved.\n\nFirst Citizen:\nFirst, you k'
"now Caius Marcius is chief enemy to the people.\n\nAll:\nWe know't, we know't.\n\nFirst Citizen:\nLet us ki"
"ll him, and we'll have corn at our own price.\nIs't a verdict?\n\nAll:\nNo more talking on't; let it be d"
'one: away, away!\n\nSecond Citizen:\nOne word, good citizens.\n\nFirst Citizen:\nWe are accounted poor citi'

Dla każdej sekwencji zduplikuj i przesuń ją, aby utworzyć tekst wejściowy i docelowy, używając metody map , aby zastosować prostą funkcję do każdej partii:

 def split_input_target(chunk):
  input_text = chunk[:-1]
  target_text = chunk[1:]
  return input_text, target_text

dataset = sequences.map(split_input_target)
 

Wydrukuj pierwsze przykłady wartości wejściowych i docelowych:

 for input_example, target_example in  dataset.take(1):
  print ('Input data: ', repr(''.join(idx2char[input_example.numpy()])))
  print ('Target data:', repr(''.join(idx2char[target_example.numpy()])))
 
Input data:  'First Citizen:\nBefore we proceed any further, hear me speak.\n\nAll:\nSpeak, speak.\n\nFirst Citizen:\nYou'
Target data: 'irst Citizen:\nBefore we proceed any further, hear me speak.\n\nAll:\nSpeak, speak.\n\nFirst Citizen:\nYou '

Każdy indeks tych wektorów jest przetwarzany jako jeden krok czasowy. Dla danych wejściowych w kroku czasowym 0 model otrzymuje indeks dla „F” i próbuje przewidzieć indeks dla „i” jako następny znak. W następnym kroku robi to samo, ale RNN pod uwagę kontekst poprzedniego kroku, oprócz bieżącego znaku wejściowego.

 for i, (input_idx, target_idx) in enumerate(zip(input_example[:5], target_example[:5])):
  print("Step {:4d}".format(i))
  print("  input: {} ({:s})".format(input_idx, repr(idx2char[input_idx])))
  print("  expected output: {} ({:s})".format(target_idx, repr(idx2char[target_idx])))
 
Step    0
  input: 18 ('F')
  expected output: 47 ('i')
Step    1
  input: 47 ('i')
  expected output: 56 ('r')
Step    2
  input: 56 ('r')
  expected output: 57 ('s')
Step    3
  input: 57 ('s')
  expected output: 58 ('t')
Step    4
  input: 58 ('t')
  expected output: 1 (' ')

Utwórz paczki szkoleniowe

Użyliśmy tf.data do podzielenia tekstu na możliwe do zarządzania sekwencje. Ale przed wprowadzeniem tych danych do modelu musimy przetasować dane i spakować je w partie.

 # Batch size
BATCH_SIZE = 64

# Buffer size to shuffle the dataset
# (TF data is designed to work with possibly infinite sequences,
# so it doesn't attempt to shuffle the entire sequence in memory. Instead,
# it maintains a buffer in which it shuffles elements).
BUFFER_SIZE = 10000

dataset = dataset.shuffle(BUFFER_SIZE).batch(BATCH_SIZE, drop_remainder=True)

dataset
 
<BatchDataset shapes: ((64, 100), (64, 100)), types: (tf.int64, tf.int64)>

Zbuduj model

Użyj tf.keras.Sequential aby zdefiniować model. W tym prostym przykładzie trzy warstwy są używane do zdefiniowania naszego modelu:

  • tf.keras.layers.Embedding : warstwa wejściowa. Dająca się nauczyć tabela przeglądowa, która będzie mapować liczby każdego znaku do wektora o wymiarach embedding_dim ;
  • tf.keras.layers.GRU : Typ RNN z units=rnn_units rozmiaru units=rnn_units (tutaj można również użyć warstwy LSTM).
  • tf.keras.layers.Dense : warstwa wyjściowa z vocab_size wyjściowymi vocab_size .
 # Length of the vocabulary in chars
vocab_size = len(vocab)

# The embedding dimension
embedding_dim = 256

# Number of RNN units
rnn_units = 1024
 
 def build_model(vocab_size, embedding_dim, rnn_units, batch_size):
  model = tf.keras.Sequential([
    tf.keras.layers.Embedding(vocab_size, embedding_dim,
                              batch_input_shape=[batch_size, None]),
    tf.keras.layers.GRU(rnn_units,
                        return_sequences=True,
                        stateful=True,
                        recurrent_initializer='glorot_uniform'),
    tf.keras.layers.Dense(vocab_size)
  ])
  return model
 
 model = build_model(
    vocab_size = len(vocab),
    embedding_dim=embedding_dim,
    rnn_units=rnn_units,
    batch_size=BATCH_SIZE)
 

Dla każdego znaku model wyszukuje osadzenie, uruchamia GRU o jeden krok w czasie z osadzaniem jako danymi wejściowymi i stosuje gęstą warstwę, aby wygenerować logity przewidujące logiczne prawdopodobieństwo następnego znaku:

Rysunek danych przechodzących przez model

Należy pamiętać, że wybieramy tutaj sekwencyjny model Keras, ponieważ wszystkie warstwy w modelu mają tylko jedno wejście i generują jedno wyjście. W przypadku, gdy chcesz pobrać i ponownie wykorzystać stany ze stanowej warstwy RNN, możesz chcieć zbudować swój model za pomocą funkcjonalnego interfejsu API Keras lub podklasy modelu. Więcej informacji znajdziesz w przewodniku Keras RNN .

Wypróbuj model

Teraz uruchom model, aby zobaczyć, czy zachowuje się zgodnie z oczekiwaniami.

Najpierw sprawdź kształt wyniku:

 for input_example_batch, target_example_batch in dataset.take(1):
  example_batch_predictions = model(input_example_batch)
  print(example_batch_predictions.shape, "# (batch_size, sequence_length, vocab_size)")
 
(64, 100, 65) # (batch_size, sequence_length, vocab_size)

W powyższym przykładzie długość sekwencji wejścia wynosi 100 ale model można uruchomić na wejściach o dowolnej długości:

 model.summary()
 
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (64, None, 256)           16640     
_________________________________________________________________
gru (GRU)                    (64, None, 1024)          3938304   
_________________________________________________________________
dense (Dense)                (64, None, 65)            66625     
=================================================================
Total params: 4,021,569
Trainable params: 4,021,569
Non-trainable params: 0
_________________________________________________________________

Aby uzyskać rzeczywiste prognozy z modelu, musimy pobrać próbkę z rozkładu wyjściowego, aby uzyskać rzeczywiste wskaźniki znaków. Ten rozkład jest definiowany przez logity w słowniku znaków.

Wypróbuj dla pierwszego przykładu w partii:

 sampled_indices = tf.random.categorical(example_batch_predictions[0], num_samples=1)
sampled_indices = tf.squeeze(sampled_indices,axis=-1).numpy()
 

To daje nam, na każdym kroku, prognozę następnego indeksu znaków:

 sampled_indices
 
array([30, 39, 15, 31, 45, 50, 51,  1,  1, 20, 39, 50, 52, 56, 49, 39, 17,
       49, 25, 36, 42, 56, 28, 46, 21, 44, 50, 27, 51, 30,  3, 60, 57,  5,
       33, 13, 11, 33,  1,  4, 10, 33, 10, 27,  7,  6, 19, 46, 33, 48, 22,
       17, 55, 47, 41, 56, 35,  4, 48, 23, 62,  1, 60, 46,  1, 20, 11, 30,
       35, 31, 64, 23, 37, 19, 11, 40, 35,  2, 54, 26,  9, 30, 46, 26, 32,
       35, 18, 56, 31, 54, 15,  4, 36, 12,  6, 47, 24,  3, 53, 47])

Odszyfruj je, aby zobaczyć tekst przewidywany przez ten niewytrenowany model:

 print("Input: \n", repr("".join(idx2char[input_example_batch[0]])))
print()
print("Next Char Predictions: \n", repr("".join(idx2char[sampled_indices ])))
 
Input: 
 "dness! Make not impossible\nThat which but seems unlike: 'tis not impossible\nBut one, the wicked'st c"

Next Char Predictions: 
 "RaCSglm  HalnrkaEkMXdrPhIflOmR$vs'UA;U &:U:O-,GhUjJEqicrW&jKx vh H;RWSzKYG;bW!pN3RhNTWFrSpC&X?,iL$oi"

Wytrenuj model

W tym miejscu problem można potraktować jako standardowy problem klasyfikacyjny. Biorąc pod uwagę poprzedni stan RNN i dane wejściowe w tym przedziale czasowym, przewiduj klasę następnego znaku.

Dołącz optymalizator i funkcję strat

Standardowa tf.keras.losses.sparse_categorical_crossentropy straty tf.keras.losses.sparse_categorical_crossentropy działa w tym przypadku, ponieważ jest stosowana w ostatnim wymiarze prognoz.

Ponieważ nasz model zwraca logity, musimy ustawić flagę from_logits .

 def loss(labels, logits):
  return tf.keras.losses.sparse_categorical_crossentropy(labels, logits, from_logits=True)

example_batch_loss  = loss(target_example_batch, example_batch_predictions)
print("Prediction shape: ", example_batch_predictions.shape, " # (batch_size, sequence_length, vocab_size)")
print("scalar_loss:      ", example_batch_loss.numpy().mean())
 
Prediction shape:  (64, 100, 65)  # (batch_size, sequence_length, vocab_size)
scalar_loss:       4.1742387

Skonfiguruj procedurę uczenia za pomocą metody tf.keras.Model.compile . Użyjemy tf.keras.optimizers.Adam z domyślnymi argumentami i funkcją strat.

 model.compile(optimizer='adam', loss=loss)
 

Skonfiguruj punkty kontrolne

Użyj tf.keras.callbacks.ModelCheckpoint aby upewnić się, że punkty kontrolne są zapisywane podczas treningu:

 # Directory where the checkpoints will be saved
checkpoint_dir = './training_checkpoints'
# Name of the checkpoint files
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt_{epoch}")

checkpoint_callback=tf.keras.callbacks.ModelCheckpoint(
    filepath=checkpoint_prefix,
    save_weights_only=True)
 

Wykonaj szkolenie

Aby zachować rozsądny czas szkolenia, wytrenuj model w 10 epokach. W Colab ustaw czas wykonywania na GPU, aby przyspieszyć trening.

 EPOCHS=10
 
 history = model.fit(dataset, epochs=EPOCHS, callbacks=[checkpoint_callback])
 
Epoch 1/10
172/172 [==============================] - 5s 28ms/step - loss: 2.6593
Epoch 2/10
172/172 [==============================] - 5s 28ms/step - loss: 1.9565
Epoch 3/10
172/172 [==============================] - 5s 27ms/step - loss: 1.6894
Epoch 4/10
172/172 [==============================] - 5s 27ms/step - loss: 1.5419
Epoch 5/10
172/172 [==============================] - 5s 27ms/step - loss: 1.4529
Epoch 6/10
172/172 [==============================] - 5s 28ms/step - loss: 1.3947
Epoch 7/10
172/172 [==============================] - 5s 27ms/step - loss: 1.3486
Epoch 8/10
172/172 [==============================] - 5s 27ms/step - loss: 1.3103
Epoch 9/10
172/172 [==============================] - 5s 27ms/step - loss: 1.2765
Epoch 10/10
172/172 [==============================] - 5s 27ms/step - loss: 1.2437

Generuj tekst

Przywróć ostatni punkt kontrolny

Aby uprościć ten krok prognozy, użyj rozmiaru partii 1.

Ze względu na sposób, w jaki stan RNN jest przekazywany z etapu do etapu czasu, model akceptuje tylko ustalony rozmiar partii po zbudowaniu.

Aby uruchomić model z innym batch_size , musimy przebudować model i przywrócić wagi z punktu kontrolnego.

 tf.train.latest_checkpoint(checkpoint_dir)
 
'./training_checkpoints/ckpt_10'
 model = build_model(vocab_size, embedding_dim, rnn_units, batch_size=1)

model.load_weights(tf.train.latest_checkpoint(checkpoint_dir))

model.build(tf.TensorShape([1, None]))
 
 model.summary()
 
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding_1 (Embedding)      (1, None, 256)            16640     
_________________________________________________________________
gru_1 (GRU)                  (1, None, 1024)           3938304   
_________________________________________________________________
dense_1 (Dense)              (1, None, 65)             66625     
=================================================================
Total params: 4,021,569
Trainable params: 4,021,569
Non-trainable params: 0
_________________________________________________________________

Pętla przewidywania

Poniższy blok kodu generuje tekst:

  • Zaczyna się od wybrania ciągu początkowego, zainicjowania stanu RNN i ustawienia liczby znaków do wygenerowania.

  • Uzyskaj rozkład przewidywania następnego znaku przy użyciu ciągu początkowego i stanu RNN.

  • Następnie użyj rozkładu jakościowego, aby obliczyć indeks przewidywanego znaku. Użyj tego przewidywanego znaku jako naszego następnego wejścia do modelu.

  • Stan RNN zwracany przez model jest zwracany do modelu, dzięki czemu ma teraz więcej kontekstu, a nie tylko jeden znak. Po przewidzeniu następnego znaku, zmodyfikowane stany RNN są ponownie wprowadzane z powrotem do modelu, w ten sposób uczy się, gdy uzyskuje więcej kontekstu z wcześniej przewidywanych znaków.

Aby wygenerować tekst, dane wyjściowe modelu są zwracane na wejście

Patrząc na wygenerowany tekst, zobaczysz, że model wie, kiedy używać wielkich liter, tworzyć akapity i naśladuje szekspirowskie słownictwo. Przy niewielkiej liczbie epok szkoleniowych nie nauczył się jeszcze formułować spójnych zdań.

 def generate_text(model, start_string):
  # Evaluation step (generating text using the learned model)

  # Number of characters to generate
  num_generate = 1000

  # Converting our start string to numbers (vectorizing)
  input_eval = [char2idx[s] for s in start_string]
  input_eval = tf.expand_dims(input_eval, 0)

  # Empty string to store our results
  text_generated = []

  # Low temperatures results in more predictable text.
  # Higher temperatures results in more surprising text.
  # Experiment to find the best setting.
  temperature = 1.0

  # Here batch size == 1
  model.reset_states()
  for i in range(num_generate):
    predictions = model(input_eval)
    # remove the batch dimension
    predictions = tf.squeeze(predictions, 0)

    # using a categorical distribution to predict the character returned by the model
    predictions = predictions / temperature
    predicted_id = tf.random.categorical(predictions, num_samples=1)[-1,0].numpy()

    # We pass the predicted character as the next input to the model
    # along with the previous hidden state
    input_eval = tf.expand_dims([predicted_id], 0)

    text_generated.append(idx2char[predicted_id])

  return (start_string + ''.join(text_generated))
 
 print(generate_text(model, start_string=u"ROMEO: "))
 
ROMEO: wh't for a sooth,--

HENRY BOLAND BRWATER:
Nor name I have Katharina themselves,
effects it in am perditions,
And I will cat you come; good my Lord,
Who be sworn so suiterate garlation?
But I would not call thee! Many there has bestrideen my gentleman too:
I waked, for the const mut of whose note
Lieson with thee: the Volsces that the face of debets
In many I run furry conjure or tread
As that our commons' waxer's wind.

GONZALO:
Thou didst they was ever.

DUKE OF AUMERLE:
Stay, when 'twas my duty, minates, news, browlord,
Scarcellict then long has his times most grief may
Arent with you at oncunation?
Yet, that namer'd hath towardour heartime!
Nor Geere is battle like and that twoing the sword.

COMINIUS:
I'll carried, him in.

GREMIO:
Y she had much
God as 'twere an ill. I'll pings thee
And cet your slave, direcliful there!
O, thy dear keavens and to' no more surse!

Nurse:
Happy Mangel, a pruse is again;
One hooth against me;
That they lives swear having but a fence,
I have fish to 

Najłatwiejszą rzeczą, jaką możesz zrobić, aby poprawić wyniki, jest trenowanie go dłużej (wypróbuj EPOCHS=30 ).

Możesz także eksperymentować z innym ciągiem początkowym lub spróbować dodać kolejną warstwę RNN, aby poprawić dokładność modelu, lub dostosować parametr temperatury, aby generować mniej lub bardziej losowe prognozy.

Zaawansowane: szkolenie dostosowane do potrzeb

Powyższa procedura treningowa jest prosta, ale nie daje dużej kontroli.

Teraz, gdy wiesz, jak ręcznie uruchomić model, rozpakujmy pętlę treningową i zaimplementujmy ją samodzielnie. Daje to punkt wyjścia, na przykład do wdrożenia uczenia się w ramach programu nauczania, aby pomóc ustabilizować wyniki modelu w otwartej pętli.

Będziemy używać tf.GradientTape do śledzenia gradientów. Możesz dowiedzieć się więcej o tym podejściu, czytając przewodnik po chętnym wykonaniu .

Procedura wygląda następująco:

  • Najpierw zresetuj stan RNN. Robimy to, wywołując metodę tf.keras.Model.reset_states .

  • Następnie iteruj po zestawie danych (partia po partii) i oblicz prognozy skojarzone z każdym z nich.

  • Otwórz tf.GradientTape i oblicz prognozy i straty w tym kontekście.

  • Obliczyć gradienty straty w odniesieniu do zmiennych modelu przy użyciu metody tf.GradientTape.grads .

  • Na koniec zrób krok w dół, używając metody tf.train.Optimizer.apply_gradients optymalizatora.

 model = build_model(
    vocab_size = len(vocab),
    embedding_dim=embedding_dim,
    rnn_units=rnn_units,
    batch_size=BATCH_SIZE)
 
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.iter
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.beta_1
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.beta_2
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.decay
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.learning_rate
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer's state 'm' for (root).layer_with_weights-0.embeddings
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer's state 'm' for (root).layer_with_weights-2.kernel
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer's state 'm' for (root).layer_with_weights-2.bias
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer's state 'm' for (root).layer_with_weights-1.cell.kernel
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer's state 'm' for (root).layer_with_weights-1.cell.recurrent_kernel
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer's state 'm' for (root).layer_with_weights-1.cell.bias
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer's state 'v' for (root).layer_with_weights-0.embeddings
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer's state 'v' for (root).layer_with_weights-2.kernel
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer's state 'v' for (root).layer_with_weights-2.bias
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer's state 'v' for (root).layer_with_weights-1.cell.kernel
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer's state 'v' for (root).layer_with_weights-1.cell.recurrent_kernel
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer's state 'v' for (root).layer_with_weights-1.cell.bias
WARNING:tensorflow:A checkpoint was restored (e.g. tf.train.Checkpoint.restore or tf.keras.Model.load_weights) but not all checkpointed values were used. See above for specific issues. Use expect_partial() on the load status object, e.g. tf.train.Checkpoint.restore(...).expect_partial(), to silence these warnings, or use assert_consumed() to make the check explicit. See https://www.tensorflow.org/guide/checkpoint#loading_mechanics for details.

 optimizer = tf.keras.optimizers.Adam()
 
 @tf.function
def train_step(inp, target):
  with tf.GradientTape() as tape:
    predictions = model(inp)
    loss = tf.reduce_mean(
        tf.keras.losses.sparse_categorical_crossentropy(
            target, predictions, from_logits=True))
  grads = tape.gradient(loss, model.trainable_variables)
  optimizer.apply_gradients(zip(grads, model.trainable_variables))

  return loss
 
 # Training step
EPOCHS = 10

for epoch in range(EPOCHS):
  start = time.time()

  # resetting the hidden state at the start of every epoch
  model.reset_states()

  for (batch_n, (inp, target)) in enumerate(dataset):
    loss = train_step(inp, target)

    if batch_n % 100 == 0:
      template = 'Epoch {} Batch {} Loss {}'
      print(template.format(epoch+1, batch_n, loss))

  # saving (checkpoint) the model every 5 epochs
  if (epoch + 1) % 5 == 0:
    model.save_weights(checkpoint_prefix.format(epoch=epoch))

  print ('Epoch {} Loss {:.4f}'.format(epoch+1, loss))
  print ('Time taken for 1 epoch {} sec\n'.format(time.time() - start))

model.save_weights(checkpoint_prefix.format(epoch=epoch))
 
Epoch 1 Batch 0 Loss 4.174392223358154
Epoch 1 Batch 100 Loss 2.3985118865966797
Epoch 1 Loss 2.1551
Time taken for 1 epoch 6.254742622375488 sec

Epoch 2 Batch 0 Loss 2.1428608894348145
Epoch 2 Batch 100 Loss 1.9496537446975708
Epoch 2 Loss 1.7899
Time taken for 1 epoch 5.287492275238037 sec

Epoch 3 Batch 0 Loss 1.7644929885864258
Epoch 3 Batch 100 Loss 1.7042765617370605
Epoch 3 Loss 1.6075
Time taken for 1 epoch 5.316596984863281 sec

Epoch 4 Batch 0 Loss 1.58280348777771
Epoch 4 Batch 100 Loss 1.5163054466247559
Epoch 4 Loss 1.4844
Time taken for 1 epoch 5.294792413711548 sec

Epoch 5 Batch 0 Loss 1.4671127796173096
Epoch 5 Batch 100 Loss 1.4383118152618408
Epoch 5 Loss 1.4392
Time taken for 1 epoch 5.385573148727417 sec

Epoch 6 Batch 0 Loss 1.3468033075332642
Epoch 6 Batch 100 Loss 1.393198847770691
Epoch 6 Loss 1.3746
Time taken for 1 epoch 5.335136413574219 sec

Epoch 7 Batch 0 Loss 1.3691208362579346
Epoch 7 Batch 100 Loss 1.3387356996536255
Epoch 7 Loss 1.3408
Time taken for 1 epoch 5.244983673095703 sec

Epoch 8 Batch 0 Loss 1.3485757112503052
Epoch 8 Batch 100 Loss 1.2911202907562256
Epoch 8 Loss 1.3264
Time taken for 1 epoch 5.2453694343566895 sec

Epoch 9 Batch 0 Loss 1.2468737363815308
Epoch 9 Batch 100 Loss 1.2936309576034546
Epoch 9 Loss 1.2899
Time taken for 1 epoch 5.335190296173096 sec

Epoch 10 Batch 0 Loss 1.2130709886550903
Epoch 10 Batch 100 Loss 1.231929063796997
Epoch 10 Loss 1.2601
Time taken for 1 epoch 5.280482053756714 sec