Aide à protéger la Grande barrière de corail avec tensorflow sur Kaggle Rejoignez Défi

Génération de texte avec un RNN

Voir sur TensorFlow.org Exécuter dans Google Colab Voir la source sur GitHub Télécharger le cahier

Ce didacticiel montre comment générer du texte à l'aide d'un RNN basé sur des caractères. Vous travaillerez avec un ensemble de données de l'écriture de Shakespeare de Andrej Karpathy L'efficacité de Unreasonable récurrentes des réseaux de neurones . Étant donné une séquence de caractères à partir de ces données ("Shakespear"), entraînez un modèle pour prédire le caractère suivant dans la séquence ("e"). Des séquences de texte plus longues peuvent être générées en appelant le modèle à plusieurs reprises.

Ce tutoriel inclut le code exécutable implémenté en utilisant tf.keras et exécution avide . Ce qui suit est l'exemple de sortie lorsque le modèle de ce didacticiel s'est entraîné pendant 30 époques et a démarré avec l'invite « 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

Alors que certaines phrases sont grammaticales, la plupart n'ont pas de sens. Le modèle n'a pas appris le sens des mots, mais considérez :

  • Le modèle est basé sur les personnages. Lorsque la formation a commencé, le modèle ne savait pas comment épeler un mot anglais, ou ces mots étaient même une unité de texte.

  • La structure de la sortie ressemble à une pièce de théâtre : les blocs de texte commencent généralement par un nom de locuteur, en lettres majuscules similaires à l'ensemble de données.

  • Comme démontré ci-dessous, le modèle est entraîné sur de petits lots de texte (100 caractères chacun) et est toujours capable de générer une séquence de texte plus longue avec une structure cohérente.

Installer

Importer TensorFlow et d'autres bibliothèques

import tensorflow as tf

import numpy as np
import os
import time

Télécharger l'ensemble de données Shakespeare

Modifiez la ligne suivante pour exécuter ce code sur vos propres données.

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
1130496/1115394 [==============================] - 0s 0us/step

Lire les données

Tout d'abord, regardez dans le texte :

# 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(f'Length of text: {len(text)} characters')
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(f'{len(vocab)} unique characters')
65 unique characters

Traiter le texte

Vectoriser le texte

Avant l'entraînement, vous devez convertir les chaînes en une représentation numérique.

La tf.keras.layers.StringLookup couche peut convertir chaque caractère en un identifiant numérique. Il suffit que le texte soit d'abord divisé en jetons.

example_texts = ['abcdefg', 'xyz']

chars = tf.strings.unicode_split(example_texts, input_encoding='UTF-8')
chars
<tf.RaggedTensor [[b'a', b'b', b'c', b'd', b'e', b'f', b'g'], [b'x', b'y', b'z']]>

Maintenant , créez la tf.keras.layers.StringLookup couche:

ids_from_chars = tf.keras.layers.StringLookup(
    vocabulary=list(vocab), mask_token=None)

Il convertit les jetons de formulaire en identifiants de personnage :

ids = ids_from_chars(chars)
ids
<tf.RaggedTensor [[40, 41, 42, 43, 44, 45, 46], [63, 64, 65]]>

Le but de ce tutoriel étant de générer du texte, il sera également important d'inverser cette représentation et d'en récupérer des chaînes lisibles par l'homme. Pour cela , vous pouvez utiliser tf.keras.layers.StringLookup(..., invert=True) .

chars_from_ids = tf.keras.layers.StringLookup(
    vocabulary=ids_from_chars.get_vocabulary(), invert=True, mask_token=None)

Cette couche récupère les caractères des vecteurs d'ID, et retourne eux comme un tf.RaggedTensor de caractères:

chars = chars_from_ids(ids)
chars
<tf.RaggedTensor [[b'a', b'b', b'c', b'd', b'e', b'f', b'g'], [b'x', b'y', b'z']]>

Vous pouvez tf.strings.reduce_join pour rejoindre les personnages de nouveau dans les chaînes.

tf.strings.reduce_join(chars, axis=-1).numpy()
array([b'abcdefg', b'xyz'], dtype=object)
def text_from_ids(ids):
  return tf.strings.reduce_join(chars_from_ids(ids), axis=-1)

La tâche de prédiction

Étant donné un caractère ou une séquence de caractères, quel est le prochain caractère le plus probable ? Il s'agit de la tâche pour laquelle vous entraînez le modèle. L'entrée du modèle sera une séquence de caractères, et vous entraînez le modèle pour prédire la sortie, le caractère suivant à chaque pas de temps.

