Görüntüleri sınıflandıran basit bir web sitesi oluşturma

1. Başlamadan önce

Bu codelab'de, REST ve gRPC ile TensorFlow Serving kullanarak bir web sitesinden görüntü sınıflandırma çıkarımı çalıştırmayı öğreneceksiniz.

Ön koşullar

  • HTML ve JavaScript gibi web geliştirme konusunda temel bilgiler
  • Eğitim ve dağıtım gibi TensorFlow ile makine öğrenimi hakkında temel bilgiler
  • Terminaller ve Docker hakkında temel bilgiler

Neler öğreneceksiniz?

  • TensorFlow Hub'da önceden eğitilmiş görüntü sınıflandırma modellerini bulma
  • TensorFlow Serving (REST ve gRPC) aracılığıyla indirilen görüntü sınıflandırma modeliyle basit bir web sitesi oluşturma ve tahmin yapma
  • Algılama sonucunu kullanıcı arayüzünde nasıl oluşturacağınız.

İhtiyacınız olanlar

2. Hazırlanın

Bu codelab'in kodunu indirmek için:

  1. Bu GitHub deposuna gidin.
  2. Bu codelab'in tüm kodunu indirmek için Code > Download zip'i (Kod > Zip dosyasını indir) tıklayın.

a72f2bb4caa9a96.png

  1. İndirilen ZIP dosyasını açarak ihtiyacınız olan tüm kaynakların bulunduğu bir codelabs kök klasörünü çıkarın.

Bu codelab için depodaki TFServing/ImageClassificationWeb alt dizinindeki dosyalar yeterlidir. Bu dizinde iki klasör bulunur:

  • starter klasörü, bu codelab'de temel alacağınız başlangıç kodunu içerir.
  • finished klasöründe, tamamlanmış örnek uygulamanın kodu yer alır.

3. Bağımlılıkları yükleyin

Bağımlılıkları yüklemek için:

  • Terminalinizde starter klasörüne gidin ve gerekli NPM paketlerini yükleyin:
npm install

4. Başlangıç web sitesini çalıştırma

TFServing/ImageClassificationWeb/starter/dist/index.html dosyasını yüklemek için Web Server for Chrome'u kullanın:

  1. Chrome'un adres çubuğuna Chrome://apps/ yazın ve uygulama listesinde Web Server for Chrome'u bulun.
  2. Web Server for Chrome'u başlatın ve TFServing/ImageClassificationWeb/starter/dist/ klasörünü seçin.
  3. Etkinleştirmek için Web Sunucusu açma/kapatma düğmesini tıklayın ve tarayıcınızda http://localhost:8887/ adresine gidin.

f7b43cd44ebf1f1b.png

Web sitesini çalıştırma ve keşfetme

Web sitesini artık görmeniz gerekir. Kullanıcı arayüzü oldukça basittir: Sınıflandırmak istediğiniz bir kedi resmi vardır ve kullanıcı, verileri REST veya gRPC ile arka uca gönderebilir. Arka uç, görüntü üzerinde görüntü sınıflandırması gerçekleştirir ve sınıflandırma sonucunu, sonucu görüntüleyen web sitesine döndürür.

837d97a27c59a0b3.png

Sınıflandır'ı tıkladığınızda henüz arka uçla iletişim kurulamadığından hiçbir şey olmaz.

5. TensorFlow Serving ile görüntü sınıflandırma modeli dağıtma

Görüntü sınıflandırma, bir görüntüyü, görüntünün birincil içeriğine göre önceden tanımlanmış kategorilere sınıflandıran çok yaygın bir makine öğrenimi görevidir. Çiçekleri sınıflandırma örneğini aşağıda görebilirsiniz:

a6da16b4a7665db0.png

TensorFlow Hub'da önceden eğitilmiş çeşitli görüntü sınıflandırma modelleri bulunur. Bu codelab'de popüler bir Inception v3 modeli kullanacaksınız.

TensorFlow Serving ile görüntü sınıflandırma modelini dağıtmak için:

  1. Inception v3 model dosyasını indirin.
  2. İndirilen .tar.gz dosyasını 7-Zip gibi bir sıkıştırma açma aracıyla açın.
  3. inception_v3 klasörü oluşturun ve ardından bu klasörün içinde bir 123 alt klasörü oluşturun.
  4. Ayıklanan variables klasörünü ve saved_model.pb dosyasını 123 alt klasörüne yerleştirin.

