При использовании разреженной матрицы в качестве входных данных в тензорном потоке 2.0 возникла исключительная ситуация: «Должно быть определено последнее измерение входных данных для« Плотного ». Найдено« Нет ».» - PullRequest
2 голосов
/ 09 января 2020

Я попытался использовать tf.keras.Input для загрузки разреженной матрицы в мою модель и обнаружил, что input_shapes из SparseTensor не может быть автоматически выведен с помощью tenorflow 2.0. Как загрузить данные разреженной матрицы в модель в tenorflow 2.0?

Мой тестовый код:

import scipy as sp
import numpy as np
import pandas as pd
import tensorflow as tf

trainX = sp.sparse.random(586, 64)
trainY = np.array(pd.get_dummies(list(map(int, np.random.uniform(0,9,size=586)))).values, dtype=np.int)

inputs = Input(shape=(trainX.shape[1],), sparse=True)
outputs = Dense(trainY.shape[1], activation='softmax')(inputs)
model = Model(inputs=inputs, outputs=outputs)
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

steps = 10
for i in range(steps):
    print(model.train_on_batch(trainX, trainY))

Трассировка:

ValueError                                Traceback (most recent call last)
<ipython-input-70-3322ddb40fa8> in <module>
      8 
      9 inputs = Input(shape=(trainX.shape[1],), sparse=True)
---> 10 outputs = Dense(trainY.shape[1], activation='softmax')(inputs)
     11 model = Model(inputs=inputs, outputs=outputs)
     12 model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

C:\ProgramData\Anaconda3\lib\site-packages\tensorflow_core\python\keras\engine\base_layer.py in __call__(self, inputs, *args, **kwargs)
    815           # Build layer if applicable (if the `build` method has been
    816           # overridden).
--> 817           self._maybe_build(inputs)
    818           cast_inputs = self._maybe_cast_inputs(inputs)
    819 

C:\ProgramData\Anaconda3\lib\site-packages\tensorflow_core\python\keras\engine\base_layer.py in _maybe_build(self, inputs)
   2139         # operations.
   2140         with tf_utils.maybe_init_scope(self):
-> 2141           self.build(input_shapes)
   2142       # We must set self.built since user defined build functions are not
   2143       # constrained to set self.built.

C:\ProgramData\Anaconda3\lib\site-packages\tensorflow_core\python\keras\layers\core.py in build(self, input_shape)
   1013     input_shape = tensor_shape.TensorShape(input_shape)
   1014     if tensor_shape.dimension_value(input_shape[-1]) is None:
-> 1015       raise ValueError('The last dimension of the inputs to `Dense` '
   1016                        'should be defined. Found `None`.')
   1017     last_dim = tensor_shape.dimension_value(input_shape[-1])

ValueError: The last dimension of the inputs to `Dense` should be defined. Found `None`.

Я также попытался определить input_shapes разреженной матрицы вручную, но получил еще одно исключение. мой тестовый код:

class SparseDense(Layer):
    def __init__(self, input_dim, units, activation=tf.keras.activations.relu, dropout_rate=0.5,
                use_bias=True, l2_reg=0, seed=1024, **kwargs):

        super(SparseDense, self).__init__(**kwargs)
        self.input_dim=input_dim
        self.units = units
        self.use_bias = use_bias
        self.l2_reg = l2_reg
        self.dropout_rate = dropout_rate
        self.activation = activation
        self.seed=seed

    def build(self, input_shapes):

        self.kernel = self.add_weight(shape=(self.input_dim, self.units),
                                     initializer = GlorotUniform(seed=self.seed),
                                     regularizer = l2(self.l2_reg),
                                     name = 'kernel',)
        if self.use_bias:
            self.bias = self.add_weight(shape=(self.units,),
                                        initializer=Zeros(),
                                        name='bias',)
        self.dropout = Dropout(self.dropout_rate)
        self.built=True

    def call(self, inputs, training=None, **kwargs):

        output = tf.sparse.sparse_dense_matmul(tf.dtypes.cast(inputs, dtype=tf.float32), self.kernel)

        if self.use_bias:
            output += self.bias
        act = self.activation(output)

        act._uses_learning_phase = True
        return act

    def get_config(self):
        config = {
            'input_dim':self.input_dim,
            'units': self.units,
            'activation': self.activation,
            'dropout_rate': self.dropout_rate,
            'l2_reg': self.l2_reg,
            'use_bias': self.use_bias,
        }

        base_config = super(SparseDense, self).get_config()
        return dict(list(base_config.items()) + list(config.items())) 