Puisque les RNN maintiennent un état interne qui dépend des éléments vus précédemment, étant donné tous les caractères calculés jusqu'à ce moment, quel est le prochain caractère ?

Créer des exemples et des objectifs de formation

Divisez ensuite le texte en séquences d'exemples. Chaque séquence d'entrée contiendra seq_length caractères du texte.

Pour chaque séquence d'entrée, les cibles correspondantes contiennent la même longueur de texte, à l'exception d'un caractère décalé vers la droite.

, PORTER le texte en morceaux de seq_length+1 . Par exemple, disons seq_length est 4 et notre texte est « Bonjour ». La séquence d'entrée serait « Hell » et la séquence cible « ello ».

Pour ce faire , la première utilisation tf.data.Dataset.from_tensor_slices fonction pour convertir le vecteur de texte en un flux d'indices de caractère.

all_ids = ids_from_chars(tf.strings.unicode_split(text, 'UTF-8'))
all_ids
<tf.Tensor: shape=(1115394,), dtype=int64, numpy=array([19, 48, 57, ..., 46,  9,  1])>
ids_dataset = tf.data.Dataset.from_tensor_slices(all_ids)
for ids in ids_dataset.take(10):
    print(chars_from_ids(ids).numpy().decode('utf-8'))
F
i
r
s
t
 
C
i
t
i
seq_length = 100
examples_per_epoch = len(text)//(seq_length+1)

Le batch méthode vous permet de convertir facilement ces caractères individuels à des séquences de la taille désirée.

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

for seq in sequences.take(1):
  print(chars_from_ids(seq))
tf.Tensor(
[b'F' b'i' b'r' b's' b't' b' ' b'C' b'i' b't' b'i' b'z' b'e' b'n' b':'
 b'\n' b'B' b'e' b'f' b'o' b'r' b'e' b' ' b'w' b'e' b' ' b'p' b'r' b'o'
 b'c' b'e' b'e' b'd' b' ' b'a' b'n' b'y' b' ' b'f' b'u' b'r' b't' b'h'
 b'e' b'r' b',' b' ' b'h' b'e' b'a' b'r' b' ' b'm' b'e' b' ' b's' b'p'
 b'e' b'a' b'k' b'.' b'\n' b'\n' b'A' b'l' b'l' b':' b'\n' b'S' b'p' b'e'
 b'a' b'k' b',' b' ' b's' b'p' b'e' b'a' b'k' b'.' b'\n' b'\n' b'F' b'i'
 b'r' b's' b't' b' ' b'C' b'i' b't' b'i' b'z' b'e' b'n' b':' b'\n' b'Y'
 b'o' b'u' b' '], shape=(101,), dtype=string)

Il est plus facile de voir ce que cela fait si vous joignez les jetons en chaînes :

for seq in sequences.take(5):
  print(text_from_ids(seq).numpy())
b'First Citizen:\nBefore we proceed any further, hear me speak.\n\nAll:\nSpeak, speak.\n\nFirst Citizen:\nYou '
b'are all resolved rather to die than to famish?\n\nAll:\nResolved. resolved.\n\nFirst Citizen:\nFirst, you k'
b"now Caius Marcius is chief enemy to the people.\n\nAll:\nWe know't, we know't.\n\nFirst Citizen:\nLet us ki"
b"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"
b'one: away, away!\n\nSecond Citizen:\nOne word, good citizens.\n\nFirst Citizen:\nWe are accounted poor citi'

Pour la formation que vous aurez besoin d' un ensemble de données (input, label) paires. Lorsque l' input et l' label sont des séquences. A chaque pas de temps, l'entrée est le caractère courant et l'étiquette est le caractère suivant.

Voici une fonction qui prend une séquence en entrée, la duplique et la décale pour aligner l'entrée et l'étiquette pour chaque pas de temps :

def split_input_target(sequence):
    input_text = sequence[:-1]
    target_text = sequence[1:]
    return input_text, target_text
split_input_target(list("Tensorflow"))
(['T', 'e', 'n', 's', 'o', 'r', 'f', 'l', 'o'],
 ['e', 'n', 's', 'o', 'r', 'f', 'l', 'o', 'w'])
dataset = sequences.map(split_input_target)
for input_example, target_example in dataset.take(1):
    print("Input :", text_from_ids(input_example).numpy())
    print("Target:", text_from_ids(target_example).numpy())
Input : b'First Citizen:\nBefore we proceed any further, hear me speak.\n\nAll:\nSpeak, speak.\n\nFirst Citizen:\nYou'
Target: b'irst Citizen:\nBefore we proceed any further, hear me speak.\n\nAll:\nSpeak, speak.\n\nFirst Citizen:\nYou '

