Wie erstelle ich eine benutzerdefinierte Aktivierungsfunktion nur mit Python in Tensorflow?
Lesezeit: 8 Minuten
patapouf_ai
Angenommen, Sie müssen eine Aktivierungsfunktion erstellen, die mit vordefinierten Tensorflow-Bausteinen nicht möglich ist. Was können Sie tun?
In Tensorflow ist es also möglich, eine eigene Aktivierungsfunktion zu erstellen. Aber es ist ziemlich kompliziert, Sie müssen es in C++ schreiben und den gesamten Tensorflow neu kompilieren [1][2].
Gibt es einen einfacheren Weg?
Siehe auch Wie erstellen Sie eine benutzerdefinierte Aktivierungsfunktion mit Keras?
– Martin Thoma
11. Mai ’17 um 12:30 Uhr
Es ist schwer, bei jeder Software absolute Freiheit zu haben, aber wenn Sie uns eine Vorstellung davon geben, welche Aktivierungsfunktion (Funktionsfamilie) Sie erstellen möchten, kann Ihnen vielleicht jemand helfen.
– Benutzer1700890
1. Dezember 17 um 17:19 Uhr
patapouf_ai
Ja da ist!
Kredit:
Es war schwierig, die Informationen zu finden und zum Laufen zu bringen, aber hier ist ein Beispiel, das die Prinzipien und den gefundenen Code kopiert Hier und Hier.
Anforderungen:
Bevor wir beginnen, gibt es zwei Voraussetzungen, damit dies gelingen kann. Zuerst müssen Sie in der Lage sein, Ihre Aktivierung als Funktion auf numpy-Arrays zu schreiben. Zweitens müssen Sie in der Lage sein, die Ableitung dieser Funktion entweder als Funktion in Tensorflow (einfacher) oder im schlimmsten Fall als Funktion auf numpy Arrays zu schreiben.
Aktivierungsfunktion schreiben:
Nehmen wir zum Beispiel diese Funktion, die wir als Aktivierungsfunktion verwenden möchten:
def spiky(x):
r = x % 1
if r <= 0.5:
return r
else:
return 0
Die wie folgt aussehen:
Der erste Schritt besteht darin, daraus eine numpy-Funktion zu machen, das ist einfach:
import numpy as np
np_spiky = np.vectorize(spiky)
Jetzt sollten wir seine Ableitung schreiben.
Gradient der Aktivierung:
In unserem Fall ist es einfach, es ist 1, wenn x mod 1 < 0,5 und sonst 0. So:
def d_spiky(x):
r = x % 1
if r <= 0.5:
return 1
else:
return 0
np_d_spiky = np.vectorize(d_spiky)
Nun zum schwierigen Teil, daraus eine TensorFlow-Funktion zu machen.
Eine numpy-Fkt zu einer Tensorflow-Fkt machen:
Wir beginnen damit, np_d_spiky in eine Tensorflow-Funktion zu verwandeln. Es gibt eine Funktion im Tensorflow tf.py_func(func, inp, Tout, stateful=stateful, name=name)[doc] die jede numpy-Funktion in eine Tensorflow-Funktion umwandelt, damit wir sie verwenden können:
import tensorflow as tf
from tensorflow.python.framework import ops
np_d_spiky_32 = lambda x: np_d_spiky(x).astype(np.float32)
def tf_d_spiky(x,name=None):
with tf.name_scope(name, "d_spiky", [x]) as name:
y = tf.py_func(np_d_spiky_32,
[x],
[tf.float32],
name=name,
stateful=False)
return y[0]
tf.py_func wirkt auf Listen von Tensoren (und gibt eine Liste von Tensoren zurück), deshalb haben wir [x] (und zurück y[0]). Der stateful Die Option besteht darin, Tensorflow mitzuteilen, ob die Funktion immer dieselbe Ausgabe für dieselbe Eingabe liefert (stateful = False). In diesem Fall kann Tensorflow einfach den Tensorflow-Graphen anzeigen. Dies ist unser Fall und wird wahrscheinlich in den meisten Situationen der Fall sein. Eine Sache, auf die Sie an dieser Stelle achten sollten, ist, dass numpy verwendet wird float64 aber Tensorflow verwendet float32 Sie müssen also Ihre Funktion konvertieren, um sie zu verwenden float32 bevor Sie es in eine Tensorflow-Funktion konvertieren können, sonst wird sich Tensorflow beschweren. Deshalb müssen wir machen np_d_spiky_32 Erste.
Was ist mit den Farbverläufen? Das Problem, nur das oben Gesagte zu tun, ist, dass wir es jetzt haben tf_d_spiky das ist die Tensorflow-Version von np_d_spikywir könnten es nicht als Aktivierungsfunktion verwenden, wenn wir wollten, weil Tensorflow nicht weiß, wie man die Gradienten dieser Funktion berechnet.
Hack, um Farbverläufe zu erhalten: Wie in den oben genannten Quellen erklärt, gibt es einen Hack, um Gradienten einer Funktion zu definieren tf.RegisterGradient[doc] und tf.Graph.gradient_override_map[doc]. Kopieren Sie den Code von Harpune wir können die ändern tf.py_func Funktion, damit es gleichzeitig den Gradienten definiert:
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)
Jetzt sind wir fast fertig, die einzige Sache ist, dass die grad-Funktion, die wir an die obige py_func-Funktion übergeben müssen, eine spezielle Form annehmen muss. Es muss eine Operation und die vorherigen Gradienten vor der Operation aufnehmen und die Gradienten nach der Operation rückwärts ausbreiten.
Gradientenfunktion: Für unsere stachelige Aktivierungsfunktion würden wir es also so machen:
def spikygrad(op, grad):
x = op.inputs[0]
n_gr = tf_d_spiky(x)
return grad * n_gr
Die Aktivierungsfunktion hat deshalb nur einen Eingang x = op.inputs[0]. Wenn die Operation viele Eingaben hätte, müssten wir ein Tupel zurückgeben, einen Gradienten für jede Eingabe. Zum Beispiel, wenn die Operation war a-bdie Steigung bzgl a ist +1 und bzgl b ist -1 also hätten wir return +1*grad,-1*grad. Beachten Sie, dass wir Tensorflow-Funktionen der Eingabe zurückgeben müssen, deshalb brauchen wir tf_d_spiky, np_d_spiky hätte nicht funktioniert, weil es nicht auf Tensorflow-Tensoren wirken kann. Alternativ hätten wir die Ableitung auch mit Tensorflow-Funktionen schreiben können:
def spikygrad2(op, grad):
x = op.inputs[0]
r = tf.mod(x,1)
n_gr = tf.to_float(tf.less_equal(r, 0.5))
return grad * n_gr
Alles zusammen kombinieren: Jetzt, da wir alle Teile haben, können wir sie alle miteinander kombinieren:
np_spiky_32 = lambda x: np_spiky(x).astype(np.float32)
def tf_spiky(x, name=None):
with tf.name_scope(name, "spiky", [x]) as name:
y = py_func(np_spiky_32,
[x],
[tf.float32],
name=name,
grad=spikygrad) # <-- here's the call to the gradient
return y[0]
Und jetzt sind wir fertig. Und wir können es testen.
Prüfen:
with tf.Session() as sess:
x = tf.constant([0.2,0.7,1.2,1.7])
y = tf_spiky(x)
tf.initialize_all_variables().run()
print(x.eval(), y.eval(), tf.gradients(y, [x])[0].eval())
@lahwran, das ist nicht wirklich eine Aktivierungsfunktion, die Sie im wirklichen Leben verwenden möchten. Dies ist nur ein Beispiel dafür, wie Sie eine benutzerdefinierte Aktivierungsfunktion implementieren, wenn Sie dies benötigen.
– patapouf_ai
3. Juli 17 um 13:19 Uhr
ja, es funktioniert 🙂 aber ich habe nicht versucht, ein Netzwerk zu verwenden, es war ein echtes Lernproblem, ich musste eine viel kompliziertere Aktivierungsfunktion als die für meinen Zweck machen und die hat man gelernt, aber für den Beitrag hier habe ich nur ein Spielzeug eingesetzt Aktivierungsfunktion, die ich nicht zu lernen versucht habe.
– patapouf_ai
4. Juli 17 um 7:45 Uhr
genial ! Hinweis für Personen, die derzeit Ihre Methode verwenden möchten, sollten Sie ersetzen op.scope von tf.name_scope, weil ersteres ist veraltet. op.scope nimmt das Argument wie folgt: op.scope(values, name, “default_name”), während die Argumentreihenfolge von tf.name_scope tf.name_scope(name, default_name, values) ist, also anstelle von ops.op_scope([x]name, “stachelig”) sollte man verwenden tf.name_scope(name, “stachelig”, [x])
– Nsaura
11. Juni 18 um 16:46 Uhr
@patapouf_ai verwendet TensorFlow GPU-Beschleunigung für benutzerdefinierte Funktionen? Das heißt, wird diese Aktivierung parallel auf viele Tensorelemente über CUDA-Kerne hinweg angewendet?
– Rohan Saxena
7. August 18 um 10:19 Uhr
@patapouf_ai Die klarste Erklärung zum Erstellen einer benutzerdefinierten Tensorflow-Funktion, die ich bisher gesehen habe – danke!
– jtlz2
14. April 20 um 9:53 Uhr
Warum verwenden Sie nicht einfach die Funktionen, die bereits in Tensorflow verfügbar sind, um Ihre neue Funktion zu erstellen?
Für die spiky in Ihrer Antwort funktionieren, könnte dies wie folgt aussehen
Ich würde dies als wesentlich einfacher betrachten (es müssen nicht einmal Gradienten berechnet werden), und wenn Sie nicht wirklich exotische Dinge tun möchten, kann ich mir kaum vorstellen, dass Tensorflow nicht die Bausteine für den Aufbau hochkomplexer Aktivierungsfunktionen liefert.
Ja, in der Tat, Spiky kann mit tf-Primitiven gemacht werden, aber Spiky ist nur ein einfaches Beispiel, um nicht durch die Komplexität der Funktion verwirrt zu werden, die ich wirklich implementieren wollte. Die Funktion, die ich eigentlich implementieren wollte, konnte leider nicht mit tf-Primitiven implementiert werden.
– patapouf_ai
24. Juli 17 um 08:28 Uhr
Der springende Punkt der Frage ist: Was tun Sie, wenn Sie die Aktivierungsfunktion nicht mit tf-Primitiven formulieren können?
– patapouf_ai
24. Juli 17 um 8:37 Uhr
@patapouf_ai Ich habe das bereits erwartet, aber es geht aus deiner Frage nicht hervor. Aufgrund der Popularität dieser Frage hielt ich es für eine gute Idee, auch auf diese Lösung hinzuweisen (für Personen mit wenig Erfahrung mit Tensorflow, die versuchen, ihre eigenen Aktivierungsfunktionen zu erstellen).
– Herr Tsjolder
24. Juli 17 um 9:38 Uhr
Sehr nützliche Antwort, außer Sie möchten vielleicht die Form von Tensor x so verwenden: def stachelig (x): r = tf.floormod (x, tf.constant (1, shape = x.shape)) cond = tf.less_equal ( r, tf.constant(0.5,shape=x.shape)) return tf.where(cond, r, tf.constant(0,shape=x.shape)) Andernfalls erhalten Sie möglicherweise diese Art von Fehler: ValueError: Shape must Rang xx sein, aber Rang xx für ‘cond_xx/Switch’ (op: ‘Switch’)
– adrienbourgeois
22. Juli 18 um 3:24 Uhr
@ShavedMan Meine Antwort enthält ein vollständiges Beispiel. Ich bin mir nicht sicher, was fehlen könnte…
– Herr Tsjolder
17. Dezember 21 um 7:22 Uhr
.
7593200cookie-checkWie erstelle ich eine benutzerdefinierte Aktivierungsfunktion nur mit Python in Tensorflow?yes
Siehe auch Wie erstellen Sie eine benutzerdefinierte Aktivierungsfunktion mit Keras?
– Martin Thoma
11. Mai ’17 um 12:30 Uhr
Es ist schwer, bei jeder Software absolute Freiheit zu haben, aber wenn Sie uns eine Vorstellung davon geben, welche Aktivierungsfunktion (Funktionsfamilie) Sie erstellen möchten, kann Ihnen vielleicht jemand helfen.
– Benutzer1700890
1. Dezember 17 um 17:19 Uhr