Tensorflow模型正确拟合格式数据--TypeError:无法将符号Keras输入/输出转换为numpy数组



对于NLP任务,我的输入数据集被转换为如下所示:整数列表。要素和标签是同一个数据集。

>>>training_data = [[    0     4    79  3179    11    44     8     1 11245   173   152    10
1  1138  1079]
[    0     0     4    79  3179    11    44     8 11566   173   152     8
1  1138  1079]
[    0     0     0     0     0     0     0     9    15   333    44     3
61    63   533]
[    0     0     0     0     0     0     3    19   253    28    44     3
61    63   533]
[    0     0     0     0     0     0     0     0     0     0     0     2
3    49  4395]
[    0     0     0     0     0     0     0     0     0     0     0     0
75    65  4395]
[    3     1  7128  3388   289    10   446   200   675     8  3320    14
32    82   234]
[    7    74   268   577    23    49    31     5  1032    98    10  4270
5026    12  6570]
[    0     0     0     0     0     0     0     2     3    39     7    27
155    29  4534]
[    0     0     0     0     0     2     3    19    39     7    27   155
29    34  4534]]

验证数据集是主数据集的摘录,格式相同。

然后我调用fit()方法——我的模型是vae

n_steps = (800000 / 2) / batch_size   
for counter in range(nb_epoch):
print('-------epoch: ',counter,'--------')
vae.fit(x=np.array(training_data),y=np.array(training_data), steps_per_epoch=n_steps,
epochs=1, callbacks=[checkpointer], validation_data=(data_1_val, data_1_val))

它给出了这个错误

TypeError: Cannot convert a symbolic Keras input/output to a numpy array. 
This error may indicate that you're trying to pass a symbolic value to a NumPy call, 
which is not supported. Or, you may be trying to pass Keras symbolic inputs/outputs to 
a TF API that does not register dispatching, preventing Keras from automatically 
converting the API call to a lambda layer in the Functional Model.

我试过

vae.fit(x=training_data,y=training_data, steps_per_epoch=n_steps,
epochs=1, callbacks=[checkpointer], validation_data=(data_1_val, data_1_val))

以及相同的错误。

欢迎使用列表、np.arrays或生成器来提供任何关于如何格式化训练数据的好的解决方案或提示。

编辑:一些代码

training_data = pad_sequences(sequences, maxlen = MAX_SEQUENCE_LENGTH)
len_val = int(np.floor ( len(texts) * 0.2 )) # num samples for validation
data_1_val = data_1[-len_val:] #select len_val sentences as validation data

建立和训练模型

x = Input(batch_shape=(None, max_len))
x_embed = Embedding(NB_WORDS, emb_dim, weights=[glove_embedding_matrix],
input_length=max_len, trainable=False)(x)

[…]

loss_layer = CustomVariationalLayer()([x, x_decoded_mean])
vae = Model(x, [loss_layer])
opt = Adam(lr=0.01) #SGD(lr=1e-2, decay=1e-6, momentum=0.9, nesterov=True)
vae.compile(optimizer='adam', loss=[zero_loss])
nb_epoch = 100
n_steps = (800000 / 2) / batch_size   
for counter in range(nb_epoch):
print('-------epoch: ',counter,'--------')
vae.fit(training_data,training_data, steps_per_epoch=n_steps,
epochs=1, callbacks=[checkpointer], validation_data=(data_1_val, data_1_val))

在最初的github代码中,生成器被用作fit()的输入,在Keras中使用了一种不推荐使用的方法fit_generator

for counter in range(nb_epoch):
print('-------epoch: ',counter,'--------')
vae.fit_generator(sent_generator(TRAIN_DATA_FILE, batch_size/2),
steps_per_epoch=n_steps, epochs=1, callbacks=[checkpointer],
validation_data=(data_1_val, data_1_val))

由于fit()也支持生成器参数,我第一次尝试

for counter in range(nb_epoch):
print('-------epoch: ',counter,'--------')
vae.fit(sent_generator(TRAIN_DATA_FILE, batch_size/2),
steps_per_epoch=n_steps, epochs=1, callbacks=[checkpointer],
validation_data=(data_1_val, data_1_val))

