1. 使用RNN对文本进行分类实践:电影评论 (tensorflow2.0官方教程翻译)
    1. 1. 设置输入管道
    2. 2. 创建模型
    3. 3. 训练模型
    4. 4. 堆叠两个或更多LSTM层

使用RNN对文本进行分类实践:电影评论 (tensorflow2.0官方教程翻译)

本教程在IMDB大型影评数据集 上训练一个循环神经网络进行情感分类。

from __future__ import absolute_import, division, print_function, unicode_literals

# !pip install tensorflow-gpu==2.0.0-alpha0
import tensorflow_datasets as tfds
import tensorflow as tf

导入matplotlib并创建一个辅助函数来绘制图形

import matplotlib.pyplot as plt


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

1. 设置输入管道

IMDB大型电影影评数据集是一个二元分类数据集,所有评论都有正面或负面的情绪标签。

使用TFDS下载数据集,数据集附带一个内置的子字标记器

dataset, info = tfds.load('imdb_reviews/subwords8k', with_info=True,
                          as_supervised=True)
train_dataset, test_dataset = dataset['train'], dataset['test']

由于这是一个子字标记器,它可以传递任何字符串,并且标记器将对其进行标记。

tokenizer = info.features['text'].encoder

print ('Vocabulary size: {}'.format(tokenizer.vocab_size))
      Vocabulary size: 8185
sample_string = 'TensorFlow is cool.'

tokenized_string = tokenizer.encode(sample_string)
print ('Tokenized string is {}'.format(tokenized_string))

original_string = tokenizer.decode(tokenized_string)
print ('The original string: {}'.format(original_string))

assert original_string == sample_string
      Tokenized string is [6307, 2327, 4043, 4265, 9, 2724, 7975]
      The original string: TensorFlow is cool.

如果字符串不在字典中,则标记生成器通过将字符串分解为子字符串来对字符串进行编码。

for ts in tokenized_string:
  print ('{} ----> {}'.format(ts, tokenizer.decode([ts])))
    6307 ----> Ten
    2327 ----> sor
    4043 ----> Fl
    4265 ----> ow
    9 ----> is
    2724 ----> cool
    7975 ----> .
BUFFER_SIZE = 10000
BATCH_SIZE = 64

train_dataset = train_dataset.shuffle(BUFFER_SIZE)
train_dataset = train_dataset.padded_batch(BATCH_SIZE, train_dataset.output_shapes)

test_dataset = test_dataset.padded_batch(BATCH_SIZE, test_dataset.output_shapes)

2. 创建模型

构建一个tf.keras.Sequential模型并从嵌入层开始,嵌入层每个字存储一个向量,当被调用时,它将单词索引的序列转换为向量序列,这些向量是可训练的,在训练之后(在足够的数据上),具有相似含义的词通常具有相似的向量。

这种索引查找比通过tf.keras.layers.Dense层传递独热编码向量的等效操作更有效。

递归神经网络(RNN)通过迭代元素来处理序列输入,RNN将输出从一个时间步传递到其输入端,然后传递到下一个时间步。

tf.keras.layers.Bidirectional包装器也可以与RNN层一起使用。这通过RNN层向前和向后传播输入,然后连接输出。这有助于RNN学习远程依赖性。

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

# 编译Keras模型以配置训练过程:
model.compile(loss='binary_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])

3. 训练模型

history = model.fit(train_dataset, epochs=10,
                    validation_data=test_dataset)
      ...
      Epoch 10/10
      391/391 [==============================] - 70s 180ms/step - loss: 0.3074 - accuracy: 0.8692 - val_loss: 0.5533 - val_accuracy: 0.7873
test_loss, test_acc = model.evaluate(test_dataset)

print('Test Loss: {}'.format(test_loss))
print('Test Accuracy: {}'.format(test_acc))
          391/Unknown - 19s 47ms/step - loss: 0.5533 - accuracy: 0.7873Test Loss: 0.553319326714
      Test Accuracy: 0.787320017815

上面的模型没有屏蔽应用于序列的填充。如果我们对填充序列进行训练,并对未填充序列进行测试,就会导致偏斜。理想情况下,模型应该学会忽略填充,但是正如您在下面看到的,它对输出的影响确实很小。

如果预测 >=0.5,则为正,否则为负。

def pad_to_size(vec, size):
  zeros = [0] * (size - len(vec))
  vec.extend(zeros)
  return vec

def sample_predict(sentence, pad):
  tokenized_sample_pred_text = tokenizer.encode(sample_pred_text)

  if pad:
    tokenized_sample_pred_text = pad_to_size(tokenized_sample_pred_text, 64)

  predictions = model.predict(tf.expand_dims(tokenized_sample_pred_text, 0))

  return (predictions)
# 对不带填充的示例文本进行预测 

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.68914342]]
# 对带填充的示例文本进行预测 

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.68634349]]
plot_graphs(history, 'accuracy')

png

plot_graphs(history, 'loss')

png

4. 堆叠两个或更多LSTM层

Keras递归层有两种可以用的模式,由return_sequences构造函数参数控制:

  • 返回每个时间步的连续输出的完整序列(3D张量形状 (batch_size, timesteps, output_features))。

  • 仅返回每个输入序列的最后一个输出(2D张量形状 (batch_size, output_features))。

model = tf.keras.Sequential([
    tf.keras.layers.Embedding(tokenizer.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.Dense(1, activation='sigmoid')
])

model.compile(loss='binary_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])

history = model.fit(train_dataset, epochs=10,
                    validation_data=test_dataset)
      ...
      Epoch 10/10
      391/391 [==============================] - 154s 394ms/step - loss: 0.1120 - accuracy: 0.9643 - val_loss: 0.5646 - val_accuracy: 0.8070
test_loss, test_acc = model.evaluate(test_dataset)

print('Test Loss: {}'.format(test_loss))
print('Test Accuracy: {}'.format(test_acc))
            391/Unknown - 45s 115ms/step - loss: 0.5646 - accuracy: 0.8070Test Loss: 0.564571284348
        Test Accuracy: 0.80703997612
# 在没有填充的情况下预测示例文本

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)
       [[ 0.00393916]]
# 在有填充的情况下预测示例文本

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)
      [[ 0.01098633]]
plot_graphs(history, 'accuracy')

png

plot_graphs(history, 'loss')

png

查看其它现有的递归层,例如GRU层

最新版本:https://www.mashangxue123.com/tensorflow/tf2-tutorials-text-text_classification_rnn.html
英文版本:https://tensorflow.google.cn/beta/tutorials/text/text_classification_rnn
翻译建议PR:https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/text/text_classification_rnn.md


技术交流学习,请加QQ微信:631531977
目录