Aufrufen eines trainierten TensorFlow-Modells aus Java-Programmen

Die Hauptsprache, in der TensorFlow-Modelle für maschinelles Lernen erstellt und trainiert werden, ist Python. Viele Enterprise Server-Programme sind jedoch in Java geschrieben. Daher stoßen Sie häufig auf Situationen, in denen Sie das Tensorflow-Modell, das Sie in Python trainiert haben, aus einem Java-Programm aufrufen müssen.

Wenn Sie Cloud ML Engine auf der Google Cloud Platform verwenden, ist dies kein Problem. In Cloud ML Engine werden Vorhersagen über einen REST-API-Aufruf erstellt, sodass Sie dies aus jeder Programmiersprache heraus tun können. Aber was ist, wenn Sie das TensorFlow-Modell heruntergeladen haben und Vorhersagen offline durchführen möchten?

Hier erfahren Sie, wie Sie mithilfe von Tensorflow-Modellen, die in Python geschult wurden, Vorhersagen in Java treffen können.

Hinweis: Das Tensorflow-Team hat nun begonnen, Java-Bindungen hinzuzufügen. Weitere Informationen finden Sie unter https://github.com/tensorflow/tensorflow/tree/master/tensorflow/java. Versuchen Sie es zuerst und wenn es bei Ihnen nicht funktioniert, kommen Sie hierher ...

Schreiben Sie Modelldateien in Python aus

Das erste, was Sie tun müssen, ist, das TensorFlow-Modell in Python in zwei Formaten zu speichern: (a) die Gewichte, Verzerrungen usw. als "saver_def" -Datei (b) das Diagramm selbst als protobuf -Datei. Um Ihre geistige Gesundheit zu bewahren, möchten Sie das Diagramm möglicherweise sowohl als Text als auch als binäres Protokollformat speichern. Sie werden es hilfreich finden, das Textformat durchzulesen, um die von TensorFlow zugewiesenen Namen für Knoten zu finden, denen Sie nicht explizit Namen zugewiesen haben. Der Code zum Schreiben dieser drei Dateien aus Python:

# Erstellen Sie in Python wie gewohnt ein Saver-Objekt, um Ihre Variablen zu speichern
saver = tf.train.Saver (...)
# Verwenden Sie saver_def, um die "magischen" Zeichenfolgen wiederherzustellen
saver_def = saver.as_saver_def ()
print saver_def.filename_tensor_name
print saver_def.restore_op_name
# 3 Dateien ausschreiben
saver.save (sess, 'educational_model.sd')
tf.train.write_graph (sess.graph_def, '.', 'educational_model.proto', as_text = False)
tf.train.write_graph (sess.graph_def, '.', 'taught_model.txt', as_text = True)

In meinem Fall lauteten die beiden magischen Zeichenfolgen, die aus save_def ausgegeben wurden, save / Const: 0 und save / restore_all. Das sehen Sie also in meinem Java-Code. Ändern Sie diese, wenn Sie Ihren Java-Code schreiben, falls Sie davon abweichen.

Die .sd-Datei enthält Gewichte, Verzerrungen usw. (die tatsächlichen Werte für die Variablen in Ihrem Diagramm). Die .proto-Datei ist eine Binärdatei, die Ihr Berechnungsdiagramm und .txt die entsprechende Textversion enthält.

Aufrufen von Tensorflow C ++ aus Java

Auch wenn Sie Tensorflow in Python verwendet haben, um Daten in Ihr Modell einzugeben und zu trainieren, ruft das Tensorflow-Python-Paket tatsächlich eine C ++ - Implementierung auf, um die eigentliche Arbeit auszuführen. Daher können wir Java Native Interface (JNI) verwenden, um C ++ direkt aufzurufen, und C ++ verwenden, um das Diagramm zu erstellen und die Gewichte und Verzerrungen aus dem Modell in Java wiederherzustellen.

Anstatt alle JNI-Aufrufe von Hand zu schreiben, können Sie dazu eine Open-Source-Bibliothek namens JavaCpp verwenden. Um JavaCpp zu verwenden, fügen Sie diese Abhängigkeit zu Ihrer Java Maven-Datei pom.xml hinzu:


   org.bytedeco.javacpp-presets 
   Tensorflow 
   0.9.0–1.2 

Wenn Sie ein anderes Build-Management-System verwenden, fügen Sie dem Klassenpfad Ihrer Anwendung Javacpp-Vorgaben für Tensorflow und alle zugehörigen Abhängigkeiten hinzu.

Modell in Java erstellen

Lesen Sie in Ihrem Java-Code die Protodatei, um eine Diagrammdefinition wie folgt zu erstellen (Importe sind aus Gründen der Übersichtlichkeit weggelassen):

