Buat situs sederhana yang mengklasifikasikan gambar

1. Sebelum memulai

Dalam codelab ini, Anda akan mempelajari cara menjalankan inferensi klasifikasi gambar dari situs menggunakan Penayangan TensorFlow dengan REST dan gRPC.

Prasyarat

  • Pengetahuan dasar tentang pengembangan web, seperti HTML dan JavaScript
  • Pengetahuan dasar tentang machine learning dengan TensorFlow, seperti pelatihan dan deployment
  • Pengetahuan dasar tentang terminal dan Docker

Yang akan Anda pelajari

  • Cara menemukan model klasifikasi gambar terlatih di TensorFlow Hub.
  • Cara membuat situs sederhana dan membuat prediksi dengan model klasifikasi gambar yang didownload melalui Penayangan TensorFlow (REST dan gRPC).
  • Cara merender hasil deteksi di UI.

Yang Anda butuhkan

2. Memulai persiapan

Untuk mendownload kode codelab ini:

  1. Buka repositori GitHub ini.
  2. Klik Code > Download zip untuk mendownload semua kode untuk codelab ini.

a72f2bb4caa9a96.png

  1. Ekstrak file zip yang didownload untuk mengekstrak folder root codelabs dengan semua resource yang Anda butuhkan.

Untuk codelab ini, Anda hanya memerlukan file dalam subdirektori TFServing/ImageClassificationWeb di repositori, yang berisi dua folder:

  • Folder starter berisi kode awal yang Anda buat untuk codelab ini.
  • Folder finished berisi kode yang sudah selesai untuk aplikasi contoh yang telah selesai.

3 Instal dependensi

Untuk menginstal dependensi:

  • Di terminal Anda, buka folder starter lalu instal paket NPM yang diperlukan:
npm install

4. Menjalankan situs awal

Gunakan Server Web untuk Chrome untuk memuat file TFServing/ImageClassificationWeb/starter/dist/index.html:

  1. Masukkan Chrome://apps/ di kolom URL Chrome, lalu cari Server Web untuk Chrome di daftar aplikasi.
  2. Luncurkan Server Web untuk Chrome, lalu pilih folder TFServing/ImageClassificationWeb/starter/dist/.
  3. Klik tombol Server Web untuk mengaktifkannya, lalu buka http://localhost:8887/ di browser Anda.

f7b43cd44ebf1f1b.png

Jalankan dan jelajahi situs

Anda akan melihat situs tersebut sekarang. UI cukup mudah: ada gambar kucing yang ingin Anda klasifikasikan dan pengguna dapat mengirim data ke backend dengan REST atau gRPC. Backend melakukan klasifikasi gambar pada gambar dan menampilkan hasil klasifikasi ke situs, yang menampilkan hasilnya.

837d97a27c59a0b3.png

Jika Anda mengklik Classify, tidak akan ada yang terjadi karena belum dapat berkomunikasi dengan backend.

5. Men-deploy model klasifikasi gambar dengan Penayangan TensorFlow

Klasifikasi gambar adalah tugas ML yang sangat umum yang mengklasifikasikan gambar ke dalam kategori yang telah ditetapkan berdasarkan konten utama gambar. Berikut ini contoh mengklasifikasikan bunga:

a6da16b4a7665db0.png

Ada sejumlah model klasifikasi gambar terlatih di TensorFlow Hub. Anda menggunakan model Inception v3 yang populer untuk codelab ini.

Untuk men-deploy model klasifikasi gambar dengan Penayangan TensorFlow:

  1. Download file model Inception v3.
  2. Kompresi file .tar.gz yang telah didownload dengan alat dekompresi, seperti 7-Zip.
  3. Buat folder inception_v3 lalu buat subfolder 123 di dalamnya.
  4. Masukkan folder variables yang diekstrak dan file saved_model.pb ke dalam subfolder 123.

Anda dapat merujuk ke folder inception_v3 sebagai folder SavedModel. 123 adalah contoh nomor versi. Jika mau, Anda dapat memilih nomor lain.

Struktur folder akan terlihat seperti gambar ini:

21a8675ac8d31907.png

Memulai TensorFlow Serving

  • Di terminal Anda, mulai Penayangan TensorFlow dengan Docker, tetapi ganti PATH/TO/SAVEDMODEL dengan jalur absolut folder inception_v3 di komputer Anda.
docker pull tensorflow/serving

docker run -it --rm -p 8500:8500 -p 8501:8501 -v "PATH/TO/SAVEDMODEL:/models/inception" -e MODEL_NAME=inception tensorflow/serving

Docker otomatis mendownload gambar Penayangan TensorFlow terlebih dahulu, yang memerlukan waktu satu menit. Setelah itu, Penayangan TensorFlow akan dimulai. Log akan terlihat seperti cuplikan kode ini:

2022-02-25 06:01:12.513231: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle.
2022-02-25 06:01:12.585012: I external/org_tensorflow/tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 3000000000 Hz
2022-02-25 06:01:13.395083: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/inception/123
2022-02-25 06:01:13.837562: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 1928700 microseconds.
2022-02-25 06:01:13.877848: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/inception/123/assets.extra/tf_serving_warmup_requests
2022-02-25 06:01:13.929844: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: inception version: 123}
2022-02-25 06:01:13.985848: I tensorflow_serving/model_servers/server_core.cc:486] Finished adding/updating models
2022-02-25 06:01:13.985987: I tensorflow_serving/model_servers/server.cc:367] Profiler service is enabled
2022-02-25 06:01:13.988994: I tensorflow_serving/model_servers/server.cc:393] Running gRPC ModelServer at 0.0.0.0:8500 ...
[warn] getaddrinfo: address family for nodename not supported
2022-02-25 06:01:14.033872: I tensorflow_serving/model_servers/server.cc:414] Exporting HTTP/REST API at:localhost:8501 ...
[evhttp_server.cc : 245] NET_LOG: Entering the event loop ...

6. Menyiapkan proxy Envoy

Saat ini, Penayangan TensorFlow tidak menetapkan header Access-Control-Allow-Origin, sehingga browser memblokir permintaan dari JavaScript frontend ke Penayangan TensorFlow untuk alasan keamanan. Untuk mengatasinya, Anda perlu menggunakan proxy, seperti Envoy, untuk membuat proxy permintaan dari JavaScript ke backend Penayangan TensorFlow.

Mulai Envoy

  • Di terminal Anda, download gambar Envoy dan mulai Envoy dengan Docker, tetapi ganti placeholder PATH/TO/ENVOY-CUSTOM.YAML dengan jalur absolut file envoy-custom.yaml di folder starter.
docker pull envoyproxy/envoy-dev:fd3e8370ddb7a96634c192d1461516e6de1d1797

docker run --add-host host.docker.internal:host-gateway --rm -it -p 9901:9901 -p 8000:8000 -p 8080:8080 -v PATH/TO/ENVOY-CUSTOM.YAML:/envoy-custom.yaml envoyproxy/envoy-dev:fd3e8370ddb7a96634c192d1461516e6de1d1797 -c /envoy-custom.yaml

Docker otomatis mendownload gambar Envoy terlebih dahulu. Setelah itu, Envoy akan dimulai. Log akan terlihat seperti cuplikan kode ini:

[2022-03-02 07:51:48.563][1][info][main] [source/server/server.cc:436]   response trailer map: 152 bytes: grpc-message,grpc-status
[2022-03-02 07:51:48.681][1][info][main] [source/server/server.cc:772] runtime: {}
[2022-03-02 07:51:48.682][1][info][admin] [source/server/admin/admin.cc:134] admin address: 0.0.0.0:9901
[2022-03-02 07:51:48.683][1][info][config] [source/server/configuration_impl.cc:127] loading tracing configuration
[2022-03-02 07:51:48.683][1][info][config] [source/server/configuration_impl.cc:87] loading 0 static secret(s)
[2022-03-02 07:51:48.683][1][info][config] [source/server/configuration_impl.cc:93] loading 2 cluster(s)
[2022-03-02 07:51:48.687][1][info][config] [source/server/configuration_impl.cc:97] loading 2 listener(s)
[2022-03-02 07:51:48.694][1][info][config] [source/server/configuration_impl.cc:109] loading stats configuration
[2022-03-02 07:51:48.696][1][info][main] [source/server/server.cc:868] starting main dispatch loop
[2022-03-02 07:51:48.881][1][info][runtime] [source/common/runtime/runtime_impl.cc:446] RTDS has finished initialization
[2022-03-02 07:51:48.881][1][info][upstream] [source/common/upstream/cluster_manager_impl.cc:207] cm init: all clusters initialized
[2022-03-02 07:51:48.881][1][info][main] [source/server/server.cc:849] all clusters initialized. initializing init manager
[2022-03-02 07:51:48.881][1][info][config] [source/server/listener_manager_impl.cc:784] all dependencies initialized. starting workers
[2022-03-02 07:51:48.902][1][warning][main] [source/server/server.cc:747] there is no configured limit to the number of allowed active connections. Set a limit via the runtime key overload.global_downstream_max_connections

7. Menghubungkan situs dengan TensorFlow melalui REST

Backend sekarang sudah siap sehingga Anda dapat mengirim permintaan klien ke Penayangan TensorFlow untuk mengklasifikasikan gambar. Ada dua cara untuk mengirim permintaan ke Penayangan TensorFlow:

  • REST
  • gRPC

Mengirim permintaan dan menerima respons melalui REST

Ada tiga langkah sederhana untuk mengirim dan menerima permintaan melalui REST:

  1. Buat permintaan REST.
  2. Kirim permintaan REST ke Penayangan TensorFlow.
  3. Ekstrak hasil prediksi dari respons REST dan tampilkan hasilnya.

Anda akan melakukan langkah-langkah berikut dalam file src/index.js.

Membuat permintaan REST

Saat ini, fungsi classify_img() tidak mengirimkan permintaan REST ke Penayangan TensorFlow. Anda perlu mengimplementasikan cabang REST ini untuk membuat permintaan REST terlebih dahulu:

if (radioButtons[0].checked) {
    console.log('Using REST');
    // TODO: Add code to send a REST request to TensorFlow Serving.

}

Penayangan TensorFlow mengharapkan permintaan POST yang berisi tensor gambar untuk model Inception v3 yang Anda gunakan, jadi Anda harus mengekstrak nilai RGB dari setiap piksel gambar ke dalam array lalu menggabungkan array dalam JSON, yang merupakan payload dari permintaan.

  • Tambahkan kode ini ke cabang REST:
//Create the REST request.
let imgTensor = new Array();
let pixelArray = new Array();
context.drawImage(img, 0, 0);
for(let i=0; i<inputImgHeight; i++) {
    pixelArray[i] = new Array();
    for (let j=0; j<inputImgWidth; j++) {
        pixelArray[i][j] = new Array();
        pixelArray[i][j].push(context.getImageData(i, j, 1, 1).data[0]/255);
        pixelArray[i][j].push(context.getImageData(i, j, 1, 1).data[1]/255);
        pixelArray[i][j].push(context.getImageData(i, j, 1, 1).data[2]/255);
    }
}
imgTensor.push(pixelArray);

const RESTURL = 'http://localhost:8000/v1/models/inception:predict';
let xhr = new XMLHttpRequest();
xhr.open('POST', RESTURL);
xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8;');
let data = JSON.stringify({
    instances: imgTensor
});
xhr.onload = () => {

}
xhr.onerror = () => {
    console.log('REST request error');
}

Mengirim permintaan REST ke Penayangan TensorFlow

Sekarang Anda dapat mengirimkan permintaan.

  • Tambahkan kode ini tepat setelah kode di atas di cabang REST:
// Send the REST request.
xhr.send(data);

Memproses respons REST dari TensorFlow Serving

Model Inception v3 menampilkan array probabilitas bahwa gambar tersebut termasuk dalam kategori yang telah ditetapkan. Jika prediksi berhasil, Anda akan menampilkan kategori yang paling mungkin muncul di UI.

Anda mengimplementasikan pemroses onload() untuk menangani respons.