Créer des lots de formation

Vous avez utilisé tf.data de scinder le texte en séquences faciles à gérer. Mais avant d'introduire ces données dans le modèle, vous devez mélanger les données et les regrouper en lots.

# 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)
    .prefetch(tf.data.experimental.AUTOTUNE))

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

Construire le modèle

Cette section définit le modèle comme keras.Model sous - classe (Pour plus de détails voir faire de nouveaux calques et modèles via le sous - classement ).

Ce modèle comporte trois couches :

  • tf.keras.layers.Embedding : la couche d'entrée. Une table trainable de recherche qui tracera chaque caractère ID à un vecteur avec embedding_dim dimensions;
  • tf.keras.layers.GRU : Un type de RNN avec la taille des units=rnn_units (Vous pouvez également utiliser une couche LSTM ici.)
  • tf.keras.layers.Dense : la couche de sortie, avec vocab_size sorties. Il génère un logit pour chaque caractère du vocabulaire. Ce sont les log-vraisemblances de chaque caractère selon le modèle.
# Length of the vocabulary in chars
vocab_size = len(vocab)

# The embedding dimension
embedding_dim = 256

# Number of RNN units
rnn_units = 1024
class MyModel(tf.keras.Model):
  def __init__(self, vocab_size, embedding_dim, rnn_units):
    super().__init__(self)
    self.embedding = tf.keras.layers.Embedding(vocab_size, embedding_dim)
    self.gru = tf.keras.layers.GRU(rnn_units,
                                   return_sequences=True,
                                   return_state=True)
    self.dense = tf.keras.layers.Dense(vocab_size)

  def call(self, inputs, states=None, return_state=False, training=False):
    x = inputs
    x = self.embedding(x, training=training)
    if states is None:
      states = self.gru.get_initial_state(x)
    x, states = self.gru(x, initial_state=states, training=training)
    x = self.dense(x, training=training)

    if return_state:
      return x, states
    else:
      return x
model = MyModel(
    # Be sure the vocabulary size matches the `StringLookup` layers.
    vocab_size=len(ids_from_chars.get_vocabulary()),
    embedding_dim=embedding_dim,
    rnn_units=rnn_units)

Pour chaque caractère, le modèle recherche l'intégration, exécute le GRU un pas de temps avec l'intégration en entrée et applique la couche dense pour générer des logits prédisant la probabilité de log du prochain caractère :

Un dessin des données passant par le modèle

Essayez le modèle

Exécutez maintenant le modèle pour voir qu'il se comporte comme prévu.

Vérifiez d'abord la forme de la sortie :

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, 66) # (batch_size, sequence_length, vocab_size)

Dans l'exemple ci - dessus la longueur de séquence de l'entrée est de 100 , mais le modèle peut être exécuté sur des données de longueur quelconque:

model.summary()
Model: "my_model"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 embedding (Embedding)       multiple                  16896     
                                                                 
 gru (GRU)                   multiple                  3938304   
                                                                 
 dense (Dense)               multiple                  67650     
                                                                 
=================================================================
Total params: 4,022,850
Trainable params: 4,022,850
Non-trainable params: 0
_________________________________________________________________

Pour obtenir des prédictions réelles à partir du modèle, vous devez échantillonner à partir de la distribution de sortie, pour obtenir des indices de caractères réels. Cette distribution est définie par les logits sur le vocabulaire des caractères.

Essayez-le pour le premier exemple du lot :

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

Cela nous donne, à chaque pas de temps, une prédiction du prochain indice de caractère :

sampled_indices
array([ 6, 52, 24, 12, 28, 62,  4, 36, 29,  3, 50, 14, 49, 26, 58, 40,  0,
       36,  5, 31, 55, 60, 47, 53, 64, 24, 46,  2,  4,  7, 40, 12, 40, 39,
       57, 21, 46, 38, 44, 26, 45, 53, 25, 39,  3, 24, 59, 44, 26, 60, 45,
       24,  6, 61,  8,  9,  3, 19, 25, 15, 19, 38, 24, 16, 24, 64, 21,  0,
       18, 65, 52,  7,  9, 49, 17, 37, 23, 62, 33, 43, 19, 24, 25, 37,  9,
       38, 56, 33,  8, 46,  9, 18, 21, 11, 11, 27,  7, 51, 14, 50])

Décodez-les pour voir le texte prédit par ce modèle non entraîné :

print("Input:\n", text_from_ids(input_example_batch[0]).numpy())
print()
print("Next Char Predictions:\n", text_from_ids(sampled_indices).numpy())
Input:
 b" kinsman! O sweet Juliet,\nThy beauty hath made me effeminate\nAnd in my temper soften'd valour's stee"

