Pengenalan Tensorflow untuk Java

1. Gambaran keseluruhan

TensorFlow adalah perpustakaan sumber terbuka untuk pengaturcaraan aliran data . Ini awalnya dikembangkan oleh Google dan tersedia untuk pelbagai platform. Walaupun TensorFlow dapat berfungsi pada satu teras, ia dapat dengan mudah memanfaatkan banyak CPU, GPU atau TPU yang tersedia .

Dalam tutorial ini, kita akan membahas asas-asas TensorFlow dan cara menggunakannya di Java. Harap maklum bahawa TensorFlow Java API adalah API eksperimen dan oleh itu tidak dilindungi di bawah jaminan kestabilan. Kami akan membahas nanti dalam tutorial kemungkinan kes penggunaan untuk menggunakan TensorFlow Java API.

2. Asas

Pengiraan TensorFlow pada dasarnya berkisar pada dua konsep asas: Grafik dan Sesi . Mari kita teliti dengan cepat untuk mendapatkan latar belakang yang diperlukan untuk menjalani sisa tutorial.

2.1. Graf TensorFlow

Sebagai permulaan, mari kita fahami asas asas program TensorFlow. Pengiraan diwakili sebagai grafik dalam TensorFlow . Grafik biasanya merupakan grafik operasi dan data asiklik terarah, contohnya:

Gambar di atas mewakili graf pengiraan untuk persamaan berikut:

f(x, y) = z = a*x + b*y

Graf pengiraan TensorFlow terdiri daripada dua elemen:

  1. Tensor: Ini adalah unit inti data di TensorFlow. Mereka diwakili sebagai tepi dalam grafik komputasi, yang menggambarkan aliran data melalui grafik. Tensor boleh mempunyai bentuk dengan sebilangan dimensi. Bilangan dimensi dalam tensor biasanya disebut sebagai peringkatnya. Jadi skalar adalah tensor peringkat 0, vektor adalah tensor peringkat 1, matriks adalah tensor peringkat 2, dan seterusnya dan seterusnya.
  2. Operasi: Ini adalah nod dalam graf pengiraan. Mereka merujuk kepada pelbagai pengiraan yang boleh berlaku pada tensor yang memasuki operasi. Mereka juga sering menghasilkan tegangan yang berpunca dari operasi dalam grafik komputasi.

2.2. Sesi TensorFlow

Sekarang, grafik TensorFlow hanyalah skema pengiraan yang sebenarnya tidak mempunyai nilai. Grafik sedemikian mesti dijalankan di dalam apa yang disebut sesi TensorFlow agar tensor dalam grafik dinilai . Sesi boleh mengambil banyak tensor untuk menilai dari grafik sebagai parameter input. Kemudian ia berjalan ke belakang dalam grafik dan menjalankan semua nod yang diperlukan untuk menilai tensor tersebut.

Dengan pengetahuan ini, kami sekarang siap untuk mengambil ini dan menerapkannya ke API Java!

3. Persediaan Maven

Kami akan menyiapkan projek Maven cepat untuk membuat dan menjalankan grafik TensorFlow di Java. Kami hanya memerlukan pergantungan tensorflow :

 org.tensorflow tensorflow 1.12.0 

4. Membuat Grafik

Mari sekarang cuba membina grafik yang telah kita bincangkan di bahagian sebelumnya menggunakan TensorFlow Java API. Lebih tepatnya, untuk tutorial ini kita akan menggunakan API TensorFlow Java untuk menyelesaikan fungsi yang diwakili oleh persamaan berikut:

z = 3*x + 2*y

Langkah pertama adalah menyatakan dan memulakan grafik:

Graph graph = new Graph()

Sekarang, kita harus menentukan semua operasi yang diperlukan. Ingat, operasi di TensorFlow memakan dan menghasilkan tensor sifar atau lebih . Lebih-lebih lagi, setiap nod dalam grafik adalah operasi termasuk pemalar dan penahan tempat. Ini mungkin kelihatan tidak intuitif, tetapi tahan sebentar!

Graf kelas mempunyai fungsi generik yang dipanggil opBuilder () untuk membina sebarang jenis operasi di TensorFlow.

4.1. Mendefinisikan Pemalar

Sebagai permulaan, mari kita tentukan operasi berterusan dalam grafik kita di atas. Perhatikan bahawa operasi berterusan memerlukan tensor untuk nilainya :