xhr.onload = () => {

}
  • Tambahkan kode ini ke pemroses onload():
// Process the REST response.
const response = JSON.parse(xhr.responseText);
const maxIndex = argmax(response['predictions'][0])
document.getElementById('category').textContent = 'Predicted category: ' + maxIndex;

Sekarang pemroses mengekstrak probabilitas prediksi dari respons, mengidentifikasi kategori objek yang paling mungkin, dan menampilkan hasilnya di UI.

Menjalankan aplikasi

  1. Di terminal Anda, buka folder starter dan gunakan webpack untuk memaketkan semua file JavaScript ke dalam satu file yang dapat Anda sematkan dalam file dist/index.html:
npm install -g npx
npm install --save-dev webpack
npx webpack
  1. Muat Ulanghttp://localhost:8887/ di browser, lalu klikREST > Klasifikasikan data.

Situs menampilkan 286 sebagai kategori yang diprediksi, yang dipetakan ke label Egyptian Cat di set data ImageNet.

c865a93b9b58335d.png

8 Menghubungkan situs dengan TensorFlow Serve melalui gRPC

Selain REST, Penayangan TensorFlow juga mendukung gRPC.

b6f4449c2c850b0e.png

gRPC adalah framework Modern Procedure Call (RPC) modern yang bersifat open source dan berperforma tinggi, yang dapat berjalan di lingkungan apa pun. Layanan ini dapat secara efisien menghubungkan layanan di dan ke seluruh pusat data dengan dukungan yang dapat dicolokkan untuk load balancing, perekaman aktivitas, pemeriksaan kesehatan, dan autentikasi. Telah diamati bahwa dalam praktiknya, gRPC lebih berperforma daripada REST.

Mengirim permintaan dan menerima respons dengan gRPC

Ada empat langkah sederhana:

  1. Opsional: Buat kode stub klien gRPC.
  2. Buat permintaan gRPC.
  3. Kirim permintaan gRPC ke Penayangan TensorFlow.
  4. Ekstrak hasil prediksi dari respons gRPC dan tampilkan di UI.

Anda dapat menyelesaikan langkah-langkah ini di file src/index.js.

Opsional: Membuat kode stub klien gRPC

Untuk menggunakan gRPC dengan TensorFlow Serve, Anda harus mengikuti alur kerja gRPC. Untuk mempelajari detailnya lebih lanjut, lihat dokumentasi gRPC.

a9d0e5cb543467b4.png

Penayangan TensorFlow dan TensorFlow menentukan file .proto untuk Anda. Mulai TensorFlow dan TensorFlow Serve 2.8, file .proto berikut adalah yang diperlukan:

tensorflow/core/example/example.proto
tensorflow/core/example/feature.proto
tensorflow/core/protobuf/struct.proto
tensorflow/core/protobuf/saved_object_graph.proto
tensorflow/core/protobuf/saver.proto
tensorflow/core/protobuf/trackable_object_graph.proto
tensorflow/core/protobuf/meta_graph.proto
tensorflow/core/framework/node_def.proto
tensorflow/core/framework/attr_value.proto
tensorflow/core/framework/function.proto
tensorflow/core/framework/types.proto
tensorflow/core/framework/tensor_shape.proto
tensorflow/core/framework/full_type.proto
tensorflow/core/framework/versions.proto
tensorflow/core/framework/op_def.proto
tensorflow/core/framework/graph.proto
tensorflow/core/framework/tensor.proto
tensorflow/core/framework/resource_handle.proto
tensorflow/core/framework/variable.proto

tensorflow_serving/apis/inference.proto
tensorflow_serving/apis/classification.proto
tensorflow_serving/apis/predict.proto
tensorflow_serving/apis/regression.proto
tensorflow_serving/apis/get_model_metadata.proto
tensorflow_serving/apis/input.proto
tensorflow_serving/apis/prediction_service.proto
tensorflow_serving/apis/model.proto
  • Di terminal Anda, buka folder starter/src/proto/ dan buat stub:
bash generate_grpc_stub_js.sh

Membuat permintaan gRPC