Next Char Predictions:
 b"'mK;Ow\\(WP!kAjMsa[UNK]W&RpuhnyKg \\),a;aZrHgYeMfnLZ!KteMufK'v-.!FLBFYKCKyH[UNK]Ezm,.jDXJwTdFKLX.YqT-g.EH::N,lAk"

Former le modèle

À ce stade, le problème peut être traité comme un problème de classification standard. Étant donné l'état RNN précédent et l'entrée de ce pas de temps, prédisez la classe du caractère suivant.

Attachez un optimiseur et une fonction de perte

La norme tf.keras.losses.sparse_categorical_crossentropy fonction de perte fonctionne dans ce cas parce qu'il est appliqué dans la dernière dimension des prédictions.

Parce que votre modèle retourne logits, vous devez définir le from_logits drapeau.

loss = tf.losses.SparseCategoricalCrossentropy(from_logits=True)
example_batch_loss = loss(target_example_batch, example_batch_predictions)
mean_loss = example_batch_loss.numpy().mean()
print("Prediction shape: ", example_batch_predictions.shape, " # (batch_size, sequence_length, vocab_size)")
print("Mean loss:        ", mean_loss)
Prediction shape:  (64, 100, 66)  # (batch_size, sequence_length, vocab_size)
Mean loss:         4.190459

Un modèle nouvellement initialisé ne doit pas être trop sûr de lui-même, les logits de sortie doivent tous avoir des amplitudes similaires. Pour le confirmer, vous pouvez vérifier que l'exponentielle de la perte moyenne est approximativement égale à la taille du vocabulaire. Une perte beaucoup plus élevée signifie que le modèle est sûr de ses mauvaises réponses, et est mal initialisé :

tf.exp(mean_loss).numpy()
66.053085

Configurer la procédure de formation en utilisant la tf.keras.Model.compile méthode. Utilisez tf.keras.optimizers.Adam avec des arguments par défaut et la fonction de perte.

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

Configurer les points de contrôle

Utilisez un tf.keras.callbacks.ModelCheckpoint pour veiller à ce que les points de contrôle sont enregistrés lors de la formation:

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

Exécuter la formation

Pour que le temps d'entraînement reste raisonnable, utilisez 10 époques pour entraîner le modèle. Dans Colab, définissez le temps d'exécution sur GPU pour un entraînement plus rapide.

EPOCHS = 20
history = model.fit(dataset, epochs=EPOCHS, callbacks=[checkpoint_callback])
Epoch 1/20
172/172 [==============================] - 7s 25ms/step - loss: 2.6892
Epoch 2/20
172/172 [==============================] - 5s 25ms/step - loss: 1.9741
Epoch 3/20
172/172 [==============================] - 5s 24ms/step - loss: 1.6954
Epoch 4/20
172/172 [==============================] - 5s 25ms/step - loss: 1.5369
Epoch 5/20
172/172 [==============================] - 5s 25ms/step - loss: 1.4420
Epoch 6/20
172/172 [==============================] - 5s 25ms/step - loss: 1.3770
Epoch 7/20
172/172 [==============================] - 6s 24ms/step - loss: 1.3244
Epoch 8/20
172/172 [==============================] - 5s 24ms/step - loss: 1.2801
Epoch 9/20
172/172 [==============================] - 5s 24ms/step - loss: 1.2400
Epoch 10/20
172/172 [==============================] - 5s 24ms/step - loss: 1.2015
Epoch 11/20
172/172 [==============================] - 5s 24ms/step - loss: 1.1627
Epoch 12/20
172/172 [==============================] - 6s 25ms/step - loss: 1.1211
Epoch 13/20
172/172 [==============================] - 5s 25ms/step - loss: 1.0782
Epoch 14/20
172/172 [==============================] - 5s 25ms/step - loss: 1.0337
Epoch 15/20
172/172 [==============================] - 5s 25ms/step - loss: 0.9863
Epoch 16/20
172/172 [==============================] - 5s 24ms/step - loss: 0.9360
Epoch 17/20
172/172 [==============================] - 5s 24ms/step - loss: 0.8843
Epoch 18/20
172/172 [==============================] - 5s 24ms/step - loss: 0.8319
Epoch 19/20
172/172 [==============================] - 5s 24ms/step - loss: 0.7807
Epoch 20/20
172/172 [==============================] - 5s 24ms/step - loss: 0.7334

Générer du texte

Le moyen le plus simple de générer du texte avec ce modèle est de l'exécuter en boucle et de garder une trace de l'état interne du modèle au fur et à mesure que vous l'exécutez.

