Jak vyvolat vyškolený model TensorFlow z programů Java

Primárním jazykem, ve kterém jsou vytvářeny a školeny modely strojového učení TensorFlow, je Python. Mnoho programů podnikových serverů je však napsáno v jazyce Java. Takže se často setkáte s situacemi, kdy musíte vyvolat model Tensorflow, který jste vyškolili v Pythonu z Java programu.

Pokud používáte Cloud ML Engine na platformě Google Cloud Platform, není to žádný problém - v Cloud ML Engine jsou předpovědi prováděny prostřednictvím volání REST API a můžete tak učinit z jakéhokoli programovacího jazyka. Ale co když jste si stáhli model TensorFlow a chcete předpovědi provádět offline?

Zde je návod, jak můžete předpovídat v Javě pomocí modelů Tensorflow, které byly vyškoleny v Pythonu.

Poznámka: Tým Tensorflow nyní začal přidávat vazby Java. Podrobnosti viz https://github.com/tensorflow/tensorflow/tree/master/tensorflow/java. Vyzkoušejte to první, a pokud to pro vás nefunguje, přijďte sem ...

Zapisujte modelové soubory do Pythonu

První věc, kterou musíte udělat, je uložit model TensorFlow do Pythonu ve dvou formátech: (a) váhy, zkreslení atd. Jako soubor „saver_def“ (b) samotný graf jako soubor protobuf. Chcete-li si zachovat zdravý rozum, možná budete chtít graf uložit jako text i jako binární formát protobuf. Bude pro vás užitečné přečíst si textový formát a najít jména přiřazená TensorFlow uzlům, kterým jste explicitně nepřidělili jména. Kód pro zápis těchto tří souborů z Pythonu:

# vytvořte Saver objekt jako obvykle v Pythonu a uložte své proměnné
saver = tf.train.Saver (...)
# Použijte saver_def k získání „magických“ řetězců k obnovení
saver_def = saver.as_saver_def ()
print saver_def.filename_tensor_name
print saver_def.restore_op_name
# vypsat 3 soubory
saver.save (sess, 'trénoval_model.sd')
tf.train.write_graph (sess.graph_def, '.', 'trénoval_model.proto', as_text = False)
tf.train.write_graph (sess.graph_def, '.', 'trénoval_model.txt', as_text = True)

V mém případě byly dva magické řetězce vytištěné ze souboru save_def save / Const: 0 a save / restore_all - to je to, co uvidíte v mém kódu Java. Změňte je při psaní kódu Java, pokud se liší.

Soubor .sd obsahuje váhy, zkreslení atd. (Skutečné hodnoty proměnných v grafu). Soubor .proto je binární soubor obsahující váš výpočetní graf a .txt odpovídající textovou verzi.

Vyvolání Tensorflow C ++ z Javy

I když jste možná použili Tensorflow v Pythonu k přenosu dat do vašeho modelu a jejich zaškolení, balíček Tensorflow Python ve skutečnosti vyžaduje implementaci C ++, aby provedl skutečnou práci. Proto můžeme použít Java Native Interface (JNI) k přímému vyvolání C ++ a pomocí C ++ k vytvoření grafu a obnovení vah a zkreslení z modelu z Java.

Spíše než psát všechna volání JNI ručně, je možné použít open-source knihovnu nazvanou JavaCpp. Chcete-li použít JavaCpp, přidejte tuto závislost do svého Java Maven pom.xml:


   org.bytedeco.javacpp-presets 
   tensorflow 
   0.9.0–1.2 

Pokud používáte jiný systém správy sestavení, přidejte předvolby jazyka Javacpp pro tensorflow a všechny jeho závislosti do cesty ke třídě vaší aplikace.

Vytvořte model v Javě

Ve svém Java kódu si přečtěte proto proto, abyste vytvořili definici Graph následujícím způsobem (pro větší přehlednost jsou dovozy vynechány):

závěrečná relace relace = nová relace (nová SessionOptions ());
GraphDef def = new GraphDef ();
tensorflow.ReadBinaryProto (Env.Default (),
                           "somedir / trénoval_model.proto", def);