它正在崩溃,具有与上面相同的错误。

问题:

类型错误:无法将符号Keras输入/输出转换为numpy数组
此错误可能表示您正试图通过NumPy调用的符号值,这是不受支持的。或者,你可能试图将Keras符号输入/输出传递给TF API不注册调度,阻止Keras自动地将API调用转换为函数模型中的lambda层。

调查

由于此TypeError的性质,我建议您在禁用急切执行时检查错误代码:

from tensorflow.python.framework.ops import disable_eager_execution 
disable_eager_execution()

您没有错误,但出现以下警告:WARNING:tensorflow:When passing input data as arrays, do not specify steps_per_epoch/steps argument. Please use batch_size instead.

了解问题

我将首先解释这个建议的原因。使用Functional API创建的模型的行为,如果启用了热切的执行,可能看起来相当不可预测。但我们会理解为什么会发生这种情况以及如何修复它

在这里,您可以找到来自KerasSensor类的TypeError:https://github.com/keras-team/keras/blob/4a978914d2298db2c79baa4012af5ceff4a4e203/keras/engine/keras_tensor.py#L244

为什么禁用急切执行似乎可以解决问题:

让我们首先阅读以下引文https://www.tensorflow.org/guide/eager

启用热切执行会改变TensorFlow操作的行为方式——现在它们会立即求值并将值返回给蟒蛇tf.Tensor对象引用具体值,而不是计算图中节点的符号句柄。既然没有一个计算图,可以在会话后期构建和运行,这很容易使用print()或调试器检查结果。评估、打印、,检查张量值不会破坏计算流程梯度。

热切的执行与NumPy配合得很好。NumPy操作接受tf.Tensor参数。TensorFlow tf.math操作转换Python对象和NumPy数组到tf.Tensor对象。tf.Tensor.numpy方法以NumPy ndarray形式返回对象的值。

但是热切的执行应该能很好地与Numpy配合使用,为什么在使用Numpy数组时会出现错误?

Tensorflow的急切执行并没有引发此错误。这个错误是由Keras抛出的,更具体地说是由KerasSensor抛出的。

在模型的Functional API构造期间,创建KerasTensors以表示;符号输入";和输出每个Keras层。你的输入是一个np.ndarray。Keras获取你的数组,并将其放入一个tf.Keras.input`层,生成一个KerasSensor。由于您的模型将尝试将此符号输入/输出转换为np.ndarray.,因此引发错误

但为什么会有这种行为呢?

在急切执行tf.Tensor objects reference concrete values instead of symbolic handles to nodes in a computational graph.时记住因此,急切的执行将尝试从KerasSensor中获得一个具体的值,该值将抛出此错误TypeError: Cannot convert a symbolic Keras input/output to a numpy array.

禁用急切执行时,您永远不会尝试从KerasSensor中获取具体值,并且永远不会抛出此错误。

如果你想更好地了解你的功能模型内部发生了什么,请阅读KerasSensor类的这2句话:

KerasTensor传递给tf.keras.Layer__call__使层知道您正在构建一个功能模型。图层__call__将推断输出签名并返回KerasTensors,其中tf.TypeSpecs对应于该签名的符号输出层调用。这些输出KerasTensor将具有Keras需要附加的内部KerasHistory元数据构建一个功能模型。当前,层推断输出签名者:
*创建一个暂存FuncGraph
**在暂存图中制作与输入类型规范匹配的占位符
*在这些占位符上调用layer.call
**在清除暂存图之前提取输出的签名

如果将KerasTensor传递给支持调度的TFneneneba API,Keras将自动将API调用转换为函数模型,并返回表示
符号输出的KerasSensor。

建议的解决方案:

禁用急切执行不是一个令人满意的解决方案。

我建议您尝试使用tf.data.Dataset类将training_data转换为数据集,或者在model.fit之前使用tf.Tensor类将其转换为张量。

此外,如果问题仍未解决,如果您能够提供一些代码来重现错误,这将有所帮助。

最新更新