inception_v3 klasörünü SavedModel klasörü olarak adlandırabilirsiniz. 123, örnek bir sürüm numarasıdır. İsterseniz başka bir numara seçebilirsiniz.

Klasör yapısı aşağıdaki resimdeki gibi olmalıdır:

21a8675ac8d31907.png

TensorFlow Serving'i başlatma

  • Terminalinizde, Docker ile TensorFlow Serving'i başlatın ancak PATH/TO/SAVEDMODEL yerine bilgisayarınızdaki inception_v3 klasörünün mutlak yolunu kullanın.
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, önce TensorFlow Serving görüntüsünü otomatik olarak indirir. Bu işlem bir dakika sürer. Ardından TensorFlow Serving başlatılmalıdır. Günlük, aşağıdaki kod snippet'i gibi görünmelidir:

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. Envoy proxy'yi ayarlama

TensorFlow Serving şu anda Access-Control-Allow-Origin üstbilgisini ayarlamadığı için tarayıcı, güvenlik nedeniyle ön uç JavaScript'inden TensorFlow Serving'e yapılan isteği engelliyor. Bu sorunu çözmek için JavaScript'ten TensorFlow Serving arka ucuna yapılan isteği proxy'lemek üzere Envoy gibi bir proxy kullanmanız gerekir.

Envoy'u başlatma

  • Terminalinizde Envoy görüntüsünü indirin ve Docker ile Envoy'u başlatın. Ancak PATH/TO/ENVOY-CUSTOM.YAML yer tutucusunu starter klasöründeki envoy-custom.yaml dosyasının mutlak yoluyla değiştirin.
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, önce Envoy görüntüsünü otomatik olarak indirir. Ardından Envoy başlatılmalıdır. Günlük, aşağıdaki kod snippet'i gibi görünmelidir:

[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. REST aracılığıyla web sitesini TensorFlow'a bağlama

Arka uç artık hazır olduğundan, görüntüleri sınıflandırmak için TensorFlow Serving'e istemci istekleri gönderebilirsiniz. TensorFlow Serving'e istek göndermenin iki yolu vardır:

  • REST
  • gRPC

REST üzerinden istek gönderme ve yanıt alma

REST üzerinden istek göndermek ve almak için üç basit adım vardır:

  1. REST isteğini oluşturun.
  2. REST isteğini TensorFlow Serving'e gönderin.
  3. Tahmin edilen sonucu REST yanıtından çıkarın ve sonucu gösterin.

Bu adımları src/index.js dosyasında gerçekleştirirsiniz.

REST isteğini oluşturma

Şu anda classify_img() işlevi, REST isteğini TensorFlow Serving'e göndermiyor. Öncelikle bir REST isteği oluşturmak için bu REST dalını uygulamanız gerekir:

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

} 

TensorFlow Serving, kullandığınız Inception v3 modeli için görüntü tensörünü içeren bir POST isteği bekler. Bu nedenle, görüntünün her pikselinden RGB değerlerini bir diziye çıkarmanız ve ardından diziyi isteğin yükü olan bir JSON'a sarmalamanız gerekir.

  • Bu kodu REST dalına ekleyin:
//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');
}

REST isteğini TensorFlow Serving'e gönderme

Artık isteği gönderebilirsiniz.

  • Bu kodu, REST dalında yukarıdaki kodun hemen sonrasına ekleyin:
// Send the REST request.
xhr.send(data);

TensorFlow Serving'den gelen REST yanıtını işleme

Inception v3 modeli, resmin önceden tanımlanmış kategorilere ait olma olasılıklarının bir dizisini döndürür. Tahmin başarılı olduğunda, kullanıcı arayüzünde en olası kategoriyi göstermeniz gerekir.

Yanıtı işlemek için onload() işleyicisini uygularsınız.

xhr.onload = () => {

}
  • Bu kodu onload() dinleyicisine ekleyin:
// Process the REST response.
const response = JSON.parse(xhr.responseText);
const maxIndex = argmax(response['predictions'][0])
document.getElementById('category').textContent = 'Predicted category: ' + maxIndex;

Dinleyici artık yanıttan tahmin edilen olasılıkları çıkarıyor, nesnenin en olası kategorisini tanımlıyor ve sonucu kullanıcı arayüzünde gösteriyor.

