Я попытался использовать 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:
.