trainX = sp.sparse.random(586, 64)
trainY = np.array(pd.get_dummies(list(map(int, np.random.uniform(0,9,size=586)))).values, dtype=np.int)

inputs = tf.keras.layers.Input(shape=(None,), sparse=True)
outputs = SparseDense(64, 10, activation=tf.keras.activations.softmax)(inputs)
model = Model(inputs=inputs, outputs=outputs)
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

model.train_on_batch(trainX, trainY)

Trackback:

ValueError                                Traceback (most recent call last)
C:\ProgramData\Anaconda3\lib\site-packages\tensorflow_core\python\util\nest.py in assert_same_structure(nest1, nest2, check_types, expand_composites)
    317     _pywrap_tensorflow.AssertSameStructure(nest1, nest2, check_types,
--> 318                                            expand_composites)
    319   except (ValueError, TypeError) as e:

ValueError: The two structures don't have the same nested structure.

First structure: type=SparseTensorSpec str=SparseTensorSpec(TensorShape([586, 64]), tf.float64)

Second structure: type=SparseTensor str=SparseTensor(indices=Tensor("input_28/indices:0", shape=(None, 2), dtype=int64), values=Tensor("input_28/values:0", shape=(None,), dtype=float32), dense_shape=Tensor("input_28/shape:0", shape=(2,), dtype=int64))

More specifically: Incompatible CompositeTensor TypeSpecs: type=SparseTensorSpec str=SparseTensorSpec(TensorShape([586, 64]), tf.float64) vs. type=SparseTensorSpec str=SparseTensorSpec(TensorShape([None, None]), tf.float32)

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
<ipython-input-72-ad3501ab854a> in <module>
      7 model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
      8 
----> 9 model.train_on_batch(trainX, trainY)

C:\ProgramData\Anaconda3\lib\site-packages\tensorflow_core\python\keras\engine\training.py in train_on_batch(self, x, y, sample_weight, class_weight, reset_metrics)
    971       outputs = training_v2_utils.train_on_batch(
    972           self, x, y=y, sample_weight=sample_weight,
--> 973           class_weight=class_weight, reset_metrics=reset_metrics)
    974       outputs = (outputs['total_loss'] + outputs['output_losses'] +
    975                  outputs['metrics'])

C:\ProgramData\Anaconda3\lib\site-packages\tensorflow_core\python\keras\engine\training_v2_utils.py in train_on_batch(model, x, y, sample_weight, class_weight, reset_metrics)
    251   x, y, sample_weights = model._standardize_user_data(
    252       x, y, sample_weight=sample_weight, class_weight=class_weight,
--> 253       extract_tensors_from_dataset=True)
    254   batch_size = array_ops.shape(nest.flatten(x, expand_composites=True)[0])[0]
    255   # If `model._distribution_strategy` is True, then we are in a replica context

C:\ProgramData\Anaconda3\lib\site-packages\tensorflow_core\python\keras\engine\training.py in _standardize_user_data(self, x, y, sample_weight, class_weight, batch_size, check_steps, steps_name, steps, validation_split, shuffle, extract_tensors_from_dataset)
   2495     flat_expected_inputs = nest.flatten(self.inputs, expand_composites=False)
   2496     for (a, b) in zip(flat_inputs, flat_expected_inputs):
-> 2497       nest.assert_same_structure(a, b, expand_composites=True)
   2498 
   2499     if y is not None:

C:\ProgramData\Anaconda3\lib\site-packages\tensorflow_core\python\util\nest.py in assert_same_structure(nest1, nest2, check_types, expand_composites)
    323                   "Entire first structure:\n%s\n"
    324                   "Entire second structure:\n%s"
--> 325                   % (str(e), str1, str2))
    326 
    327 

ValueError: The two structures don't have the same nested structure.

First structure: type=SparseTensorSpec str=SparseTensorSpec(TensorShape([586, 64]), tf.float64)

Second structure: type=SparseTensor str=SparseTensor(indices=Tensor("input_28/indices:0", shape=(None, 2), dtype=int64), values=Tensor("input_28/values:0", shape=(None,), dtype=float32), dense_shape=Tensor("input_28/shape:0", shape=(2,), dtype=int64))

More specifically: Incompatible CompositeTensor TypeSpecs: type=SparseTensorSpec str=SparseTensorSpec(TensorShape([586, 64]), tf.float64) vs. type=SparseTensorSpec str=SparseTensorSpec(TensorShape([None, None]), tf.float32)
Entire first structure:
.
Entire second structure:
.
...