letzte Sitzung session = neue Sitzung (new SessionOptions ());
GraphDef def = new GraphDef ();
tensorflow.ReadBinaryProto (Env.Default (),
                           "somedir / educational_model.proto", def);
Status s = session.Create (def);
if (! an ok ()) {
    werfen neue RuntimeException (s.error_message (). getString ());
}

Stellen Sie als Nächstes die Gewichte und Vorspannungen aus der gespeicherten Modelldatei mit Session :: Run () wieder her. Beachten Sie, wie die magischen Zeichenfolgen von saver_def verwendet werden.

// wiederherstellen
Tensor fn = neuer Tensor (tensorflow.DT_STRING, neue TensorShape (1));
StringArray a = fn.createStringArray ();
a.position (0) .put ("somedir / educational_model.sd");
s = session.Run (neuer StringTensorPairVector (neuer String [] {“save / Const: 0”}, neuer Tensor [] {fn}), neuer StringVector (), neuer StringVector (“save / restore_all”), neuer TensorVector ( ));
if (! an ok ()) {
   werfen neue RuntimeException (s.error_message (). getString ());
}

Vorhersagen in Java treffen

Zu diesem Zeitpunkt ist Ihr Modell fertig. Sie können es jetzt verwenden, um Vorhersagen zu treffen. Dies ist ähnlich wie in Python - Sie müssen Werte für alle Ihre Platzhalter übergeben und den Ausgabeknoten auswerten. Der Unterschied besteht darin, dass Sie die tatsächlichen Namen des Platzhalters und der Ausgabeknoten kennen müssen. Wenn Sie diesen Knoten in Python keine eindeutigen Namen zugewiesen haben, hat Tensorflow ihnen Namen zugewiesen. Sie können herausfinden, was sie sind, indem Sie sich die ausgebildete_modell.txt-Datei ansehen, die ausgeschrieben wurde. Sie können auch zu Ihrem Python-Code zurückkehren und die Namen der Schlüsselknoten zuweisen, an die Sie sich erinnern. In meinem Fall wurde der Eingabe-Platzhalter als Platzhalter bezeichnet. Der Platzhalter für den Dropout-Knoten hieß Placeholder_2, und der Ausgabeknoten hieß Sigmoid. Diese werden im folgenden Aufruf von Session :: Run () angegeben.

In meinem Fall verwendet das neuronale Netzwerk 5 Prädiktorvariablen. Angenommen, ich habe das Array von Eingängen, die die Prädiktoren für mein neuronales Netzwerkmodell sind, und möchte die Vorhersage für 2 Sätze solcher Eingänge durchführen, dann ist meine Eingabe eine 2x5-Matrix. Mein NN hat nur einen Ausgang, daher ist der Ausgangstensor für 2 Sätze von Eingängen eine 2x1-Matrix. Der Dropout-Knoten erhält eine fest codierte Eingabe von 1,0 (in der Vorhersage behalten wir alle Knoten bei - die Dropout-Wahrscheinlichkeit gilt nur für das Training). Also habe ich:

// Versuchen Sie, zwei (2) Sätze von Eingaben vorherzusagen.
Tensor-Eingänge = neuer Tensor (
         tensorflow.DT_FLOAT, neue TensorShape (2,5));
FloatBuffer x = inputs.createBuffer ();
x.put (new float [] {- ​​6.0f, 22.0f, 383.0f, 27.781754111198122f, -6.5f});
x.put (neuer Gleitkommawert [] {66.0f, 22.0f, 2422.0f, 45.72160947712418f, 0.4f});
Tensor keepall = neuer Tensor (
        tensorflow.DT_FLOAT, neue TensorShape (2,1));
((FloatBuffer) keepall.createBuffer ()). Put (new float [] {1f, 1f});
TensorVector-Ausgänge = new TensorVector ();
// Um ​​jedes Mal vorherzusagen, übergeben Sie Werte für Platzhalter
output.resize (0);
s = session.Run (neuer StringTensorPairVector (neuer String [] {"Placeholder", "Placeholder_2"}, neuer Tensor [] {Eingänge, keepall}),
 neuer StringVector ("Sigmoid"), neuer StringVector (), Ausgänge);
if (! an ok ()) {
   werfen neue RuntimeException (s.error_message (). getString ());
}
// Auf diese Weise erhalten Sie den vorhergesagten Wert von den Ausgaben zurück
FloatBuffer output = output.get (0) .createBuffer ();
für (int k = 0; k 

Siehe auch

So vermarkten Sie sich besser mit einem fantastischen LinkedIn-ProfilSo nehmen Sie sich Zeit für Kundeninterviews und ValidierungWie ich mein Leben in 30 Tagen verändereSo optimieren Sie Ihren EntscheidungsprozessWährend des Studiums lernen.