Stav s = session.Create (def);
if (! s.ok ()) {
    vyvolání nové RuntimeException (s.error_message (). getString ());
}

Dále obnovte váhy a zkreslení z uloženého souboru modelu pomocí Session :: Run (). Všimněte si, jak jsou použity magické řetězce od saver_def.

// obnovit
Tensor fn = nový Tensor (tensorflow.DT_STRING, nový TensorShape (1));
StringArray a = fn.createStringArray ();
a.position (0) .put („somedir / trénoval_model.sd“);
s = session.Run (nový StringTensorPairVector (nový String [] {“save / Const: 0”}, nový Tensor [] {fn}), nový StringVector (), nový StringVector (“save / restore_all”), nový TensorVector ( ));
if (! s.ok ()) {
   vyvolání nové RuntimeException (s.error_message (). getString ());
}

Vytváření předpovědí v Javě

Nyní je váš model připraven. Nyní ji můžete použít k vytváření předpovědí. Je to podobné, jako byste to udělali v Pythonu - musíte předat hodnoty pro všechny vaše zástupné symboly a vyhodnotit výstupní uzel. Rozdíl je v tom, že musíte znát skutečná jména zástupných symbolů a výstupních uzlů. Pokud jste v Pythonu nepřiřadili tyto uzly jedinečné názvy, Tensorflow jim přiřadil jména. Co to je, se dozvíte na souboru training_model.txt, který byl napsán. Nebo se můžete vrátit ke svému kódu Python a přiřadit názvy klíčových uzlů, které si pamatujete. V mém případě byl zástupný symbol vstupu označen jako zástupný symbol; zástupný symbol nouzového uzlu se jmenoval Placeholder_2 a výstupní uzel se jmenoval Sigmoid. Uvidíte je, na něž se odkazuje v hovoru Session :: Run () níže.

V mém případě neuronová síť používá 5 predikčních proměnných. Za předpokladu, že mám řadu vstupů, které jsou prediktory mého modelu neuronové sítě, a chci dělat předpověď pro 2 sady takových vstupů, můj vstup je matice 2x5. Moje NN má pouze jeden výstup, takže pro 2 sady vstupů je výstupní tenzor maticí 2x1. Uzlu výpadku je dán pevně zakódovaný vstup 1,0 (v predikci ponecháme všechny uzly - pravděpodobnost výpadku je pouze pro výcvik). Takže mám:

// zkuste předpovídat dva (2) sady vstupů.
Tensorové vstupy = nový Tensor (
         tensorflow.DT_FLOAT, nový TensorShape (2,5));
FloatBuffer x = inputs.createBuffer ();
x.put (nový plovák [] {- ​​6.0f, 22.0f, 383.0f, 27.781754111198122f, -6.5f});
x.put (nový plovák [] {66,0f, 22,0f, 2422,0f, 45,72160947712418f, 0,4f});
Tensor keepall = nový Tensor (
        tensorflow.DT_FLOAT, nový TensorShape (2,1));
((FloatBuffer) keepall.createBuffer ()). Put (nový float [] {1f, 1f});
Výstupy TensorVector = nový TensorVector ();
// pokaždé předpovídat, předávat hodnoty pro zástupné symboly
outputs.resize (0);
s = session.Run (nový StringTensorPairVector (nový String [] {“Placeholder”, “Placeholder_2”}, nový Tensor [] {vstupy, keepall}),
 nový StringVector („Sigmoid“), nový StringVector (), výstupy);
if (! s.ok ()) {
   vyvolání nové RuntimeException (s.error_message (). getString ());
}
// takto získáte zpětně předpokládanou hodnotu z výstupů
Výstup FloatBuffer = outputs.get (0) .createBuffer ();
pro (int k = 0; k 

To je vše - nyní používáte Java k provádění svých předpovědí. Existuje několik kroků, ale to lze očekávat, když jeden míchá 3 programovací jazyky (Python, C ++ a Java). Důležité však je, že se to dá udělat a že je to relativně jednoduché.

To samozřejmě nevyužívá hardwarové akcelerace a distribuce. Pokud chcete předpovídat velmi rychle v reálném čase, měli byste zvážit použití Cloud ML Engine.