J'ai beaucoup de mal à obtenir une fonction de perte personnalisée avec un argument supplémentaire pour fonctionner dans TF 2.0 en utilisant tf.keras et un ensemble de données.
Dans le cas suivant, l'argument supplémentaire correspond aux données d'entrée dans le modèle, qui sont contenues dans un Dataset
. Dans le cas 1.14, j'exécuterais .make_one_shot_iterator().get_next()
sur l'ensemble de données et passerais ensuite le tenseur que j'entrerais dans la fonction de perte. La même chose ne fonctionne pas en 2.0.
class WeightedSDRLoss(keras.losses.Loss):
def __init__(self, noisy_signal, reduction=keras.losses.Reduction.AUTO, name='WeightedSDRLoss'):
super().__init__(reduction=reduction, name=name)
self.noisy_signal = noisy_signal
def sdr_loss(self, sig_true, sig_pred):
return (-tf.reduce_mean(sig_true * sig_pred) /
tf.reduce_mean(tf.norm(tensor=sig_pred) * tf.norm(tensor=sig_true)))
def call(self, y_true, y_pred):
noise_true = self.noisy_signal - y_true
noise_pred = self.noisy_signal - y_pred
alpha = (tf.reduce_mean(tf.square(y_true)) /
tf.reduce_mean(tf.square(y_true) + tf.square(self.noisy_signal - y_pred)))
return alpha * self.sdr_loss(y_true, y_pred) + (1 - alpha) * self.sdr_loss(noise_true, noise_pred)
data_x = np.random.Rand(5, 4, 1)
data_y = np.random.Rand(5, 4, 1)
x = keras.layers.Input([4, 1])
y = keras.layers.Activation('tanh')(x)
model = keras.models.Model(inputs=x, outputs=y)
train_dataset = tf.data.Dataset.from_tensor_slices((data_x, data_y))
x_dataset = train_dataset.map(lambda x, y: x)
model.compile(loss=WeightedSDRLoss(x_dataset), optimizer='Adam')
model.fit(train_dataset)
Mais j'obtiens l'erreur suivante dans tensorflow:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../anaconda3/envs/.../lib/python3.6/site-packages/tensorflow_core/python/training/tracking/base.py:457: in _method_wrapper
result = method(self, *args, **kwargs)
../../anaconda3/envs/.../lib/python3.6/site-packages/tensorflow_core/python/keras/engine/training.py:377: in compile
self._compile_weights_loss_and_weighted_metrics()
../../anaconda3/envs/.../lib/python3.6/site-packages/tensorflow_core/python/training/tracking/base.py:457: in _method_wrapper
result = method(self, *args, **kwargs)
../../anaconda3/envs/.../lib/python3.6/site-packages/tensorflow_core/python/keras/engine/training.py:1618: in _compile_weights_loss_and_weighted_metrics
self.total_loss = self._prepare_total_loss(masks)
../../anaconda3/envs/.../lib/python3.6/site-packages/tensorflow_core/python/keras/engine/training.py:1678: in _prepare_total_loss
per_sample_losses = loss_fn.call(y_true, y_pred)
...:144: in call
noise_true = self.noisy_signal - y_true
../../anaconda3/envs/.../lib/python3.6/site-packages/tensorflow_core/python/ops/math_ops.py:924: in r_binary_op_wrapper
x = ops.convert_to_tensor(x, dtype=y.dtype.base_dtype, name="x")
../../anaconda3/envs/.../lib/python3.6/site-packages/tensorflow_core/python/framework/ops.py:1184: in convert_to_tensor
return convert_to_tensor_v2(value, dtype, preferred_dtype, name)
../../anaconda3/envs/.../lib/python3.6/site-packages/tensorflow_core/python/framework/ops.py:1242: in convert_to_tensor_v2
as_ref=False)
../../anaconda3/envs/.../lib/python3.6/site-packages/tensorflow_core/python/framework/ops.py:1296: in internal_convert_to_tensor
ret = conversion_func(value, dtype=dtype, name=name, as_ref=as_ref)
../../anaconda3/envs/.../lib/python3.6/site-packages/tensorflow_core/python/framework/constant_op.py:286: in _constant_tensor_conversion_function
return constant(v, dtype=dtype, name=name)
../../anaconda3/envs/.../lib/python3.6/site-packages/tensorflow_core/python/framework/constant_op.py:227: in constant
allow_broadcast=True)
../../anaconda3/envs/.../lib/python3.6/site-packages/tensorflow_core/python/framework/constant_op.py:265: in _constant_impl
allow_broadcast=allow_broadcast))
../../anaconda3/envs/.../lib/python3.6/site-packages/tensorflow_core/python/framework/tensor_util.py:449: in make_tensor_proto
_AssertCompatible(values, dtype)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
values = <MapDataset shapes: (...), types: tf.float32>
dtype = tf.float32
def _AssertCompatible(values, dtype):
if dtype is None:
fn = _check_not_tensor
else:
try:
fn = _TF_TO_IS_OK[dtype]
except KeyError:
# There isn't a specific fn, so we try to do the best possible.
if dtype.is_integer:
fn = _check_int
Elif dtype.is_floating:
fn = _check_float
Elif dtype.is_complex:
fn = _check_complex
Elif dtype.is_quantized:
fn = _check_quantized
else:
fn = _check_not_tensor
try:
fn(values)
except ValueError as e:
[mismatch] = e.args
if dtype is None:
raise TypeError("List of Tensors when single Tensor expected")
else:
raise TypeError("Expected %s, got %s of type '%s' instead." %
> (dtype.name, repr(mismatch), type(mismatch).__name__))
E TypeError: Expected float32, got <MapDataset shapes: (...), types: tf.float32> of type 'MapDataset' instead.
Le problème semble être que je passe un ensemble de données dans la fonction de perte, mais il veut un tenseur évalué avec impatience.
Au lieu de cela, j'ai essayé de passer la couche d'entrée dans la perte personnalisée, mais cela ne fonctionne pas non plus:
data_x = np.random.Rand(5, 4, 1)
data_y = np.random.Rand(5, 4, 1)
x = keras.layers.Input(shape=[4, 1])
y = keras.layers.Activation('tanh')(x)
model = keras.models.Model(inputs=x, outputs=y)
train_dataset = tf.data.Dataset.from_tensor_slices((data_x, data_y)).batch(1)
model.compile(loss=WeightedSDRLoss(x), optimizer='Adam')
model.fit(train_dataset)
Au lieu de cela, j'obtiens l'erreur:
op_name = '__inference_distributed_function_169', num_outputs = 2
inputs = [<tf.Tensor: id=82, shape=(), dtype=resource, numpy=<unprintable>>, <tf.Tensor: id=83, shape=(), dtype=variant, numpy=<unprintable>>, <tf.Tensor 'input_1:0' shape=(None, 4, 1) dtype=float32>]
attrs = ('executor_type', '', 'config_proto', b'\n\x07\n\x03GPU\x10\x00\n\x07\n\x03CPU\x10\x012\x02J\x008\x01')
ctx = <tensorflow.python.eager.context.Context object at 0x11785f4e0>
name = None
def quick_execute(op_name, num_outputs, inputs, attrs, ctx, name=None):
"""Execute a TensorFlow operation.
Args:
op_name: Name of the TensorFlow operation (see REGISTER_OP in C++ code) to
execute.
num_outputs: The number of outputs of the operation to fetch.
(Explicitly provided instead of being inferred for performance
reasons).
inputs: A list of inputs to the operation. Each entry should be a Tensor, or
a value which can be passed to the Tensor constructor to create one.
attrs: A Tuple with alternating string attr names and attr values for this
operation.
ctx: The value of context.context().
name: Customized name for the operation.
Returns:
List of output Tensor objects. The list is empty if there are no outputs
Raises:
An exception on error.
"""
device_name = ctx.device_name
# pylint: disable=protected-access
try:
ctx.ensure_initialized()
tensors = pywrap_tensorflow.TFE_Py_Execute(ctx._handle, device_name,
op_name, inputs, attrs,
> num_outputs)
E TypeError: An op outside of the function building code is being passed
E a "Graph" tensor. It is possible to have Graph tensors
E leak out of the function building context by including a
E tf.init_scope in your function building code.
E For example, the following function will fail:
E @tf.function
E def has_init_scope():
E my_constant = tf.constant(1.)
E with tf.init_scope():
E added = my_constant * 2
E The graph tensor has name: input_1:0
../../../lib/python3.6/site-packages/tensorflow_core/python/eager/execute.py:61: TypeError
During handling of the above exception, another exception occurred:
def test_loss():
data_x = np.random.Rand(5, 4, 1)
data_y = np.random.Rand(5, 4, 1)
x = keras.layers.Input(shape=[4, 1])
y = keras.layers.Activation('tanh')(x)
model = keras.models.Model(inputs=x, outputs=y)
train_dataset = tf.data.Dataset.from_tensor_slices((data_x, data_y)).batch(1)
print(train_dataset)
model.compile(loss=WeightedSDRLoss(x))
> model.fit(train_dataset)
test_preprocess.py:162:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../lib/python3.6/site-packages/tensorflow_core/python/keras/engine/training.py:734: in fit
use_multiprocessing=use_multiprocessing)
../../../lib/python3.6/site-packages/tensorflow_core/python/keras/engine/training_v2.py:324: in fit
total_epochs=epochs)
../../../lib/python3.6/site-packages/tensorflow_core/python/keras/engine/training_v2.py:123: in run_one_Epoch
batch_outs = execution_function(iterator)
../../../training_v2_utils.py:86: in execution_function
distributed_function(input_fn))
../../../def_function.py:445: in __call__
return self._concrete_stateful_fn._filtered_call(Canon_args, Canon_kwds) # pylint: disable=protected-access
../../../function.py:1141: in _filtered_call
self.captured_inputs)
../../../function.py:1224: in _call_flat
ctx, args, cancellation_manager=cancellation_manager)
../../../function.py:511: in call
ctx=ctx)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
op_name = '__inference_distributed_function_169', num_outputs = 2
inputs = [<tf.Tensor: id=82, shape=(), dtype=resource, numpy=<unprintable>>, <tf.Tensor: id=83, shape=(), dtype=variant, numpy=<unprintable>>, <tf.Tensor 'input_1:0' shape=(None, 4, 1) dtype=float32>]
attrs = ('executor_type', '', 'config_proto', b'\n\x07\n\x03GPU\x10\x00\n\x07\n\x03CPU\x10\x012\x02J\x008\x01')
ctx = <tensorflow.python.eager.context.Context object at 0x11785f4e0>
name = None
def quick_execute(op_name, num_outputs, inputs, attrs, ctx, name=None):
"""Execute a TensorFlow operation.
Args:
op_name: Name of the TensorFlow operation (see REGISTER_OP in C++ code) to
execute.
num_outputs: The number of outputs of the operation to fetch.
(Explicitly provided instead of being inferred for performance
reasons).
inputs: A list of inputs to the operation. Each entry should be a Tensor, or
a value which can be passed to the Tensor constructor to create one.
attrs: A Tuple with alternating string attr names and attr values for this
operation.
ctx: The value of context.context().
name: Customized name for the operation.
Returns:
List of output Tensor objects. The list is empty if there are no outputs
Raises:
An exception on error.
"""
device_name = ctx.device_name
# pylint: disable=protected-access
try:
ctx.ensure_initialized()
tensors = pywrap_tensorflow.TFE_Py_Execute(ctx._handle, device_name,
op_name, inputs, attrs,
num_outputs)
except core._NotOkStatusException as e:
if name is not None:
message = e.message + " name: " + name
else:
message = e.message
six.raise_from(core._status_to_exception(e.code, message), None)
except TypeError as e:
keras_symbolic_tensors = [
x for x in inputs if ops._is_keras_symbolic_tensor(x)
]
if keras_symbolic_tensors:
raise core._SymbolicException(
"Inputs to eager execution function cannot be Keras symbolic "
> "tensors, but found {}".format(keras_symbolic_tensors))
E tensorflow.python.eager.core._SymbolicException: Inputs to eager execution function cannot be Keras symbolic tensors, but found [<tf.Tensor 'input_1:0' shape=(None, 4, 1) dtype=float32>]
Des idées sur la façon de faire fonctionner cela? Je ne veux pas utiliser une boucle d'entraînement personnalisée, car je perds alors beaucoup de la commodité des keras.
[~ # ~] uniquement [~ # ~] TF 2.0.0-beta1 [~ # ~] pas [~ # ~] rc
Pour moi ta deuxième tentative
data_x = np.random.Rand(5, 4, 1)
data_y = np.random.Rand(5, 4, 1)
x = keras.layers.Input([4, 1])
y = keras.layers.Activation('tanh')(x)
model = keras.models.Model(inputs=x, outputs=y)
train_dataset = tf.data.Dataset.from_tensor_slices((data_x, data_y)).batch(1)
model.compile(loss=WeightedSDRLoss(x), optimizer='Adam')
model.fit(train_dataset)
fonctionne bien. Je devais juste spécifier un optimiseur.
Je reçois seulement l'avertissement Expected a shuffled dataset but input dataset `x` is not shuffled. Please invoke `shuffle()` on input dataset.
qui peut être évité en ajoutant train_dataset = train_dataset.shuffle(1)
avant l'entraînement.