2017-04-20 10 views
2

Ich versuche, ein Keras 2 LSTM mit einer benutzerdefinierten Verlustfunktion über Tensorflow zu schreiben:Ausnahme in Tensorflow Funktion als Keras individuellen Verlust verwendete

model.compile(loss=in_top_k_loss, optimizer='rmsprop', metrics=[bin_crossent_true_only, 'binary_crossentropy', 'mean_squared_error', 'accuracy']) 

Mein Trainingssatz Beispiele mit verschiedenen Größen der Zeitdimension hat, daher Ich verwende train_on_batch, wobei jeder Batch nur aus Instanzen mit derselben Zeitdimension besteht. Losgröße ist 256. Der folgende Code löst eine sehr unangenehme Ausnahme in der ersten Epoche (wenn train_on_batch zuerst genannt):

# takes 2 1D arrays of equal length, returns a single value (the negative of my own "precision" measure) 
def in_top_k_loss_single(y_true, y_pred): 
    y_true_labels = tf.cast(tf.transpose(tf.where(y_true > 0))[0], tf.int32) 
    y_pred = tf.reshape(y_pred, [1, tf.shape(y_pred)[0]]) 
    y_topk_tensor = tf.nn.top_k(y_pred, k=7) 
    y_topk_ixs = y_topk_tensor[0][0][:7] 
    y_topk = y_topk_tensor[1][0][:7] 
    y_topk_len = tf.cast(tf.count_nonzero(y_topk_ixs), tf.int32) 
    y_topk = y_topk[:y_topk_len] 
    y_topk0 = tf.expand_dims(y_topk, 1) 
    y_true_labels0 = tf.expand_dims(y_true_labels, 0) 
    re = tf.cast(tf.reduce_any(tf.equal(y_topk0, y_true_labels0), 1), tf.int32)/tf.range(1,y_topk_len+1) 
    return (-1) * tf.where(tf.equal(tf.reduce_sum(y_pred), tf.constant(0.0)), tf.constant(0.0), tf.cast(tf.reduce_mean(re),tf.float32)) 

# takes 2 matrices of equal sizes, 
# applies the upper function for y_true[i] & y_pred[i] for each row i, 
# returns a single value (mean of all row-wise values) 
def in_top_k_loss(y_true, y_pred): 
    # if I change `in_top_k_loss_single` to `keras.metrics.binary_crossentropy` (for instance) it runs 
    return K.mean(tf.map_fn(lambda x: in_top_k_loss_single(x[0], x[1]), (y_true, y_pred), dtype=tf.float32)) 

wo in_top_k_loss meine benutzerdefinierte Verlustfunktion im Keras Modell. Diese Funktionen scheinen zu funktionieren, wenn ich sie separat mit verschiedenen Eingaben (sogar tricky) teste. Es scheint, dass nur Keras Probleme damit hat - vielleicht erwartet es andere Datentypen/Formen/etc.

Einige kluge Ideen aus dem Internet: Versucht, die Batch-Größe zu ändern, den Optimierer zu ändern und den Gradienten zu kappen - kein Erfolg. Auch versucht, evaluate vor train_on_batch aufrufen - kein Erfolg.

Rest des Codes arbeitet mit Verlusten aus Keras sowie Verlusten wie diese:

def bin_crossent_true_only(y_true, y_pred): 
    return (1 + keras.backend.sum(y_pred)) * keras.metrics.binary_crossentropy(y_true, y_true * y_pred) 

Die Funktion in_top_k_loss Werke und liefert aussagekräftige Ergebnisse, wenn in dem metrics Array verwendet. Alle Eingaben (y_true, y_pred) sind nicht NaN. y_true may hat 0s und 1s (null oder mehr 1s pro Reihe, d. h. pro Instanz des Trainingssatzes).

Die Ausnahme selbst:

Traceback (most recent call last): 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\op_def_library.py", line 491, in apply_op 
    preferred_dtype=default_dtype) 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\ops.py", line 702, in internal_convert_to_tensor 
    ret = conversion_func(value, dtype=dtype, name=name, as_ref=as_ref) 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\constant_op.py", line 110, in _constant_tensor_conversion_function 
    return constant(v, dtype=dtype, name=name) 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\constant_op.py", line 99, in constant 
    tensor_util.make_tensor_proto(value, dtype=dtype, shape=shape, verify_shape=verify_shape)) 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\tensor_util.py", line 360, in make_tensor_proto 
    raise ValueError("None values not supported.") 
ValueError: None values not supported. 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "<stdin>", line 9, in <module> 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\keras\models.py", line 941, in train_on_batch 
    class_weight=class_weight) 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\keras\engine\training.py", line 1620, in train_on_batch 
    self._make_train_function() 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\keras\engine\training.py", line 1002, in _make_train_function 
    self.total_loss) 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\keras\optimizers.py", line 210, in get_updates 
    new_a = self.rho * a + (1. - self.rho) * K.square(g) 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\keras\backend\tensorflow_backend.py", line 1225, in square 
    return tf.square(x) 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\ops\math_ops.py", line 384, in square 
    return gen_math_ops.square(x, name=name) 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\ops\gen_math_ops.py", line 2733, in square 
    result = _op_def_lib.apply_op("Square", x=x, name=name) 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\op_def_library.py", line 504, in apply_op 
    values, as_ref=input_arg.is_ref).dtype.name 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\ops.py", line 702, in internal_convert_to_tensor 
    ret = conversion_func(value, dtype=dtype, name=name, as_ref=as_ref) 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\constant_op.py", line 110, in _constant_tensor_conversion_function 
    return constant(v, dtype=dtype, name=name) 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\constant_op.py", line 99, in constant 
    tensor_util.make_tensor_proto(value, dtype=dtype, shape=shape, verify_shape=verify_shape)) 
    File "C:\Users\myname\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\tensor_util.py", line 360, in make_tensor_proto 
    raise ValueError("None values not supported.") 
ValueError: None values not supported. 

Antwort

3

Die Optimizern in TensorFlow erfordern, daß die Verlustfunktion differenzierbar sein, die durch alle der Operationen zwischen dem Verlust führen und den Variablen in der TensorFlow Graph mit definierten Gradienten bestimmt wird. Die tf.where() Operation hat keine definierten Gradienten, was bedeutet, dass die Gesamtverlustfunktion nicht differenzierbar ist. Das Ergebnis der Berechnung der Gradienten einer nicht differenzierbaren Funktion in TensorFlow ist None, was zu dem Fehler führt, den Sie sehen, wenn Keras versucht, die Variablen zu aktualisieren.

+1

Das beantwortete meine Frage. Leider kann ich mir keine Möglichkeit vorstellen, die 2 'where' im Funktionskörper zu entfernen. :( Kann ich MAP @ k - Mittlere Durchschnittspräzision für die höchsten vorhergesagten K-Klassen (eine Instanz kann mehr als 1 Label haben) - als Verlust (das Negative von, da wir Verluste minimieren) verwenden? Oder was sind meine Alternativen - Verwenden Sie es in 'metrics' und überwachen Sie es separat (dann speichern Sie das Modell mit einem Callback, wenn der Messwert maximal ist) – altier2856

+1

Bedeutet das, dass es keinen einfachen Weg gibt, eine Zeichenänderung in einem Verlust zu bestrafen? : https://codeburst.io/neural-networks-for-algorithmic-trading-volatility-forecasting-and-custom-loss-functions-c030e316ea7e mit K.switch (das ist Theano) – wordsforthewise

Verwandte Themen