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

Klasyfikacja tekstu z numerem RNN

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

Ten samouczek dotyczący klasyfikacji tekstu szkoli powtarzającą się sieć neuronową w zestawie danych przeglądu dużych filmów IMDB w celu analizy nastrojów.

Ustawiać

pip install -q tfds-nightly
WARNING: You are using pip version 20.2.2; however, version 20.2.3 is available.
You should consider upgrading via the '/tmpfs/src/tf_docs_env/bin/python -m pip install --upgrade pip' command.

import tensorflow_datasets as tfds
import tensorflow as tf

Zaimportuj matplotlib i utwórz funkcję pomocniczą do tworzenia wykresów:

import matplotlib.pyplot as plt

def plot_graphs(history, metric):
  plt.plot(history.history[metric])
  plt.plot(history.history['val_'+metric], '')
  plt.xlabel("Epochs")
  plt.ylabel(metric)
  plt.legend([metric, 'val_'+metric])
  plt.show()

Skonfiguruj potok wejściowy

Duży zbiór danych przeglądów filmów IMDB to binarny zbiór danych klasyfikacji - wszystkie recenzje mają pozytywny lub negatywny nastrój.

Pobierz zestaw danych za pomocą TFDS .

dataset, info = tfds.load('imdb_reviews/subwords8k', with_info=True,
                          as_supervised=True)
train_dataset, test_dataset = dataset['train'], dataset['test']
WARNING:absl:TFDS datasets with text encoding are deprecated and will be removed in a future version. Instead, you should use the plain text version and tokenize the text using `tensorflow_text` (See: https://www.tensorflow.org/tutorials/tensorflow_text/intro#tfdata_example)

Downloading and preparing dataset imdb_reviews/subwords8k/1.0.0 (download: 80.23 MiB, generated: Unknown size, total: 80.23 MiB) to /home/kbuilder/tensorflow_datasets/imdb_reviews/subwords8k/1.0.0...
Shuffling and writing examples to /home/kbuilder/tensorflow_datasets/imdb_reviews/subwords8k/1.0.0.incomplete00IL86/imdb_reviews-train.tfrecord
Shuffling and writing examples to /home/kbuilder/tensorflow_datasets/imdb_reviews/subwords8k/1.0.0.incomplete00IL86/imdb_reviews-test.tfrecord
Shuffling and writing examples to /home/kbuilder/tensorflow_datasets/imdb_reviews/subwords8k/1.0.0.incomplete00IL86/imdb_reviews-unsupervised.tfrecord
Dataset imdb_reviews downloaded and prepared to /home/kbuilder/tensorflow_datasets/imdb_reviews/subwords8k/1.0.0. Subsequent calls will reuse this data.

info zestawie danych obejmują koder ( tfds.deprecated.text.SubwordTextEncoder ).

encoder = info.features['text'].encoder
print('Vocabulary size: {}'.format(encoder.vocab_size))
Vocabulary size: 8185

Ten koder tekstu odwracalnie zakoduje dowolny ciąg, w razie potrzeby powracając do kodowania bajtowego.

sample_string = 'Hello TensorFlow.'

encoded_string = encoder.encode(sample_string)
print('Encoded string is {}'.format(encoded_string))

original_string = encoder.decode(encoded_string)
print('The original string: "{}"'.format(original_string))
Encoded string is [4025, 222, 6307, 2327, 4043, 2120, 7975]
The original string: "Hello TensorFlow."

assert original_string == sample_string
for index in encoded_string:
  print('{} ----> {}'.format(index, encoder.decode([index])))
4025 ----> Hell
222 ----> o 
6307 ----> Ten
2327 ----> sor
4043 ----> Fl
2120 ----> ow
7975 ----> .

Przygotuj dane do treningu

Następnie utwórz partie tych zakodowanych ciągów. Użyj metody padded_batch , aby padded_batch sekwencje do długości najdłuższego ciągu w partii:

BUFFER_SIZE = 10000
BATCH_SIZE = 64
train_dataset = train_dataset.shuffle(BUFFER_SIZE)
train_dataset = train_dataset.padded_batch(BATCH_SIZE)

test_dataset = test_dataset.padded_batch(BATCH_SIZE)

Utwórz model

Zbuduj model tf.keras.Sequential i zacznij od osadzania warstwy. Warstwa osadzająca przechowuje jeden wektor na słowo. Po wywołaniu konwertuje sekwencje indeksów słów na sekwencje wektorów. Te wektory można trenować. Po przeszkoleniu (przy wystarczającej ilości danych) słowa o podobnym znaczeniu często mają podobne wektory.

To wyszukiwanie indeksu jest znacznie bardziej wydajne niż równoważna operacja polegająca na przepuszczaniu jednego zakodowanego wektora przez warstwę tf.keras.layers.Dense .

Cykliczna sieć neuronowa (RNN) przetwarza sekwencję wejściową poprzez iterację przez elementy. RNN przekazują dane wyjściowe z jednego kroku czasowego do swojego wejścia - a następnie do następnego.

tf.keras.layers.Bidirectional może być również używane z warstwą RNN. Powoduje to propagację danych wejściowych do przodu i do tyłu przez warstwę RNN, a następnie konkatenację danych wyjściowych. Pomaga to RNN nauczyć się zależności dalekiego zasięgu.

model = tf.keras.Sequential([
    tf.keras.layers.Embedding(encoder.vocab_size, 64),
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64)),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dense(1)
])

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. Jeśli chcesz użyć stanowej warstwy RNN, możesz chcieć zbudować swój model za pomocą funkcjonalnego interfejsu API Keras lub podklasy modelu, aby móc pobierać i ponownie wykorzystywać stany warstw RNN. Więcej informacji znajdziesz w przewodniku Keras RNN .

