2017-05-26 30 views
1

Meine Kostenfunktion beinhaltet die Berechnung von log (det (A)) (vorausgesetzt, det (A) ist positiv, so dass das Protokoll sinnvoll ist, aber A ist nicht Hermiteschen so die Cholesky-Zerlegung ist hier nicht anwendbar). Wenn det (A) sehr groß/klein ist, wird ein direkter Aufruf von det (A) überlaufen/unterlaufen. Um dies zu umgehen, verwenden Sie eine die mathematische Tatsache, dassBerechne Log der Determinante in TensorFlow, wenn Determinante Überlauf/Unterlauf

log (det (A)) = Tr (log (A)),

, wo die später ausgewertet werden können LU-Zerlegung verwendet (was effizienter als Eigenwert/SVD). Dieser Algorithmus wurde in numpy als numpy.linalg.slogdet implementiert. Das Problem besteht also darin, wie numpy von TensorFlow aufgerufen wird.


Hier ist, was ich versuchte

import numpy as np 
import tensorflow as tf 
from tensorflow.python.framework import function 

def logdet_np(a): 
    _, l = np.linalg.slogdet(a) 
    return l 

def logdet1(a): 
    return tf.py_func(logdet_np, [a], tf.float64) 

@function.Defun(tf.float64, func_name='LogDet') 
def logdet2(a): 
    return tf.py_func(logdet_np, [a], tf.float64) 

with tf.Session() as sess: 
    a = tf.constant(np.eye(500)*10.) 
    #print(sess.run(logdet1(a))) 
    print(sess.run(logdet2(a))) 

ich zum ersten Mal einer Python-Funktion definiert das numpy Ergebnis heraus zu führen. Dann habe ich zwei logdet Funktionen unter Verwendung tf.py_func definiert. Die zweite Funktion ist mit function.Defun dekoriert, die später verwendet wird, um TensorFlow-Funktionen und ihre Gradienten zu definieren. Als ich sie prüfte, fand ich, dass die erste Funktion logdet1 funktioniert und das korrekte Ergebnis gibt. Aber die zweite Funktion logdet2 gibt einen KeyError zurück.

--------------------------------------------------------------------------- 
KeyError         Traceback (most recent call last) 
/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site- 
packages/tensorflow/python/ops/script_ops.py in __call__(self, token, args) 
    77 def __call__(self, token, args): 
    78  """Calls the registered function for `token` with args.""" 
---> 79  func = self._funcs[token] 
    80  if func is None: 
    81  raise ValueError("callback %s is not found" % token) 

KeyError: 'pyfunc_0' 

Meine Frage ist, was mit dem Defun Dekorateur falsch ist? Warum steht es im Widerspruch zu py_func? Wie kann ich numpy Funktionen in TensorFlor richtig einwickeln?


Der verbleibende Teil wird der Gradient für logdet des Definierens matrix determinant differentiation in tensorflow auf die Frage im Zusammenhang. Gemäß der Lösung in dieser Frage versucht man

@function.Defun(tf.float64, tf.float64, func_name='LogDet_Gradient') 
def logdet_grad(a, grad): 
    a_adj_inv = tf.matrix_inverse(a, adjoint=True) 
    out_shape = tf.concat([tf.shape(a)[:-2], [1, 1]], axis=0) 
    return tf.reshape(grad, out_shape) * a_adj_inv 
@function.Defun(tf.float64, func_name='LogDet', grad_func=logdet_grad) 
def logdet(a): 
    return tf.py_func(logdet_np, [a], tf.float64, stateful=False, name='LogDet') 

Der obige Code zu schreiben funktionieren würde, wenn man den Konflikt zwischen Defun und py_func lösen kann, die die entscheidende Frage ist, die ich oben angehoben.

+0

Sie SVD verwenden können und erhalten Determinante von singulären Werten –

+0

ist eine besondere (zB positiv definite)? – dmuir

+0

@dmuir det (A) ist positiv, aber die Eigenwerte sind nicht alle positiv (dh es gibt negative Eigenwerte, die paarweise auftreten). –

Antwort

2

Mit Hilfe von @MaxB, hier poste ich den Code, um die Funktion logdet für log (abs (det (A))) und seine Steigung zu definieren.

  • logdet ruft die numpy Funktion numpy.linalg.slogdet das Protokoll der Determinante die Idee der log (det (A)) = Tr (log (A)) unter Verwendung von zu berechnen, die gegen den Überlauf/Unterlauf des robust bestimmend. Es basiert auf der LU-Zerlegung, die im Vergleich zur Eigenwert/SVD-basierten Methode effizienter ist.

  • Die Zahlfunktion slogdet gibt ein Tupel zurück, das sowohl das Vorzeichen der Determinante als auch das Protokoll enthält (abs (det (A))). Das Vorzeichen wird vernachlässigt, da es bei der Optimierung nicht zum Gradientensignal beiträgt.

  • Der Gradient von logdet wird durch Matrixinversion berechnet, gemäß Grad log (det (A)) = inv (A)^T. Es basiert auf TensorFlow's Code auf _MatrixDeterminantGrad mit leichten Modifikationen.