Operation a = graph.opBuilder("Const", "a") .setAttr("dtype", DataType.fromClass(Double.class)) .setAttr("value", Tensor.create(3.0, Double.class)) .build(); Operation b = graph.opBuilder("Const", "b") .setAttr("dtype", DataType.fromClass(Double.class)) .setAttr("value", Tensor.create(2.0, Double.class)) .build();

Di sini, kami telah menentukan Operasi jenis tetap, memberi makan di Tensor dengan nilai berganda 2.0 dan 3.0. Permulaannya mungkin kelihatan sedikit luar biasa tetapi seperti itulah yang ada di Java API buat masa ini. Konstruk ini jauh lebih ringkas dalam bahasa seperti Python.

4.2. Menentukan Pemegang Tempat

Walaupun kita perlu memberikan nilai kepada pemalar kita, pemegang tempat tidak memerlukan nilai pada waktu definisi . Nilai untuk pemegang tempat perlu diberikan semasa grafik dijalankan dalam sesi. Kami akan membahas bahagian itu kemudian dalam tutorial.

Buat masa ini, mari kita lihat bagaimana kita dapat menentukan tempat letak kita:

Operation x = graph.opBuilder("Placeholder", "x") .setAttr("dtype", DataType.fromClass(Double.class)) .build(); Operation y = graph.opBuilder("Placeholder", "y") .setAttr("dtype", DataType.fromClass(Double.class)) .build();

Perhatikan bahawa kami tidak perlu memberikan nilai untuk pemegang tempat kami. Nilai-nilai ini akan diberi makan sebagai Tensor semasa dijalankan.

4.3. Mendefinisikan Fungsi

Akhirnya, kita perlu menentukan operasi matematik persamaan kita, iaitu pendaraban dan penambahan untuk mendapatkan hasilnya.

Ini tidak lain hanyalah Operasi di TensorFlow dan Graph.opBuilder () berguna sekali lagi:

Operation ax = graph.opBuilder("Mul", "ax") .addInput(a.output(0)) .addInput(x.output(0)) .build(); Operation by = graph.opBuilder("Mul", "by") .addInput(b.output(0)) .addInput(y.output(0)) .build(); Operation z = graph.opBuilder("Add", "z") .addInput(ax.output(0)) .addInput(by.output(0)) .build();

Di sini, kami telah menentukan Operasi , dua untuk mengalikan input kami dan yang terakhir untuk menyimpulkan hasil perantaraan. Perhatikan bahawa operasi di sini menerima tensor yang tidak lain adalah hasil operasi sebelumnya.

Harap diperhatikan bahawa kami mendapatkan output Tensor dari Operasi menggunakan indeks '0'. Seperti yang kita bincangkan sebelum ini, satu Operasi boleh menyebabkan satu atau lebih Tensor dan dengan itu semasa mendapatkan semula pemegang untuk itu, kita perlu menyebut indeks. Oleh kerana kami tahu bahawa operasi kami hanya mengembalikan satu Tensor , '0' berfungsi dengan baik!

5. Menggambarkan Grafik

Sukar untuk mengawasi grafik kerana saiznya bertambah besar. Ini menjadikannya penting untuk membayangkannya dalam beberapa cara . Kita selalu dapat membuat lukisan tangan seperti graf kecil yang kita buat sebelumnya tetapi tidak praktikal untuk grafik yang lebih besar. TensorFlow menyediakan utiliti yang dipanggil TensorBoard untuk memudahkan ini .

Sayangnya, API Java tidak memiliki kemampuan untuk menghasilkan fail peristiwa yang digunakan oleh TensorBoard. Tetapi menggunakan API di Python kita dapat menghasilkan fail acara seperti:

writer = tf.summary.FileWriter('.') ...... writer.add_graph(tf.get_default_graph()) writer.flush()

Jangan repot-repot jika ini tidak masuk akal dalam konteks Java, ini telah ditambahkan di sini hanya demi kelengkapan dan tidak perlu untuk melanjutkan tutorial ini.

Kita sekarang boleh memuat dan memvisualisasikan fail acara di TensorBoard seperti:

tensorboard --logdir .

TensorBoard hadir sebagai sebahagian daripada pemasangan TensorFlow.

Perhatikan persamaan antara ini dan grafik yang dilukis secara manual sebelumnya!

6. Bekerja dengan Sesi