Çalıştırın

  1. Terminalinizde starter klasörüne gidin ve webpack'i kullanarak tüm JavaScript dosyalarını dist/index.html dosyasına yerleştirebileceğiniz tek bir dosyada paketleyin:
npm install -g npx
npm install --save-dev webpack
npx webpack
  1. Tarayıcınızda http://localhost:8887/ adresini yenileyin ve REST > Classify'ı (REST > Sınıflandır) tıklayın.

Web sitesi, ImageNet veri kümesindeki Egyptian Cat etiketine karşılık gelen 286 kategorisini tahmin edilen kategori olarak gösteriyor.

c865a93b9b58335d.png

8. Web sitesini gRPC aracılığıyla TensorFlow Serving'e bağlama

TensorFlow Serving, REST'in yanı sıra gRPC'yi de destekler.

b6f4449c2c850b0e.png

gRPC, herhangi bir ortamda çalışabilen modern, açık kaynaklı ve yüksek performanslı bir Uzak Prosedür Çağrısı (RPC) çerçevesidir. Yük dengeleme, izleme, sağlık kontrolü ve kimlik doğrulama için takılabilir destekle veri merkezlerindeki ve veri merkezleri arasındaki hizmetleri verimli bir şekilde bağlayabilir. gRPC'nin pratikte REST'ten daha iyi performans gösterdiği gözlemlenmiştir.

gRPC ile istek gönderme ve yanıt alma

Dört basit adım vardır:

  1. İsteğe bağlı: gRPC istemci taslağı kodunu oluşturun.
  2. gRPC isteğini oluşturun.
  3. gRPC isteğini TensorFlow Serving'e gönderin.
  4. Tahmin edilen sonucu gRPC yanıtından çıkarın ve kullanıcı arayüzünde gösterin.

Bu adımları src/index.js dosyasında tamamlarsınız.

İsteğe bağlı: gRPC istemci taslağı kodunu oluşturma

TensorFlow Serving ile gRPC'yi kullanmak için gRPC iş akışını uygulamanız gerekir. Ayrıntılar hakkında daha fazla bilgi edinmek için gRPC belgelerine bakın.

a9d0e5cb543467b4.png

TensorFlow Serving ve TensorFlow, .proto dosyalarını sizin için tanımlar. TensorFlow ve TensorFlow Serving 2.8'den itibaren şu .proto dosyaları gereklidir:

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
  • Terminalinizde starter/src/proto/ klasörüne gidin ve sap oluşturun:
bash generate_grpc_stub_js.sh

gRPC isteğini oluşturma

REST isteğine benzer şekilde, gRPC isteğini gRPC dalında oluşturursunuz..

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

}
else {
    print("Using gRPC")
    // TODO: Add code to send a gRPC request to TensorFlow Serving.
    
}
  • Bu kodu gRPC dalına ekleyin:
// 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);

gRPC isteğini TensorFlow Serving'e gönderme

Artık isteği gönderebilirsiniz.

  • Bu kodu, önceki kod snippet'indeki gRPC dalındaki kodun hemen sonrasına ekleyin:
// Send the gRPC request.
stub.predict(predictionServiceRequest, {}, function(err, response) {
    // TODO: Add code to process the response.
});

TensorFlow Serving'den gelen gRPC yanıtını işleme

Son olarak, yanıtı işlemek için yukarıdaki geri çağırma işlevini uygularsınız.

  • Bu kodu, önceki kod snippet'indeki işlev gövdesine ekleyin:
// 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;
}

Dinleyici artık yanıttan tahmin edilen olasılıkları çıkarıyor, nesnenin en olası kategorisini tanımlıyor ve sonucu kullanıcı arayüzünde gösteriyor.

Çalıştırın

  1. Terminalinizde, tüm JavaScript dosyalarını index.html dosyasına yerleştirebileceğiniz tek bir dosyada paketlemek için webpack'i kullanın:
npx webpack
  1. Tarayıcınızda http://localhost:8887/ adresini yenileyin.
  2. gRPC > Classify'ı (Sınıflandır) tıklayın.

Web sitesinde, ImageNet veri kümesindeki Egyptian Cat etiketine karşılık gelen 286 tahmini kategorisi gösteriliyor.

9. Tebrikler

Web sitenize görüntü sınıflandırma özellikleri eklemek için TensorFlow Serving'i kullandınız.

Daha fazla bilgi