在 Keras/Tensorflow 中使用具有部分形状的 3d 稀疏输入会产生错误

Using 3d sparse input with partial shape in Keras/Tensorflow gives error

我正在尝试创建一个密集的神经网络,我的输入是一个稀疏的 3d 矩阵。当转换为密集矩阵时,形状为 (2, None, n)(其中 n 是许多特征并且是固定的。)当我使用密集输入时,我的 keras 架构工作正常。但是,为了节省内存,我尝试使用稀疏张量作为输入。

这是我的代码

import numpy as np
import tensorflow as tf

input = tf.keras.Input(batch_shape=(2,None,5))
x = tf.keras.layers.Dropout(0.1)(input)
x = tf.keras.layers.Dense(1)(x)

model = tf.keras.models.Model(inputs=[input], outputs=[x])
model.compile(loss='mse')
print(model.summary())

dummy_input = np.random.random((2,10,5))
dummy_sp = tf.sparse.from_dense(dummy_input)

dummy_output= np.random.random((2,10,1))

model.fit(x=dummy_sp, y=dummy_output, epochs=1)

当我使用 x=dummy_input 时,上面的代码工作正常。但是,当我切换到稀疏输入 dummy_sp 时,出现以下错误

Model: "model"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_1 (InputLayer)        [(2, None, 5)]            0

 dropout (Dropout)           (2, None, 5)              0

 dense (Dense)               (2, None, 1)              6

=================================================================
Total params: 6
Trainable params: 6
Non-trainable params: 0
_________________________________________________________________
None
Traceback (most recent call last):
  File "c:\Users9391\OneDrive\Documents\Projects\NP_E-QSI\srcc\test.py", line 17, in <module>
    model.fit(x=dummy_sp, y=dummy_output, epochs=1)
  File "C:\Users9391\Anaconda3\lib\site-packages\keras\utils\traceback_utils.py", line 67, in error_handler
    raise e.with_traceback(filtered_tb) from None
  File "C:\Users9391\Anaconda3\lib\site-packages\tensorflow\python\framework\func_graph.py", line 1147, in autograph_handler
    raise e.ag_error_metadata.to_exception(e)
TypeError: in user code:

    File "C:\Users9391\Anaconda3\lib\site-packages\keras\engine\training.py", line 1021, in train_function  *
        return step_function(self, iterator)
    File "C:\Users9391\Anaconda3\lib\site-packages\keras\engine\training.py", line 1010, in step_function  **
        outputs = model.distribute_strategy.run(run_step, args=(data,))
    File "C:\Users9391\Anaconda3\lib\site-packages\keras\engine\training.py", line 1000, in run_step  **
        outputs = model.train_step(data)
    File "C:\Users9391\Anaconda3\lib\site-packages\keras\engine\training.py", line 859, in train_step
        y_pred = self(x, training=True)
    File "C:\Users9391\Anaconda3\lib\site-packages\keras\utils\traceback_utils.py", line 67, in error_handler
        raise e.with_traceback(filtered_tb) from None

    TypeError: Exception encountered when calling layer "dropout" (type Dropout).

    Failed to convert elements of SparseTensor(indices=Tensor("DeserializeSparse:0", shape=(None, 3), dtype=int64), values=Tensor("model/Cast:0", shape=(None,), dtype=float32), dense_shape=Tensor("stack:0", shape=(3,), dtype=int64)) to Tensor. Consider casting elements to a supported type. See https://www.tensorflow.org/api_docs/python/tf/dtypes for supported TF dtypes.

    Call arguments received:
      • inputs=<tensorflow.python.framework.sparse_tensor.SparseTensor object at 0x000002423CD78E20>
      • training=True

基于tf-documentation,即使sparse参数设置为False,仍然可以传递sparse张量,只要输入数据是稀疏矩阵。

sparse : A boolean specifying whether the placeholder to be created is sparse. Only one of 'ragged' and 'sparse' can be True. Note that, if sparse is False, sparse tensors can still be passed into the input - they will be densified with a default value of 0.

input = tf.keras.Input(batch_shape=(2,None,5), sparse=False)
x = tf.keras.layers.Dropout(0.1)(input)
x = tf.keras.layers.Dense(1)(x)
model = tf.keras.models.Model(inputs=[input], outputs=[x])
print(model.summary())
# OK 

更新

基于下面的评论。

class toDense(keras.layers.Layer):
    def call(self, input):
        if isinstance(input, tf.sparse.SparseTensor):
            return tf.sparse.to_dense(input)
        return input

将其放在上述模型的 Input 之后和 Dropout 层之前。喜欢,

input = tf.keras.Input(batch_shape=(2,None,5))
x = toDense()(input)
x = tf.keras.layers.Dropout(0.1)(x)
...

接下来,你可以做

dummy_input = np.random.random((2,10,5))
dummy_sp = tf.sparse.from_dense(dummy_input)
dummy_output= np.random.random((2,10,1))

model(dummy_sp).shape 
>> TensorShape([2, 10, 1])

model.compile(loss='mse')
model.fit(x=dummy_sp, y=dummy_output, epochs=1)
1/1 [=====] - 0s 416ms/step - loss: 0.2746