Pour générer du texte, la sortie du modèle est renvoyée à l'entrée

Chaque fois que vous appelez le modèle, vous transmettez du texte et un état interne. Le modèle renvoie une prédiction pour le caractère suivant et son nouvel état. Retransmettez la prédiction et l'état pour continuer à générer du texte.

Ce qui suit fait une prédiction en une seule étape :

class OneStep(tf.keras.Model):
  def __init__(self, model, chars_from_ids, ids_from_chars, temperature=1.0):
    super().__init__()
    self.temperature = temperature
    self.model = model
    self.chars_from_ids = chars_from_ids
    self.ids_from_chars = ids_from_chars

    # Create a mask to prevent "[UNK]" from being generated.
    skip_ids = self.ids_from_chars(['[UNK]'])[:, None]
    sparse_mask = tf.SparseTensor(
        # Put a -inf at each bad index.
        values=[-float('inf')]*len(skip_ids),
        indices=skip_ids,
        # Match the shape to the vocabulary
        dense_shape=[len(ids_from_chars.get_vocabulary())])
    self.prediction_mask = tf.sparse.to_dense(sparse_mask)

  @tf.function
  def generate_one_step(self, inputs, states=None):
    # Convert strings to token IDs.
    input_chars = tf.strings.unicode_split(inputs, 'UTF-8')
    input_ids = self.ids_from_chars(input_chars).to_tensor()

    # Run the model.
    # predicted_logits.shape is [batch, char, next_char_logits]
    predicted_logits, states = self.model(inputs=input_ids, states=states,
                                          return_state=True)
    # Only use the last prediction.
    predicted_logits = predicted_logits[:, -1, :]
    predicted_logits = predicted_logits/self.temperature
    # Apply the prediction mask: prevent "[UNK]" from being generated.
    predicted_logits = predicted_logits + self.prediction_mask

    # Sample the output logits to generate token IDs.
    predicted_ids = tf.random.categorical(predicted_logits, num_samples=1)
    predicted_ids = tf.squeeze(predicted_ids, axis=-1)

    # Convert from token ids to characters
    predicted_chars = self.chars_from_ids(predicted_ids)

    # Return the characters and model state.
    return predicted_chars, states
one_step_model = OneStep(model, chars_from_ids, ids_from_chars)

Exécutez-le en boucle pour générer du texte. En regardant le texte généré, vous verrez que le modèle sait quand capitaliser, faire des paragraphes et imiter un vocabulaire d'écriture semblable à celui de Shakespeare. Avec le petit nombre d'époques d'entraînement, il n'a pas encore appris à former des phrases cohérentes.

start = time.time()
states = None
next_char = tf.constant(['ROMEO:'])
result = [next_char]

for n in range(1000):
  next_char, states = one_step_model.generate_one_step(next_char, states=states)
  result.append(next_char)

result = tf.strings.join(result)
end = time.time()
print(result[0].numpy().decode('utf-8'), '\n\n' + '_'*80)
print('\nRun time:', end - start)
ROMEO:
I am comfort; and it must retter you must fled.

WARWICK:
O excell the great gold times of kings,
The other strive thou seest am I, how does! Is remain
A' reckon'd in his breason should be hurt
To hide his country are man's, who stand allow.

SEBASTIAN:
His womb:
Most likewit, canst curn me to the duke?

CAMILLO:
Nicanne! can her he is common from my shield. Which raiment, when,
Manglence their voices that have fled from him,
Tell out the fire o' the strict people glass'd
My will be aspared and health of woe;
Please your scorns and young affections,
And for frost but kill watch his child.

AUTOLYCUS:
But I believe you? leven, and drip and bring it tree.
Is Richard no more of thee: their hearts as she were,
This neighbour airy conscience and notes,
Always that not in my throat, and have all very slain;
And every tree his life, so second children,
I heard their weap; when we it cannot choose
Come bohemios that must make me should
To end them. Who wanted saint--
Being cambred Barnardine  

________________________________________________________________________________

Run time: 2.4680824279785156

La chose la plus facile que vous pouvez faire pour améliorer les résultats est de former pour plus (essayez EPOCHS = 30 ).

Vous pouvez également expérimenter avec une chaîne de départ différente, essayer d'ajouter une autre couche RNN pour améliorer la précision du modèle ou ajuster le paramètre de température pour générer des prédictions plus ou moins aléatoires.

Si vous voulez que le modèle pour générer du texte plus rapidement la meilleure chose que vous pouvez faire est batch la génération de texte. Dans l'exemple ci-dessous, le modèle génère 5 sorties à peu près en même temps qu'il a fallu pour générer 1 ci-dessus.

