Tensorflow 2.1 с Керасом - InvalidArgumentError - PullRequest
0 голосов
/ 10 марта 2020

Я уже построил модель для своей рекомендательной системы, используя собственный Tensorflow 1.15, и теперь переносу весь исходный код в Tensorflow 2.1 с использованием Keras API, поскольку это рекомендуется в официальной документации Tensorflow и может облегчить мою жизнь для дальнейшего развития.

До сих пор я довольно много боролся с совместимостью между Keras и разреженной матрицей / тензором. Я должен использовать разреженный тензор, потому что мои данные слишком велики, чтобы их можно было обрабатывать с использованием нормальных плотных матриц.

Может кто-нибудь помочь мне объяснить, почему я получаю разное поведение между этими двумя кодами? Почему Tensorflow просит меня ввести значение в график, который я еще не запустил?

Вход 1:

user_inputs = tf.keras.layers.Input(
    name="user_sparse_inputs",
    shape=(10,),
    dtype=tf.float32,
    sparse=True,
    batch_size=6,
)
print(user_inputs.shape)

user_repr = SparseEmbedding(n_components=5, name_suffix="emb")(user_inputs)
print(user_repr.shape)

model = tf.keras.models.Model(inputs=user_inputs, outputs=user_repr)
model.compile(optimizer='adam', loss='mse', metrics=['mse', 'mae'])
print(model.summary())

Выход 1:

(6, 10)
(6, 5)
Model: "model_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
user_sparse_inputs (InputLay [(6, 10)]                 0         
_________________________________________________________________
sparse_embedding_2 (SparseEm (6, 5)                    50        
=================================================================
Total params: 50
Trainable params: 50
Non-trainable params: 0
_________________________________________________________________
None

Вход 2:

user_inputs = tf.keras.layers.Input(
    name="user_sparse_inputs",
    shape=(6,10),
    dtype=tf.float32,
    sparse=True,
    batch_size=1,
)
print(user_inputs.shape)
user_inputs_reshape = tf.sparse.reshape(user_inputs, [6, 10])
print(user_inputs_reshape.shape)

user_repr = SparseEmbedding(n_components=5, name_suffix="emb")
y = user_repr(user_inputs_reshape)
print(y.shape)

model = tf.keras.models.Model(inputs=user_inputs, outputs=y)
model.compile(optimizer='adam', loss='mse', metrics=['mse', 'mae'])
print(model.summary())

Выход 2:

(1, 6, 10)
(6, 10)
(6, 5)
---------------------------------------------------------------------------
InvalidArgumentError                      Traceback (most recent call last)
<ipython-input-6-81b2fd61efeb> in <module>
     14 print(y.shape)
     15 
---> 16 model = tf.keras.models.Model(inputs=user_inputs, outputs=y)
     17 model.compile(optimizer='adam', loss='mse', metrics=['mse', 'mae'])
     18 print(model.summary())

~/.local/share/virtualenvs/perx-data-ml-wBZaki4L/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/training.py in __init__(self, *args, **kwargs)
    144 
    145   def __init__(self, *args, **kwargs):
--> 146     super(Model, self).__init__(*args, **kwargs)
    147     _keras_api_gauge.get_cell('model').set(True)
    148     # initializing _distribution_strategy here since it is possible to call

~/.local/share/virtualenvs/perx-data-ml-wBZaki4L/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/network.py in __init__(self, *args, **kwargs)
    167         'inputs' in kwargs and 'outputs' in kwargs):
    168       # Graph network
--> 169       self._init_graph_network(*args, **kwargs)
    170     else:
    171       # Subclassed network

~/.local/share/virtualenvs/perx-data-ml-wBZaki4L/lib/python3.7/site-packages/tensorflow_core/python/training/tracking/base.py in _method_wrapper(self, *args, **kwargs)
    455     self._self_setattr_tracking = False  # pylint: disable=protected-access
    456     try:
--> 457       result = method(self, *args, **kwargs)
    458     finally:
    459       self._self_setattr_tracking = previous_value  # pylint: disable=protected-access

~/.local/share/virtualenvs/perx-data-ml-wBZaki4L/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/network.py in _init_graph_network(self, inputs, outputs, name, **kwargs)
    270 
    271     if any(not hasattr(tensor, '_keras_history') for tensor in self.outputs):
--> 272       base_layer_utils.create_keras_history(self._nested_outputs)
    273 
    274     self._base_init(name=name, **kwargs)

~/.local/share/virtualenvs/perx-data-ml-wBZaki4L/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/base_layer_utils.py in create_keras_history(tensors)
    185     keras_tensors: The Tensors found that came from a Keras Layer.
    186   """
--> 187   _, created_layers = _create_keras_history_helper(tensors, set(), [])
    188   return created_layers
    189 

~/.local/share/virtualenvs/perx-data-ml-wBZaki4L/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/base_layer_utils.py in _create_keras_history_helper(tensors, processed_ops, created_layers)
    245           else:
    246             with ops.init_scope():
--> 247               constants[i] = backend.function([], op_input)([])
    248       processed_ops, created_layers = _create_keras_history_helper(
    249           layer_inputs, processed_ops, created_layers)

~/.local/share/virtualenvs/perx-data-ml-wBZaki4L/lib/python3.7/site-packages/tensorflow_core/python/keras/backend.py in __call__(self, inputs)
   3725         value = math_ops.cast(value, tensor.dtype)
   3726       converted_inputs.append(value)
-> 3727     outputs = self._graph_fn(*converted_inputs)
   3728 
   3729     # EagerTensor.numpy() will often make a copy to ensure memory safety.

~/.local/share/virtualenvs/perx-data-ml-wBZaki4L/lib/python3.7/site-packages/tensorflow_core/python/eager/function.py in __call__(self, *args, **kwargs)
   1549       TypeError: For invalid positional/keyword argument combinations.
   1550     """
-> 1551     return self._call_impl(args, kwargs)
   1552 
   1553   def _call_impl(self, args, kwargs, cancellation_manager=None):

~/.local/share/virtualenvs/perx-data-ml-wBZaki4L/lib/python3.7/site-packages/tensorflow_core/python/eager/function.py in _call_impl(self, args, kwargs, cancellation_manager)
   1589       raise TypeError("Keyword arguments {} unknown. Expected {}.".format(
   1590           list(kwargs.keys()), list(self._arg_keywords)))
-> 1591     return self._call_flat(args, self.captured_inputs, cancellation_manager)
   1592 
   1593   def _filtered_call(self, args, kwargs):

~/.local/share/virtualenvs/perx-data-ml-wBZaki4L/lib/python3.7/site-packages/tensorflow_core/python/eager/function.py in _call_flat(self, args, captured_inputs, cancellation_manager)
   1690       # No tape is watching; skip to running the function.
   1691       return self._build_call_outputs(self._inference_function.call(
-> 1692           ctx, args, cancellation_manager=cancellation_manager))
   1693     forward_backward = self._select_forward_and_backward_functions(
   1694         args,

~/.local/share/virtualenvs/perx-data-ml-wBZaki4L/lib/python3.7/site-packages/tensorflow_core/python/eager/function.py in call(self, ctx, args, cancellation_manager)
    543               inputs=args,
    544               attrs=("executor_type", executor_type, "config_proto", config),
--> 545               ctx=ctx)
    546         else:
    547           outputs = execute.execute_with_cancellation(

~/.local/share/virtualenvs/perx-data-ml-wBZaki4L/lib/python3.7/site-packages/tensorflow_core/python/eager/execute.py in quick_execute(op_name, num_outputs, inputs, attrs, ctx, name)
     65     else:
     66       message = e.message
---> 67     six.raise_from(core._status_to_exception(e.code, message), None)
     68   except TypeError as e:
     69     keras_symbolic_tensors = [

~/.local/share/virtualenvs/perx-data-ml-wBZaki4L/lib/python3.7/site-packages/six.py in raise_from(value, from_value)

InvalidArgumentError:  You must feed a value for placeholder tensor 'user_sparse_inputs/values_3' with dtype float and shape [?]
     [[node user_sparse_inputs/values_3 (defined at <ipython-input-6-81b2fd61efeb>:16) ]] [Op:__inference_keras_scratch_graph_263]

Function call stack:
keras_scratch_graph

Ниже пользовательский слой SparseEmbedding, который я написал сам, потому что Keras пока не поддерживает его с обычным слоем Embedded.

class SparseEmbedding(tf.keras.layers.Layer):
    """
    Custom class for embedding sparse tensor Input.
    The current version of TF does not support embedding for Sparse Tensor.
    Ref: https://github.com/tensorflow/tensorflow/issues/33880
    """

    def __init__(self, n_components, name_suffix):
        super(SparseEmbedding, self).__init__()
        self.n_components = n_components
        self.name_suffix = name_suffix

    def build(self, input_shape):

        # Weights are normalized before building the variable
        self.raw_weights = tf.random.normal(
            [input_shape[-1], self.n_components], stddev=1.0, seed=SEED
        )
        self.normalized_weights = tf.nn.l2_normalize(self.raw_weights, 1)

        # Create variable nodes
        self.tf_linear_weights = tf.Variable(
            self.normalized_weights,
            name="embedding_weights_{}".format(self.name_suffix),
        )

    def call(self, inputs):

        weights_mult = lambda x: tf.sparse.sparse_dense_matmul(
            x, self.tf_linear_weights
        )
        outputs = tf.keras.layers.Lambda(weights_mult)(inputs)
        return outputs

Большое спасибо.

...