据我所知和研究,数据集中的序列可以有不同的长度;我们不需要填充或截断它们,前提是训练过程中的每个批次都包含相同长度的序列。
为了实现和应用它,我决定将批量大小设置为 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是官方代码示例,它可能对您有所帮助。在嵌入层中使用带有掩码的序列填充
根据您的评论和信息,似乎可以使用 可变长度输入序列,检查 this和 this也。但是,我仍然可以说,在大多数情况下,从业者更愿意
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_zero
如 True
,因此,索引 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
引用文献
关于python - 使用循环网络的电影评论分类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66813950/