start = time.time()
states = None
next_char = tf.constant(['ROMEO:', 'ROMEO:', 'ROMEO:', 'ROMEO:', 'ROMEO:'])
result = [next_char]

for n in range(1000):
  next_char, states = one_step_model.generate_one_step(next_char, states=states)
  result.append(next_char)

result = tf.strings.join(result)
end = time.time()
print(result, '\n\n' + '_'*80)
print('\nRun time:', end - start)
tf.Tensor(
[b"ROMEO:\nTake her before, sir! The glass learned will serve: for a word,\nIs praise hath been by marriage, and these\nwounds that know thy will not certain of fastiny:\nGo, poor soul: I will be here to be gone.\n\nKING RICHARD III:\nConfess, reason! the languages of my loving liege!\nThou bloody quarther of thy back! so, farewell, frear\nApother's flesh and freence: so that ever\nHeeps he use if the people's eyes at heaven.\nCoursh thyself ha? little hours lie.\nThere speaks before some behold infection as I cannither\nTo strift the right of blood and senten'd fury; and be it should\nnot trial of it and rotten on thy winds.\nDeath, that same him, it strange to the Romans longing.\nNow, Abouts and mannor,\nEmpanish'd and spurn up wat,'t mad,\nDaughter Grey, come.\n\nDUKE VINCENTIO:\nNor I.\n\nSecond Senator:\nThe next way to him and Master Catesby,\nStops! may, their awe,--who noise is grown sor: 'she hours,\nCan this be kept of any infirm the canst thou canst wepper with the city\nIf, from my heart wepting, tent thee h"
 b"ROMEO:\nThe queen on hers! Clarence, till the king\nShall have said with the Lady Romeo's gianing.\n\nQUEEN:\nThen show she wanders to reproan.\n\nMIRANDA:\nBecause sit way but I fear, sir?\n\nPROSPERO:\nThou dost show me; and thou art not bitter out of fount:\nCome, but affare his plaints, for better there,\nOr waith, and they say, he spreak of socking Chidator,\nAnd he she speak of dock, knee where.'\nThis out for Kenarchment of this fair queen,\nNo, noble uncle. What, surstitualed than one file! Why dost not look us suret\nTo hard and kindly heart my queen of very sir,\nDo is scarce curses no further to be married;\nNot reverse the apply frown and cover all revolt;\nNor need and charm thou that again, mine in't is shield. Were I not, sir:\nI shall perfume it as a pratess; and\nshortly strive more of thine. He should not let me hear\nIt soon I come at the open of the inefall.\nAnd then I'll vold the silent crown\nThat we will also beat them, now arms must ease.\nWhat, hast thou finest at noble steed, and is\nThe nob"
 b"ROMEO:\n\nJULIET:\n'Tis time thou thy arm'd lord, that good itself,\nOur cold to minister of force and we behold the king is,\nNow appear it shall be more coy the heavens, and thy ancient gentleman\nWhich is no planet, nothing Hastings have\nWast smined a holpy of jest of a fire;\nOne thing, by thee, if not put the last,\nHer whipe as heaven fears me not he's good;\nWho lips, with thoughts can yield me seemer's store;\nFor no henge bragling forth and bashful king,\nAnd make his face sourness growing herein,\nAnd fled before the wall. Give me thy year\nIs look'd upon my kindness calleth hand: O raved\nWhere we'll descend no violent\nHath discredited that the most mal of straight: corrupt oursill me\nFriar Penerous art and unrest.\n\nCORIOLANUS:\nPray, fair son, and happy be thy name;\nIn chamber, Kate, colmed their abuse, which should\nbe placed in his friends than the albshate confound;\nThe knave in absence with your night.\n\nPRINCE EDWARD:\nA cuck, brave men all at once!\n\nNurse:\nThis answer to love thee! never lea"
 b"ROMEO:\nThe news with you? Return of all, I seek to us,\nAnd tell false Edward, King Edward's lips again\nTo Rome's discontentood: for I may live in stamp,\nWithout with a sign, a month about you!\nConsent by, nay, if thou dost, I Pereit that:\nGood queen, played into a slaguabour, are it is.\n\nAUTOLYCUS:\nO cause! why dost thou show me go along,\nFor I have made thy Edward had she known to France.\n\nKING RICHARD II:\nWe will be truched, shall we heard\nfrom you the day to thee a woman's face.\n\nEMILIA:\nMasters, hap the lies!\n\nSecond Watchman:\nHere's no as foolish term is the meal. Take happy sense.\nCousin of Buckingham, and Saint George Stanley's in hell!\nThe reason where he hath seen them move,\nAnd cowardly ones two of their houses, holding twine,\nAnd pluck'd on us women on the meater that gieds,\nYou shall tridul in the chamber, only in thy back!\nWilt thou respect the senseless vengeance of my father:\nThou has the case of these of his sivery.\n\nDUKE VINCENTIO:\nI'll hate; Richard infanctime their infyirm"
 b"ROMEO:\nThe loss of your imperiment spider, make whate'er stopping\nAttend an old tale man of sovereignty.\nNow Sister Barnardine! what a shame to king?\nWere he shall silen in my mildier maiderly as he\nshould Roman's faith in this, for it enchange\nMust him allow it. Speak; for I am sure, then I'll do you for\nthe world report the state of spirit, and go\nWitch! for she let that make that scarce choose\nComes reason all the due of all.\nThe immoran properly embraced, and\nat our enmmity to thine antium!\nThis blows appear, comfort: when my thoughts shall poison, years\nMuming him our souls must elder you: he is,\nWhen inducts might be asleeping for his life:\nMore strange daughters will help you to yourself.\nThe celvatain stayf in heavenly lance\nI cannot be behells, revive my standing he\nwhere I but craft of store pair'd with lie.\n\nProvost:\nWithin this fair converse is much better expence.\n\nANGELO:\nPlantagenet impeason with his grace flamed majesty\nAids, by the match, just die I like this hisble: we\nbeho"], shape=(5,), dtype=string) 