Skompiluj model Keras, aby skonfigurować proces szkolenia:

model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              optimizer=tf.keras.optimizers.Adam(1e-4),
              metrics=['accuracy'])

Wytrenuj model

history = model.fit(train_dataset, epochs=10,
                    validation_data=test_dataset, 
                    validation_steps=30)
Epoch 1/10
391/391 [==============================] - 40s 102ms/step - loss: 0.6614 - accuracy: 0.5410 - val_loss: 0.4947 - val_accuracy: 0.7391
Epoch 2/10
391/391 [==============================] - 40s 103ms/step - loss: 0.3468 - accuracy: 0.8479 - val_loss: 0.4052 - val_accuracy: 0.7807
Epoch 3/10
391/391 [==============================] - 40s 101ms/step - loss: 0.2525 - accuracy: 0.9006 - val_loss: 0.3529 - val_accuracy: 0.8646
Epoch 4/10
391/391 [==============================] - 40s 102ms/step - loss: 0.2065 - accuracy: 0.9234 - val_loss: 0.3587 - val_accuracy: 0.8594
Epoch 5/10
391/391 [==============================] - 40s 101ms/step - loss: 0.1843 - accuracy: 0.9335 - val_loss: 0.3372 - val_accuracy: 0.8620
Epoch 6/10
391/391 [==============================] - 40s 102ms/step - loss: 0.1595 - accuracy: 0.9444 - val_loss: 0.3848 - val_accuracy: 0.8635
Epoch 7/10
391/391 [==============================] - 40s 102ms/step - loss: 0.1774 - accuracy: 0.9299 - val_loss: 0.3763 - val_accuracy: 0.8646
Epoch 8/10
391/391 [==============================] - 40s 102ms/step - loss: 0.1321 - accuracy: 0.9567 - val_loss: 0.4385 - val_accuracy: 0.8505
Epoch 9/10
391/391 [==============================] - 40s 103ms/step - loss: 0.1322 - accuracy: 0.9558 - val_loss: 0.3921 - val_accuracy: 0.8313
Epoch 10/10
391/391 [==============================] - 40s 101ms/step - loss: 0.1094 - accuracy: 0.9646 - val_loss: 0.5135 - val_accuracy: 0.8531

test_loss, test_acc = model.evaluate(test_dataset)

print('Test Loss: {}'.format(test_loss))
print('Test Accuracy: {}'.format(test_acc))
391/391 [==============================] - 15s 39ms/step - loss: 0.5083 - accuracy: 0.8549
Test Loss: 0.5083393454551697
Test Accuracy: 0.8549200296401978

Powyższy model nie maskuje wypełnienia zastosowanego do sekwencji. Może to prowadzić do wypaczenia, jeśli trenujesz na sekwencjach z wypełnieniem i testujesz na sekwencjach bez wypełnienia. Najlepiej byłoby użyć maskowania, aby tego uniknąć, ale jak widać poniżej, ma to tylko niewielki wpływ na wynik.

Jeśli prognoza jest> = 0,5, jest dodatnia, w przeciwnym razie jest ujemna.

def pad_to_size(vec, size):
  zeros = [0] * (size - len(vec))
  vec.extend(zeros)
  return vec
def sample_predict(sample_pred_text, pad):
  encoded_sample_pred_text = encoder.encode(sample_pred_text)

  if pad:
    encoded_sample_pred_text = pad_to_size(encoded_sample_pred_text, 64)
  encoded_sample_pred_text = tf.cast(encoded_sample_pred_text, tf.float32)
  predictions = model.predict(tf.expand_dims(encoded_sample_pred_text, 0))

  return (predictions)