Serupa dengan permintaan REST, Anda membuat permintaan gRPC di cabang gRPC.

if (connectionMode[picker.selectedRow(inComponent: 0)] == "REST") {

}
else {
    print("Using gRPC")
    // TODO: Add code to send a gRPC request to TensorFlow Serving.

}
  • Tambahkan kode ini ke cabang gRPC:
// Create the gRPC request.
const PredictModule = require('./proto/generated/tensorflow_serving/apis/predict_pb.js');
const PredictionServiceClientModule = require('./proto/generated/tensorflow_serving/apis/prediction_service_grpc_web_pb.js');
const ModelModule = require('./proto/generated/tensorflow_serving/apis/model_pb.js');
const TensorModule = require('./proto/generated/tensorflow/core/framework/tensor_pb.js');

const GPRCURL = 'http://localhost:8080';
const stub = new PredictionServiceClientModule.PredictionServiceClient(GPRCURL);

const modelSpec = new ModelModule.ModelSpec();
modelSpec.setName('inception');

const tensorProto = new TensorModule.TensorProto();
const tensorShapeProto = new TensorModule.TensorShapeProto();

const batchDim = (new TensorModule.TensorShapeProto.Dim()).setSize(1);
const heightDim = (new TensorModule.TensorShapeProto.Dim()).setSize(inputImgHeight);
const widthDim = (new TensorModule.TensorShapeProto.Dim()).setSize(inputImgWidth);
const channelDim = (new TensorModule.TensorShapeProto.Dim()).setSize(3);

tensorShapeProto.setDimList([batchDim, heightDim, widthDim, channelDim]);

tensorProto.setDtype(proto.tensorflow.DataType.DT_FLOAT);
tensorProto.setTensorShape(tensorShapeProto);
context.drawImage(img, 0, 0);
for(let i=0; i<inputImgHeight; i++) {
    for (let j=0; j<inputImgWidth; j++) {
        tensorProto.addFloatVal(context.getImageData(i, j, 1, 1).data[0]/255);
        tensorProto.addFloatVal(context.getImageData(i, j, 1, 1).data[1]/255);
        tensorProto.addFloatVal(context.getImageData(i, j, 1, 1).data[2]/255);
    }
}

const predictionServiceRequest = new PredictModule.PredictRequest();
predictionServiceRequest.setModelSpec(modelSpec);
predictionServiceRequest.getInputsMap().set('inputs', tensorProto);

Mengirim permintaan gRPC ke TensorFlow Serving

Sekarang Anda dapat mengirimkan permintaan.

  • Tambahkan kode ini segera setelah kode di cabang gRPC dalam cuplikan kode sebelumnya:
// Send the gRPC request.
stub.predict(predictionServiceRequest, {}, function(err, response) {
    // TODO: Add code to process the response.
});

Memproses respons gRPC dari TensorFlow Serving

Terakhir, Anda menerapkan fungsi callback di atas untuk menangani respons.

  • Tambahkan kode ini ke isi fungsi di cuplikan kode sebelumnya:
// Process the gRPC response.
if (err) {
    console.log(err.code);
    console.log(err.message);
}
else {
    const maxIndex = argmax(response.getOutputsMap().get('logits').getFloatValList());
    document.getElementById('category').textContent = 'Predicted category: ' + maxIndex;
}

Sekarang pemroses mengekstrak probabilitas prediksi dari respons, mengidentifikasi kategori objek yang paling mungkin, dan menampilkan hasilnya di UI.

Menjalankan aplikasi

  1. Di terminal Anda, gunakan webpack untuk memaketkan semua file JavaScript ke dalam satu file yang dapat Anda sematkan dalam file index.html:
npx webpack
  1. Refresh http://localhost:8887/ di browser Anda.
  2. Klik gRPC > Classify.

Situs menampilkan prediksi kategori 286, yang dipetakan ke label Egyptian Cat di set data ImageNet.

9. Selamat

Anda menggunakan Penayangan TensorFlow untuk menambahkan kemampuan klasifikasi gambar ke situs Anda.

Pelajari lebih lanjut