________________________________________________________________________________

Run time: 2.4250411987304688

Exporter le générateur

Ce modèle unique étape peut facilement être sauvegardé et restauré , ce qui vous permet de l' utiliser partout où une tf.saved_model est acceptée.

tf.saved_model.save(one_step_model, 'one_step')
one_step_reloaded = tf.saved_model.load('one_step')
WARNING:tensorflow:Skipping full serialization of Keras layer <__main__.OneStep object at 0x7f785c577a90>, because it is not built.
2021-11-30 12:39:22.505061: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
WARNING:absl:Found untraced functions such as gru_cell_layer_call_fn, gru_cell_layer_call_and_return_conditional_losses, gru_cell_layer_call_fn, gru_cell_layer_call_and_return_conditional_losses, gru_cell_layer_call_and_return_conditional_losses while saving (showing 5 of 5). These functions will not be directly callable after loading.
INFO:tensorflow:Assets written to: one_step/assets
INFO:tensorflow:Assets written to: one_step/assets
states = None
next_char = tf.constant(['ROMEO:'])
result = [next_char]

for n in range(100):
  next_char, states = one_step_reloaded.generate_one_step(next_char, states=states)
  result.append(next_char)

print(tf.strings.join(result)[0].numpy().decode("utf-8"))
ROMEO:
Happiness he comes! by awe? I would not let-
Mutus meebly bear them for the free destroying thee:
I

Avancé : Formation personnalisée

La procédure de formation ci-dessus est simple, mais ne vous donne pas beaucoup de contrôle. Il utilise le forçage par l'enseignant qui empêche les mauvaises prédictions d'être réinjectées dans le modèle, de sorte que le modèle n'apprend jamais à se remettre des erreurs.

Alors maintenant que vous avez vu comment exécuter le modèle manuellement, vous allez ensuite implémenter la boucle d'entraînement. Cela donne un point de départ si, par exemple, vous voulez mettre en œuvre l' apprentissage des programmes pour aider à stabiliser la sortie en boucle ouverte du modèle.

La partie la plus importante d'une boucle d'entraînement personnalisée est la fonction de pas d'entraînement.

Utilisez tf.GradientTape pour suivre les gradients. Vous pouvez en apprendre davantage sur cette approche en lisant le guide d'exécution avide .

La procédure de base est :

  1. Exécutez le modèle et le calcul de la perte sous un tf.GradientTape .
  2. Calculez les mises à jour et appliquez-les au modèle à l'aide de l'optimiseur.
class CustomTraining(MyModel):
  @tf.function
  def train_step(self, inputs):
      inputs, labels = inputs
      with tf.GradientTape() as tape:
          predictions = self(inputs, training=True)
          loss = self.loss(labels, predictions)
      grads = tape.gradient(loss, model.trainable_variables)
      self.optimizer.apply_gradients(zip(grads, model.trainable_variables))

      return {'loss': loss}

La mise en œuvre au- dessus de la train_step méthode suit de KERAS train_step conventions . Cette option est facultative, mais il vous permet de modifier le comportement de l'étape de train et utiliser encore de KERAS Model.compile et Model.fit méthodes.