# predict on a sample text without padding.

sample_pred_text = ('The movie was cool. The animation and the graphics '
                    'were out of this world. I would recommend this movie.')
predictions = sample_predict(sample_pred_text, pad=False)
print(predictions)
[[0.08747289]]

# predict on a sample text with padding

sample_pred_text = ('The movie was cool. The animation and the graphics '
                    'were out of this world. I would recommend this movie.')
predictions = sample_predict(sample_pred_text, pad=True)
print(predictions)
[[0.19157095]]

plot_graphs(history, 'accuracy')

png

plot_graphs(history, 'loss')

png

Ułóż dwie lub więcej warstw LSTM

Powtarzające się warstwy Keras mają dwa dostępne tryby, które są kontrolowane przez argument konstruktora return_sequences :

  • Zwróć albo pełne sekwencje kolejnych wyników dla każdego kroku czasowego (tensor 3D kształtu (batch_size, timesteps, output_features) ).
  • Zwraca tylko ostatnie dane wyjściowe dla każdej sekwencji wejściowej (tensor 2D kształtu (rozmiar_partii, cechy_wyjściowe)).
model = tf.keras.Sequential([
    tf.keras.layers.Embedding(encoder.vocab_size, 64),
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64,  return_sequences=True)),
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32)),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Dense(1)
])
model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              optimizer=tf.keras.optimizers.Adam(1e-4),
              metrics=['accuracy'])
history = model.fit(train_dataset, epochs=10,
                    validation_data=test_dataset,
                    validation_steps=30)
Epoch 1/10
391/391 [==============================] - 73s 186ms/step - loss: 0.6681 - accuracy: 0.5372 - val_loss: 0.5608 - val_accuracy: 0.6844
Epoch 2/10
391/391 [==============================] - 74s 189ms/step - loss: 0.4212 - accuracy: 0.8224 - val_loss: 0.4064 - val_accuracy: 0.8031
Epoch 3/10
391/391 [==============================] - 74s 189ms/step - loss: 0.3059 - accuracy: 0.8836 - val_loss: 0.3462 - val_accuracy: 0.8615
Epoch 4/10
391/391 [==============================] - 74s 190ms/step - loss: 0.2413 - accuracy: 0.9155 - val_loss: 0.3497 - val_accuracy: 0.8651
Epoch 5/10
391/391 [==============================] - 74s 190ms/step - loss: 0.2055 - accuracy: 0.9325 - val_loss: 0.3601 - val_accuracy: 0.8656
Epoch 6/10
391/391 [==============================] - 74s 189ms/step - loss: 0.1806 - accuracy: 0.9440 - val_loss: 0.4273 - val_accuracy: 0.8589
Epoch 7/10
391/391 [==============================] - 77s 196ms/step - loss: 0.1593 - accuracy: 0.9512 - val_loss: 0.3905 - val_accuracy: 0.8510
Epoch 8/10
391/391 [==============================] - 73s 187ms/step - loss: 0.1469 - accuracy: 0.9567 - val_loss: 0.4291 - val_accuracy: 0.8646
Epoch 9/10
391/391 [==============================] - 73s 186ms/step - loss: 0.1213 - accuracy: 0.9680 - val_loss: 0.4567 - val_accuracy: 0.8615
Epoch 10/10
391/391 [==============================] - 72s 185ms/step - loss: 0.1094 - accuracy: 0.9727 - val_loss: 0.4848 - val_accuracy: 0.8479

test_loss, test_acc = model.evaluate(test_dataset)

print('Test Loss: {}'.format(test_loss))
print('Test Accuracy: {}'.format(test_acc))
391/391 [==============================] - 28s 71ms/step - loss: 0.4853 - accuracy: 0.8448
Test Loss: 0.4852879047393799
Test Accuracy: 0.8448399901390076

# predict on a sample text without padding.

sample_pred_text = ('The movie was not good. The animation and the graphics '
                    'were terrible. I would not recommend this movie.')
predictions = sample_predict(sample_pred_text, pad=False)
print(predictions)
[[-2.1770935]]

# predict on a sample text with padding

sample_pred_text = ('The movie was not good. The animation and the graphics '
                    'were terrible. I would not recommend this movie.')
predictions = sample_predict(sample_pred_text, pad=True)
print(predictions)
[[-3.8198164]]

plot_graphs(history, 'accuracy')

png

plot_graphs(history, 'loss')

png

Sprawdź inne istniejące powtarzające się warstwy, takie jak warstwy GRU .

Jeśli interesuje Cię tworzenie niestandardowych numerów RNN , zobacz przewodnik Keras RNN .