python - 使用循环网络的电影评论分类

标签 python tensorflow keras deep-learning recurrent-neural-network

据我所知和研究,数据集中的序列可以有不同的长度;我们不需要填充或截断它们,前提是训练过程中的每个批次都包含相同长度的序列。
为了实现和应用它,我决定将批量大小设置为 1,并在 IMDB 电影分类数据集上训练我的 RNN 模型。我添加了我在下面编写的代码。

import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras.datasets import imdb
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import SimpleRNN
from tensorflow.keras.layers import Embedding

max_features = 10000
batch_size = 1

(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features)

model = Sequential()
model.add(Embedding(input_dim=10000, output_dim=32))
model.add(SimpleRNN(units=32, input_shape=(None, 32)))
model.add(Dense(1, activation="sigmoid"))
model.compile(optimizer="rmsprop", 
                  loss="binary_crossentropy", metrics=["acc"])

history = model.fit(x_train, y_train, 
                     batch_size=batch_size, epochs=10, 
                     validation_split=0.2)
acc = history.history["acc"]
loss = history.history["loss"]
val_acc = history.history["val_acc"]
val_loss = history.history["val_loss"]

epochs = range(len(acc) + 1)
plt.plot(epochs, acc, "bo", label="Training Acc")
plt.plot(epochs, val_acc, "b", label="Validation Acc")
plt.title("Training and Validation Accuracy")
plt.legend()
plt.figure()
plt.plot(epochs, loss, "bo", label="Training Loss")
plt.plot(epochs, val_loss, "b", label="Validation Loss")
plt.title("Training and Validation Loss")
plt.legend()
plt.show()
我遇到的错误是由于输入numpy数组中的列表组件而无法将输入转换为张量格式。但是,当我更改它们时,我继续遇到类似的错误。
错误信息:
ValueError: Failed to convert a NumPy array to a Tensor (Unsupported object type list).
我无法处理这个问题。在这一点上有人可以帮助我吗?

最佳答案

使用序列填充
有两个问题。您需要使用 pad_sequences首先在文本序列上。而且也没有这样的参数 input_shape SimpleRNN .尝试使用以下代码:

max_features = 20000  # Only consider the top 20k words
maxlen = 200  # Only consider the first 200 words of each movie review
batch_size = 1

(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features)
print(len(x_train), "Training sequences")
print(len(x_test), "Validation sequences")
x_train = tf.keras.preprocessing.sequence.pad_sequences(x_train, maxlen=maxlen)
x_test = tf.keras.preprocessing.sequence.pad_sequences(x_test, maxlen=maxlen)


model = Sequential()
model.add(Embedding(input_dim=max_features, output_dim=32))
model.add(SimpleRNN(units=32))
model.add(Dense(1, activation="sigmoid"))

model.compile(optimizer="rmsprop", loss="binary_crossentropy", metrics=["acc"])
history = model.fit(x_train, y_train, batch_size=batch_size, 
                         epochs=10, validation_split=0.2)
Here是官方代码示例,它可能对您有所帮助。

在嵌入层中使用带有掩码的序列填充
根据您的评论和信息,似乎可以使用 可变长度输入序列,检查 thisthis也。但是,我仍然可以说,在大多数情况下,从业者更愿意pad均匀长度的序列;因为它有说服力。选择非均匀或可变的输入序列长度是某种特殊情况;类似于我们想要视觉模型的可变输入图像大小。
但是,在这里我们将添加有关 padding 的信息。以及我们如何才能mask训练时间中的填充值,这在技术上似乎是可变长度的输入训练。希望能说服你。我们先来了解一下pad_sequences做。通常在序列数据中,很常见的情况是,每个训练样本的长度不同。让我们考虑以下输入:
raw_inputs = [
    [711, 632, 71],
    [73, 8, 3215, 55, 927],
    [83, 91, 1, 645, 1253, 927],
]
这 3 个训练样本的长度不同,分别为 3、5 和 6。我们接下来要做的是通过添加一些值(通常是 0-1 )使它们的长度都相等——无论是在序列的开头还是结尾。
tf.keras.preprocessing.sequence.pad_sequences(
    raw_inputs, maxlen=6, dtype="int32", padding="pre", value=0.0
)

array([[   0,    0,    0,  711,  632,   71],
       [   0,   73,    8, 3215,   55,  927],
       [  83,   91,    1,  645, 1253,  927]], dtype=int32)
我们可以设置padding = "post"在序列末尾设置填充值。但它建议使用 "post"使用 RNN 时的填充层以便能够使用 CuDNN层的实现。但是,仅供引用,您可能会注意到我们设置了 maxlen = 6这是最高的输入序列长度。但它不必是最高的输入序列长度,因为如果数据集变大,它的计算成本可能会很高。我们可以将其设置为 5假设我们的模型可以在这个长度内学习特征表示,它是一种超参数。这带来了另一个参数 truncating .
tf.keras.preprocessing.sequence.pad_sequences(
    raw_inputs, maxlen=5, dtype="int32", padding="pre", truncating="pre", value=0.0
)