model = CustomTraining(
    vocab_size=len(ids_from_chars.get_vocabulary()),
    embedding_dim=embedding_dim,
    rnn_units=rnn_units)
model.compile(optimizer = tf.keras.optimizers.Adam(),
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True))
model.fit(dataset, epochs=1)
172/172 [==============================] - 7s 24ms/step - loss: 2.7157
<keras.callbacks.History at 0x7f784c347d10>

Ou si vous avez besoin de plus de contrôle, vous pouvez écrire votre propre boucle d'entraînement personnalisée complète :

EPOCHS = 10

mean = tf.metrics.Mean()

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

    mean.reset_states()
    for (batch_n, (inp, target)) in enumerate(dataset):
        logs = model.train_step([inp, target])
        mean.update_state(logs['loss'])

        if batch_n % 50 == 0:
            template = f"Epoch {epoch+1} Batch {batch_n} Loss {logs['loss']:.4f}"
            print(template)

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

    print()
    print(f'Epoch {epoch+1} Loss: {mean.result().numpy():.4f}')
    print(f'Time taken for 1 epoch {time.time() - start:.2f} sec')
    print("_"*80)

model.save_weights(checkpoint_prefix.format(epoch=epoch))
Epoch 1 Batch 0 Loss 2.1894
Epoch 1 Batch 50 Loss 2.0428
Epoch 1 Batch 100 Loss 1.9478
Epoch 1 Batch 150 Loss 1.8134

Epoch 1 Loss: 1.9878
Time taken for 1 epoch 5.99 sec
________________________________________________________________________________
Epoch 2 Batch 0 Loss 1.8471
Epoch 2 Batch 50 Loss 1.7652
Epoch 2 Batch 100 Loss 1.6805
Epoch 2 Batch 150 Loss 1.6089

Epoch 2 Loss: 1.7063
Time taken for 1 epoch 5.22 sec
________________________________________________________________________________
Epoch 3 Batch 0 Loss 1.5877
Epoch 3 Batch 50 Loss 1.5644
Epoch 3 Batch 100 Loss 1.6012
Epoch 3 Batch 150 Loss 1.5249

Epoch 3 Loss: 1.5441
Time taken for 1 epoch 5.39 sec
________________________________________________________________________________
Epoch 4 Batch 0 Loss 1.4675
Epoch 4 Batch 50 Loss 1.3992
Epoch 4 Batch 100 Loss 1.4202
Epoch 4 Batch 150 Loss 1.4764

Epoch 4 Loss: 1.4450
Time taken for 1 epoch 5.19 sec
________________________________________________________________________________
Epoch 5 Batch 0 Loss 1.3906
Epoch 5 Batch 50 Loss 1.3484
Epoch 5 Batch 100 Loss 1.3649
Epoch 5 Batch 150 Loss 1.3644

Epoch 5 Loss: 1.3776
Time taken for 1 epoch 5.48 sec
________________________________________________________________________________
Epoch 6 Batch 0 Loss 1.2946
Epoch 6 Batch 50 Loss 1.3350
Epoch 6 Batch 100 Loss 1.2798
Epoch 6 Batch 150 Loss 1.3575

Epoch 6 Loss: 1.3250
Time taken for 1 epoch 5.31 sec
________________________________________________________________________________
Epoch 7 Batch 0 Loss 1.1956
Epoch 7 Batch 50 Loss 1.2781
Epoch 7 Batch 100 Loss 1.2646
Epoch 7 Batch 150 Loss 1.3028

Epoch 7 Loss: 1.2797
Time taken for 1 epoch 5.43 sec
________________________________________________________________________________
Epoch 8 Batch 0 Loss 1.2646
Epoch 8 Batch 50 Loss 1.2904
Epoch 8 Batch 100 Loss 1.2497
Epoch 8 Batch 150 Loss 1.2201

Epoch 8 Loss: 1.2387
Time taken for 1 epoch 5.45 sec
________________________________________________________________________________
Epoch 9 Batch 0 Loss 1.1981
Epoch 9 Batch 50 Loss 1.1663
Epoch 9 Batch 100 Loss 1.2200
Epoch 9 Batch 150 Loss 1.1986

Epoch 9 Loss: 1.1983
Time taken for 1 epoch 5.25 sec
________________________________________________________________________________
Epoch 10 Batch 0 Loss 1.1464
Epoch 10 Batch 50 Loss 1.1448
Epoch 10 Batch 100 Loss 1.1566
Epoch 10 Batch 150 Loss 1.1913

Epoch 10 Loss: 1.1587
Time taken for 1 epoch 5.44 sec
________________________________________________________________________________