import numpy as np 
import tensorflow as tf 
# from https://gist.github.com/harpone/3453185b41d8d985356cbe5e57d67342 
# Define custom py_func which takes also a grad op as argument: 
def py_func(func, inp, Tout, stateful=True, name=None, grad=None): 
    # Need to generate a unique name to avoid duplicates: 
    rnd_name = 'PyFuncGrad' + str(np.random.randint(0, 1E+8)) 
    tf.RegisterGradient(rnd_name)(grad) # see _MySquareGrad for grad example 
    g = tf.get_default_graph() 
    with g.gradient_override_map({"PyFunc": rnd_name}): 
     return tf.py_func(func, inp, Tout, stateful=stateful, name=name) 
# from https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/ops/linalg_grad.py 
# Gradient for logdet 
def logdet_grad(op, grad): 
    a = op.inputs[0] 
    a_adj_inv = tf.matrix_inverse(a, adjoint=True) 
    out_shape = tf.concat([tf.shape(a)[:-2], [1, 1]], axis=0) 
    return tf.reshape(grad, out_shape) * a_adj_inv 
# define logdet by calling numpy.linalg.slogdet 
def logdet(a, name = None): 
    with tf.name_scope(name, 'LogDet', [a]) as name: 
     res = py_func(lambda a: np.linalg.slogdet(a)[1], 
         [a], 
         tf.float64, 
         name=name, 
         grad=logdet_grad) # set the gradient 
     return res 

Man kann für sehr große/kleine Determinante, dass logdet Werke testen und ihre Steigung ist auch richtig.

i = tf.constant(np.eye(500)) 
x = tf.Variable(np.array([10.])) 
y = logdet(x*i) 
dy = tf.gradients(y, [x]) 
with tf.Session() as sess: 
    sess.run(tf.global_variables_initializer()) 
    print(sess.run([y, dy])) 

Ergebnis: [1151.2925464970251, [array([ 50.])]]

+0

In Ihrer Frage haben Sie nie gesagt, dass CPU-only war in Ordnung (Sonst Aufruf von NP kann schlecht sein). Sie haben auch nie gesagt, dass die Leistung für diese bestimmte Op war entscheidend (Sonst ist die einfachste Lösung am besten). – MaxB

1

Wenn Ihr Problem der Überlauf ist, können Sie es mit einfacher Mathematik bekämpfen. enter image description here

Sie müssen also nur die Eigenwerte abrufen, sie aufzeichnen und zusammenfassen.

+0

TF hat keinen allgemeinen Eigenwert op (noch wären sie reell).Die Verwendung von SVD ist der richtige Ansatz (wie vorgeschlagen). – MaxB

+0

@MaxB die Tatsache, dass Eigenwert imaginär sein kann, bricht nicht die Mathematik. Sie können immer noch imaginäre Zahlen aufzeichnen und Sie können einige imaginäre Zahlen zusammenfassen. Bezüglich der Nicht-Eigenwerte bin ich mir dessen nicht bewusst, aber was hält eine Person davon ab, eigene C++ - Funktionen zu implementieren? Jetzt sehe ich den Kommentar über SVD, und wenn Sie denken, dass dieser Kommentar ausreicht, um zu verstehen, was zu tun ist - erklären Sie uns bitte die Verbindung zwischen SVD und Determinante. –

+0

schrieb als Antwort, da Sie darauf bestanden. – MaxB

0

Sie können SVD verwenden zu zersetzen A:

A = U S V' 

Da die Determinante eines Produkts ein Produkt der Determinanten ist, und die Determinanten von U und V' sind 1 oder -1, während die Determinante S ist nicht negative,

abs(det(A)) = det(S) 

Daher Protokoll eines (positiv) kann als Determinante

berechnet werden

Ab TF1.1 fehlt tf.svd Gradienten (zukünftige Versionen haben es wahrscheinlich), und so schlage ich vor, die Umsetzung von Annahme kofd ‚s-Code:

https://github.com/tensorflow/tensorflow/issues/6503

+0

Das Fehlen von Gradienten für SVD kann durch die Tatsache umgangen werden, dass grad von log (det (A)) die Transponierte von inv (A) ist. Ich habe Ihren Code tatsächlich getestet, er ist sehr langsam aufgrund der SVD, viel langsamer als 'tf.log (tf.matrix_determinant (A))'. Ich fand auch, dass numpy eine Funktion 'slogdet' für meinen Zweck bereitstellt, die auf der effizienteren LU-Zerlegung basiert. Jetzt würde ich gerne wissen wie man numpy Form TensorFlow anruft. Bitte werfen Sie einen Blick auf meine aktualisierte Frage. Ich würde Ihre Patienten sehr schätzen. –

+0

@EverettYou Sie können NP von TF anrufen: Siehe z.B. https://stackoverflow.com/questions/43839431/tensorflow-how-to-replace-or-modify-gradient/43930598#43930598 – MaxB

+0

@EverettYou oder eher https://gist.github.com/harpone/3453185b41d8d985356cbe5e57d67342 - die letzter Kommentar dort. – MaxB

Verwandte Themen