We have now created a computational graph for our simple equation in TensorFlow Java API. But how do we run it? Before addressing that, let's see what is the state of Graph we have just created at this point. If we try to print the output of our final Operation “z”:

System.out.println(z.output(0));

This will result in something like:


    

This isn't what we expected! But if we recall what we discussed earlier, this actually makes sense. The Graph we have just defined has not been run yet, so the tensors therein do not actually hold any actual value. The output above just says that this will be a Tensor of type Double.

Let's now define a Session to run our Graph:

Session sess = new Session(graph)

Finally, we are now ready to run our Graph and get the output we have been expecting:

Tensor tensor = sess.runner().fetch("z") .feed("x", Tensor.create(3.0, Double.class)) .feed("y", Tensor.create(6.0, Double.class)) .run().get(0).expect(Double.class); System.out.println(tensor.doubleValue());

So what are we doing here? It should be fairly intuitive:

  • Get a Runner from the Session
  • Define the Operation to fetch by its name “z”
  • Feed in tensors for our placeholders “x” and “y”
  • Run the Graph in the Session

And now we see the scalar output:

21.0

This is what we expected, isn't it!

7. The Use Case for Java API

At this point, TensorFlow may sound like overkill for performing basic operations. But, of course, TensorFlow is meant to run graphs much much larger than this.

Additionally, the tensors it deals with in real-world models are much larger in size and rank. These are the actual machine learning models where TensorFlow finds its real use.

It's not difficult to see that working with the core API in TensorFlow can become very cumbersome as the size of the graph increases. To this end, TensorFlow provides high-level APIs like Keras to work with complex models. Unfortunately, there is little to no official support for Keras on Java just yet.

However, we can use Python to define and train complex models either directly in TensorFlow or using high-level APIs like Keras. Subsequently, we can export a trained model and use that in Java using the TensorFlow Java API.

Now, why would we want to do something like that? This is particularly useful for situations where we want to use machine learning enabled features in existing clients running on Java. For instance, recommending caption for user images on an Android device. Nevertheless, there are several instances where we are interested in the output of a machine learning model but do not necessarily want to create and train that model in Java.

This is where TensorFlow Java API finds the bulk of its use. We'll go through how this can be achieved in the next section.

8. Using Saved Models

We'll now understand how we can save a model in TensorFlow to the file system and load that back possibly in a completely different language and platform. TensorFlow provides APIs to generate model files in a language and platform neutral structure called Protocol Buffer.

8.1. Saving Models to the File System

We'll begin by defining the same graph we created earlier in Python and saving that to the file system.

Let's see we can do this in Python:

import tensorflow as tf graph = tf.Graph() builder = tf.saved_model.builder.SavedModelBuilder('./model') with graph.as_default(): a = tf.constant(2, name="a") b = tf.constant(3, name="b") x = tf.placeholder(tf.int32, name="x") y = tf.placeholder(tf.int32, name="y") z = tf.math.add(a*x, b*y, name="z") sess = tf.Session() sess.run(z, feed_dict = {x: 2, y: 3}) builder.add_meta_graph_and_variables(sess, [tf.saved_model.tag_constants.SERVING]) builder.save()

As the focus of this tutorial in Java, let's not pay much attention to the details of this code in Python, except for the fact that it generates a file called “saved_model.pb”. Do note in passing the brevity in defining a similar graph compared to Java!

8.2. Loading Models from the File System

We'll now load “saved_model.pb” into Java. Java TensorFlow API has SavedModelBundle to work with saved models:

SavedModelBundle model = SavedModelBundle.load("./model", "serve"); Tensor tensor = model.session().runner().fetch("z") .feed("x", Tensor.create(3, Integer.class)) .feed("y", Tensor.create(3, Integer.class)) .run().get(0).expect(Integer.class); System.out.println(tensor.intValue());

It should by now be fairly intuitive to understand what the above code is doing. It simply loads the model graph from the protocol buffer and makes available the session therein. From there onward, we can pretty much do anything with this graph as we would have done for a locally-defined graph.

9. Conclusion

To sum up, in this tutorial we went through the basic concepts related to the TensorFlow computational graph. We saw how to use the TensorFlow Java API to create and run such a graph. Then, we talked about the use cases for the Java API with respect to TensorFlow.

In the process, we also understood how to visualize the graph using TensorBoard, and save and reload a model using Protocol Buffer.

Seperti biasa, kod untuk contoh boleh didapati di GitHub.