array([[   0,    0,  711,  632,   71],
       [  73,    8, 3215,   55,  927],
       [  91,    1,  645, 1253,  927]], dtype=int32
好的,现在我们有一个填充的输入序列,所有输入都是统一的长度。现在,我们可以mask在训练时间内去掉那些额外的填充值。我们会告诉模型数据的某些部分是填充的,这些应该被忽略。该机制是 遮蔽 .所以,这是告诉 的一种方式序列处理输入中某些时间步长缺失的层,因此在处理数据时应跳过。引入输入的三种方式口罩Keras楷模:
  • 添加 keras. layers.Masking layer .
  • 配置一个 keras.layers.Embedding层与 mask_zero=True .
  • 在调用支持此参数的图层时手动传递掩码参数(例如 RNN 图层)。

  • 这里我们只通过配置Embedding来展示层。它有一个名为 mask_zero 的参数并设置 False默认情况下。如果我们设置它 True然后 0包含序列中的索引将被跳过。 False entry表示对应的timestep应该是处理过程中被忽略 .
    padd_input = tf.keras.preprocessing.sequence.pad_sequences(
        raw_inputs, maxlen=6, dtype="int32", padding="pre", value=0.0
    )
    print(padd_input)
    
    embedding = tf.keras.layers.Embedding(input_dim=5000, output_dim=16, mask_zero=True)
    masked_output = embedding(padd_input)
    print(masked_output._keras_mask)
    
    [[   0    0    0  711  632   71]
     [   0   73    8 3215   55  927]
     [  83   91    1  645 1253  927]]
    
    tf.Tensor(
    [[False False False  True  True  True]
     [False  True  True  True  True  True]
     [ True  True  True  True  True  True]], shape=(3, 6), dtype=bool)
    
    这是它在类 Embedding(Layer) 中的计算方式.
      def compute_mask(self, inputs, mask=None):
        if not self.mask_zero:
          return None
    
        return tf.not_equal(inputs, 0)
    
    这是一个问题,如果我们设置 mask_zeroTrue ,因此,索引 0不能用在词汇中。根据文档

    mask_zero: Boolean, whether or not the input value 0 is a special "padding" value that should be masked out. This is useful when using recurrent layers which may take variable length input. If this is True, then all subsequent layers in the model need to support masking or an exception will be raised. If mask_zero is set to True, as a consequence, index 0 cannot be used in the vocabulary (input_dim should equal size of vocabulary + 1).


    所以,我们必须使用 max_features + 1至少。 Here是一个很好的解释。

    这是使用这些代码的完整示例。
    # get the data 
    (x_train, y_train), (_, _) = imdb.load_data(num_words=max_features)
    print(x_train.shape)
    
    # check highest sequence lenght 
    max_list_length = lambda list: max( [len(i) for i in list])
    print(max_list_idx(x_train))
    
    max_features = 20000  # Only consider the top 20k words
    maxlen = 350  # Only consider the first 350 words out of `max_list_idx(x_train)`
    batch_size = 512
    
    print('Length ', len(x_train[0]), x_train[0])
    print('Length ', len(x_train[1]), x_train[1])
    print('Length ', len(x_train[2]), x_train[2])
    
    # (1). padding with value 0 at the end of the sequence - padding="post", value=0.
    # (2). truncate 'maxlen' words 
    # out of `max_list_idx(x_train)` at the end - maxlen=maxlen, truncating="post"
    x_train = tf.keras.preprocessing.sequence.pad_sequences(x_train, 
                                      maxlen=maxlen, dtype="int32", 
                                      padding="post", truncating="post", 
                                      value=0.)
    
    print('Length ', len(x_train[0]), x_train[0])
    print('Length ', len(x_train[1]), x_train[1])
    print('Length ', len(x_train[2]), x_train[2])
    
    您的模型定义现在应该是
    model = Sequential()
    model.add(Embedding(
               input_dim=max_features + 1,
               output_dim=32, 
               mask_zero=True))
    model.add(SimpleRNN(units=32))
    model.add(Dense(1, activation="sigmoid"))
    
    model.compile(optimizer="rmsprop", loss="binary_crossentropy", metrics=["acc"])
    history = model.fit(x_train, y_train, 
                        batch_size=256, 
                        epochs=1, validation_split=0.2)
    
    639ms/step - loss: 0.6774 - acc: 0.5640 - val_loss: 0.5034 - val_acc: 0.8036
    

    引用文献
  • Masking and padding with Keras
  • Embedding layer , - Pads sequences
  • Recurrent Neural Networks (RNN) with Keras
  • 关于python - 使用循环网络的电影评论分类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66813950/

    相关文章:

    python - 创建不带类的列表或字典的新实例

    python - Tensorflow:如何使用dynamic_rnn从LSTMCell获取中间细胞状态(c)?

    python - Tensorflow - 训练期间的 Nan 成本值 - 尝试了通常的修复但没有成功

    python - 如何处理 Keras 中超长的卷积序列内存大小?

    python - 在多个 h5 文件上训练 ANN Keras(基于 Tensorflow)模型

    python - 如何从另一个文件(在另一个文件夹中)包含类 - python

    python - 如何使用 Pandas Dataframe 重复滚动减法

    python - 在 pygame 中翻转 Sprite

    python - 与 tensorflow keras 的自定义损失混淆

    python - 如何判断哪个 Keras 模型更好?