สร้างแอป Android เพื่อตรวจหาออบเจ็กต์ภายในรูปภาพ

1. ก่อนเริ่มต้น

ในโค้ดแล็บนี้ คุณจะได้เรียนรู้วิธีเรียกใช้การอนุมานการตรวจหาออบเจ็กต์จากแอป Android โดยใช้ TensorFlow Serving กับ REST และ gRPC

ข้อกำหนดเบื้องต้น

  • มีความรู้พื้นฐานเกี่ยวกับการพัฒนาแอป Android ด้วย Java
  • ความรู้พื้นฐานเกี่ยวกับแมชชีนเลิร์นนิงด้วย TensorFlow เช่น การฝึกและการติดตั้งใช้งาน
  • ความรู้พื้นฐานเกี่ยวกับเทอร์มินัลและ Docker

สิ่งที่คุณจะได้เรียนรู้

  • วิธีค้นหาโมเดลการตรวจหาวัตถุที่ฝึกไว้ล่วงหน้าใน TensorFlow Hub
  • วิธีสร้างแอป Android อย่างง่ายและทำการคาดคะเนด้วยโมเดลการตรวจหาออบเจ็กต์ที่ดาวน์โหลดผ่าน TensorFlow Serving (REST และ gRPC)
  • วิธีแสดงผลการตรวจจับใน UI

สิ่งที่คุณต้องมี

2. ตั้งค่า

วิธีดาวน์โหลดโค้ดสำหรับ Codelab นี้

  1. ไปที่ที่เก็บ GitHub สำหรับ Codelab นี้
  2. คลิกโค้ด > ดาวน์โหลด ZIP เพื่อดาวน์โหลดโค้ดทั้งหมดสำหรับ Codelab นี้

a72f2bb4caa9a96.png

  1. แตกไฟล์ ZIP ที่ดาวน์โหลดเพื่อคลายโฟลเดอร์รูท codelabs ที่มีทรัพยากรทั้งหมดที่คุณต้องการ

สำหรับโค้ดแล็บนี้ คุณจะต้องใช้เฉพาะไฟล์ในไดเรกทอรีย่อย TFServing/ObjectDetectionAndroid ในที่เก็บ ซึ่งมี 2 โฟลเดอร์ ได้แก่

  • โฟลเดอร์ starter มีโค้ดเริ่มต้นที่คุณจะใช้ต่อยอดสำหรับโค้ดแล็บนี้
  • โฟลเดอร์ finished มีโค้ดที่เสร็จสมบูรณ์สำหรับแอปตัวอย่างที่เสร็จแล้ว

3. เพิ่มการขึ้นต่อกันลงในโปรเจ็กต์

นำเข้าแอปเริ่มต้นไปยัง Android Studio

  • ใน Android Studio ให้คลิกไฟล์ > ใหม่ > นำเข้าโปรเจ็กต์ แล้วเลือกโฟลเดอร์ starter จากซอร์สโค้ดที่คุณดาวน์โหลดไว้ก่อนหน้านี้

เพิ่มการอ้างอิงสำหรับ OkHttp และ gRPC

  • ในไฟล์ app/build.gradle ของโปรเจ็กต์ ให้ยืนยันว่ามีทรัพยากร Dependency
dependencies {
  // ...
    implementation 'com.squareup.okhttp3:okhttp:4.9.0'
    implementation 'javax.annotation:javax.annotation-api:1.3.2'
    implementation 'io.grpc:grpc-okhttp:1.29.0'
    implementation 'io.grpc:grpc-protobuf-lite:1.29.0'
    implementation 'io.grpc:grpc-stub:1.29.0'
}

ซิงค์โปรเจ็กต์กับไฟล์ Gradle

  • เลือก 541e90b497a7fef7.png Sync Project with Gradle Files จากเมนูการนำทาง

4. เรียกใช้แอปเริ่มต้น

เรียกใช้และสำรวจแอป

แอปควรเปิดขึ้นในอุปกรณ์ Android UI นั้นตรงไปตรงมามาก มีรูปภาพแมวที่คุณต้องการตรวจหาออบเจ็กต์ และผู้ใช้สามารถเลือกวิธีส่งข้อมูลไปยังแบ็กเอนด์ด้วย REST หรือ gRPC แบ็กเอนด์จะตรวจหาออบเจ็กต์ในรูปภาพและแสดงผลการตรวจหาไปยังแอปไคลเอ็นต์ ซึ่งจะแสดงผล UI อีกครั้ง

24eab579530e9645.png

ตอนนี้หากคุณคลิกเรียกใช้การอนุมาน จะไม่มีอะไรเกิดขึ้น เนื่องจากยังสื่อสารกับแบ็กเอนด์ไม่ได้

5. ติดตั้งใช้งานโมเดลการตรวจหาออบเจ็กต์ด้วย TensorFlow Serving

การตรวจหาวัตถุเป็นงาน ML ที่พบได้บ่อยมาก โดยมีเป้าหมายเพื่อตรวจหาวัตถุภายในรูปภาพ กล่าวคือ เพื่อคาดการณ์หมวดหมู่ที่เป็นไปได้ของวัตถุและกรอบล้อมรอบวัตถุ ตัวอย่างผลการตรวจหา

a68f9308fb2fc17b.png

Google ได้เผยแพร่โมเดลที่ผ่านการฝึกมาก่อนจำนวนหนึ่งใน TensorFlow Hub หากต้องการดูรายการทั้งหมด โปรดไปที่หน้า object_detection คุณใช้โมเดล SSD MobileNet V2 FPNLite 320x320 ที่มีน้ำหนักเบาพอสมควรสำหรับโค้ดแล็บนี้ เพื่อให้คุณไม่จำเป็นต้องใช้ GPU ในการเรียกใช้

หากต้องการติดตั้งใช้งานโมเดลตรวจจับออบเจ็กต์ด้วย TensorFlow Serving ให้ทำดังนี้

  1. ดาวน์โหลดไฟล์โมเดล
  2. คลายการบีบอัดไฟล์ .tar.gz ที่ดาวน์โหลดด้วยเครื่องมือคลายการบีบอัด เช่น 7-Zip
  3. สร้างssd_mobilenet_v2_2_320โฟลเดอร์ แล้วสร้าง123โฟลเดอร์ย่อยภายใน
  4. วางโฟลเดอร์ variables และไฟล์ saved_model.pb ที่แยกออกมาไว้ในโฟลเดอร์ย่อย 123

คุณอ้างอิงโฟลเดอร์ ssd_mobilenet_v2_2_320 เป็นโฟลเดอร์ SavedModel ได้ 123 เป็นตัวอย่างหมายเลขเวอร์ชัน หากต้องการ คุณเลือกหมายเลขอื่นได้

โครงสร้างโฟลเดอร์ควรมีลักษณะดังรูปภาพนี้

42c8150a42033767.png

เริ่ม TensorFlow Serving

  • ในเทอร์มินัล ให้เริ่ม TensorFlow Serving ด้วย Docker แต่แทนที่ตัวยึดตำแหน่ง PATH/TO/SAVEDMODEL ด้วยเส้นทางแบบสัมบูรณ์ของโฟลเดอร์ ssd_mobilenet_v2_2_320 ในคอมพิวเตอร์
docker pull tensorflow/serving

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

Docker จะดาวน์โหลดอิมเมจ TensorFlow Serving โดยอัตโนมัติก่อน ซึ่งจะใช้เวลา 1 นาที หลังจากนั้น TensorFlow Serving ควรจะเริ่มทำงาน โดยบันทึกควรมีลักษณะดังข้อมูลโค้ดต่อไปนี้

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/ssd_mobilenet_v2_2/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/ssd_mobilenet_v2_2/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: ssd_mobilenet_v2_2 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. เชื่อมต่อแอป Android กับ TensorFlow Serving ผ่าน REST

ตอนนี้แบ็กเอนด์พร้อมแล้ว คุณจึงส่งคำขอของไคลเอ็นต์ไปยัง TensorFlow Serving เพื่อตรวจหาออบเจ็กต์ภายในรูปภาพได้ คุณส่งคำขอไปยัง TensorFlow Serving ได้ 2 วิธีดังนี้

  • REST
  • gRPC

ส่งคำขอและรับการตอบกลับผ่าน REST

โดยมี 3 ขั้นตอนง่ายๆ ดังนี้

  • สร้างคำขอ REST
  • ส่งคำขอ REST ไปยัง TensorFlow Serving
  • ดึงผลลัพธ์ที่คาดการณ์ไว้จากการตอบกลับ REST และแสดงผล UI

คุณจะทำสิ่งเหล่านี้ได้ใน MainActivity.java.

สร้างคำขอ REST

ตอนนี้มีฟังก์ชัน createRESTRequest() ว่างเปล่าในไฟล์ MainActivity.java คุณใช้ฟังก์ชันนี้เพื่อสร้างคำขอ REST

private Request createRESTRequest() {
}

TensorFlow Serving คาดหวังคำขอ POST ที่มีเทนเซอร์รูปภาพสำหรับโมเดล SSD MobileNet ที่คุณใช้ ดังนั้นคุณจึงต้องดึงค่า RGB จากแต่ละพิกเซลของรูปภาพลงในอาร์เรย์ แล้วห่ออาร์เรย์ใน JSON ซึ่งเป็นเพย์โหลดของคำขอ

  • เพิ่มโค้ดนี้ลงในฟังก์ชัน createRESTRequest()
//Create the REST request.
int[] inputImg = new int[INPUT_IMG_HEIGHT * INPUT_IMG_WIDTH];
int[][][][] inputImgRGB = new int[1][INPUT_IMG_HEIGHT][INPUT_IMG_WIDTH][3];
inputImgBitmap.getPixels(inputImg, 0, INPUT_IMG_WIDTH, 0, 0, INPUT_IMG_WIDTH, INPUT_IMG_HEIGHT);
int pixel;
for (int i = 0; i < INPUT_IMG_HEIGHT; i++) {
    for (int j = 0; j < INPUT_IMG_WIDTH; j++) {
    // Extract RBG values from each pixel; alpha is ignored
    pixel = inputImg[i * INPUT_IMG_WIDTH + j];
    inputImgRGB[0][i][j][0] = ((pixel >> 16) & 0xff);
    inputImgRGB[0][i][j][1] = ((pixel >> 8) & 0xff);
    inputImgRGB[0][i][j][2] = ((pixel) & 0xff);
    }
}

RequestBody requestBody =
    RequestBody.create("{\"instances\": " + Arrays.deepToString(inputImgRGB) + "}", JSON);

Request request =
    new Request.Builder()
        .url("http://" + SERVER + ":" + REST_PORT + "/v1/models/" + MODEL_NAME + ":predict")
        .post(requestBody)
        .build();

return request;    

ส่งคำขอ REST ไปยัง TensorFlow Serving

แอปนี้ช่วยให้ผู้ใช้เลือก REST หรือ gRPC เพื่อสื่อสารกับ TensorFlow Serving ได้ จึงมี 2 สาขาในเครื่องฟัง onClick(View view)

predictButton.setOnClickListener(
    new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (requestRadioGroup.getCheckedRadioButtonId() == R.id.rest) {
                // TODO: REST request
            }
            else {

            }
        }
    }
)
  • เพิ่มโค้ดนี้ลงในกิ่ง REST ของonClick(View view) Listener เพื่อใช้ OkHttp ในการส่งคำขอไปยัง TensorFlow Serving
// Send the REST request.
Request request = createRESTRequest();
try {
    client =
        new OkHttpClient.Builder()
            .connectTimeout(20, TimeUnit.SECONDS)
            .writeTimeout(20, TimeUnit.SECONDS)
            .readTimeout(20, TimeUnit.SECONDS)
            .callTimeout(20, TimeUnit.SECONDS)
            .build();
    Response response = client.newCall(request).execute();
    JSONObject responseObject = new JSONObject(response.body().string());
    postprocessRESTResponse(responseObject);
} catch (IOException | JSONException e) {
    Log.e(TAG, e.getMessage());
    responseTextView.setText(e.getMessage());
    return;
}

ประมวลผลการตอบกลับ REST จาก TensorFlow Serving

โมเดล SSD MobileNet จะแสดงผลลัพธ์จำนวนหนึ่ง ซึ่งรวมถึง

  • num_detections: จำนวนการตรวจหา
  • detection_scores: คะแนนการตรวจหา
  • detection_classes: ดัชนีคลาสการตรวจหา
  • detection_boxes: พิกัดกรอบล้อมรอบ

คุณใช้ฟังก์ชัน postprocessRESTResponse() เพื่อจัดการการตอบกลับ

private void postprocessRESTResponse(Predict.PredictResponse response) {

}
  • เพิ่มโค้ดนี้ลงในฟังก์ชัน postprocessRESTResponse()
// Process the REST response.
JSONArray predictionsArray = responseObject.getJSONArray("predictions");
//You only send one image, so you directly extract the first element.
JSONObject predictions = predictionsArray.getJSONObject(0);
// Argmax
int maxIndex = 0;
JSONArray detectionScores = predictions.getJSONArray("detection_scores");
for (int j = 0; j < predictions.getInt("num_detections"); j++) {
    maxIndex =
        detectionScores.getDouble(j) > detectionScores.getDouble(maxIndex + 1) ? j : maxIndex;
}
int detectionClass = predictions.getJSONArray("detection_classes").getInt(maxIndex);
JSONArray boundingBox = predictions.getJSONArray("detection_boxes").getJSONArray(maxIndex);
double ymin = boundingBox.getDouble(0);
double xmin = boundingBox.getDouble(1);
double ymax = boundingBox.getDouble(2);
double xmax = boundingBox.getDouble(3);
displayResult(detectionClass, (float) ymin, (float) xmin, (float) ymax, (float) xmax);

ตอนนี้ฟังก์ชันหลังการประมวลผลจะดึงค่าที่คาดการณ์ไว้จากการตอบกลับ ระบุหมวดหมู่ของออบเจ็กต์ที่มีแนวโน้มมากที่สุดและพิกัดของจุดยอดของกรอบล้อมรอบ และสุดท้ายคือแสดงผลกรอบล้อมรอบการตรวจหาใน UI

เรียกใช้

  1. คลิก execute.png เรียกใช้ "แอป" ในเมนูการนำทาง แล้วรอให้แอปโหลด
  2. เลือก REST > เรียกใช้การอนุมาน

แอปจะใช้เวลา 2-3 วินาทีก่อนที่จะแสดงกล่องขอบเขตของแมวและแสดง 17 เป็นหมวดหมู่ของออบเจ็กต์ ซึ่งแมปกับออบเจ็กต์ cat ในชุดข้อมูล COCO

5a1a32768dc516d6.png

7. เชื่อมต่อแอป Android กับ TensorFlow Serving ผ่าน gRPC

นอกจาก REST แล้ว TensorFlow Serving ยังรองรับ gRPC ด้วย

b6f4449c2c850b0e.png

gRPC เป็นเฟรมเวิร์กการเรียกกระบวนการระยะไกล (RPC) ที่ทันสมัย โอเพนซอร์ส และมีประสิทธิภาพสูง ซึ่งสามารถทำงานได้ในทุกสภาพแวดล้อม โดยจะเชื่อมต่อบริการในและทั่วทั้งศูนย์ข้อมูลได้อย่างมีประสิทธิภาพ พร้อมรองรับการเสียบปลั๊กสำหรับ Load Balancing, การติดตาม, การตรวจสอบสถานะ และการตรวจสอบสิทธิ์ เราพบว่าในทางปฏิบัติ gRPC มีประสิทธิภาพมากกว่า REST

ส่งคำขอและรับการตอบกลับด้วย gRPC

โดยมี 4 ขั้นตอนง่ายๆ ดังนี้

  • [ไม่บังคับ] สร้างโค้ดสตับไคลเอ็นต์ gRPC
  • สร้างคำขอ gRPC
  • ส่งคำขอ gRPC ไปยัง TensorFlow Serving
  • ดึงผลลัพธ์ที่คาดการณ์จากการตอบกลับของ gRPC และแสดงผล UI

คุณจะทำสิ่งเหล่านี้ได้ใน MainActivity.java.

ไม่บังคับ: สร้างโค้ดสตับไคลเอ็นต์ gRPC

หากต้องการใช้ gRPC กับ TensorFlow Serving คุณต้องทำตามเวิร์กโฟลว์ gRPC ดูรายละเอียดเพิ่มเติมได้ในเอกสารประกอบของ gRPC

a9d0e5cb543467b4.png

TensorFlow Serving และ TensorFlow จะกำหนด.protoไฟล์ให้คุณ ตั้งแต่ TensorFlow และ TensorFlow Serving 2.8 เป็นต้นไป .protoไฟล์ต่อไปนี้คือไฟล์ที่จำเป็น

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
  • หากต้องการสร้าง Stub ให้เพิ่มโค้ดนี้ลงในไฟล์ app/build.gradle
apply plugin: 'com.google.protobuf'

protobuf {
    protoc { artifact = 'com.google.protobuf:protoc:3.11.0' }
    plugins {
        grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.29.0'
        }
    }
    generateProtoTasks {
        all().each { task ->
            task.builtins {
                java { option 'lite' }
            }
            task.plugins {
                grpc { option 'lite' }
            }
        }
    }
}

สร้างคำขอ gRPC

คุณสร้างคำขอ gRPC ในฟังก์ชัน createGRPCRequest() เช่นเดียวกับคำขอ REST

private Request createGRPCRequest() {

}
  • เพิ่มโค้ดนี้ลงในฟังก์ชัน createGRPCRequest()
if (stub == null) {
  channel = ManagedChannelBuilder.forAddress(SERVER, GRPC_PORT).usePlaintext().build();
  stub = PredictionServiceGrpc.newBlockingStub(channel);
}

Model.ModelSpec.Builder modelSpecBuilder = Model.ModelSpec.newBuilder();
modelSpecBuilder.setName(MODEL_NAME);
modelSpecBuilder.setVersion(Int64Value.of(MODEL_VERSION));
modelSpecBuilder.setSignatureName(SIGNATURE_NAME);

Predict.PredictRequest.Builder builder = Predict.PredictRequest.newBuilder();
builder.setModelSpec(modelSpecBuilder);

TensorProto.Builder tensorProtoBuilder = TensorProto.newBuilder();
tensorProtoBuilder.setDtype(DataType.DT_UINT8);
TensorShapeProto.Builder tensorShapeBuilder = TensorShapeProto.newBuilder();
tensorShapeBuilder.addDim(TensorShapeProto.Dim.newBuilder().setSize(1));
tensorShapeBuilder.addDim(TensorShapeProto.Dim.newBuilder().setSize(INPUT_IMG_HEIGHT));
tensorShapeBuilder.addDim(TensorShapeProto.Dim.newBuilder().setSize(INPUT_IMG_WIDTH));
tensorShapeBuilder.addDim(TensorShapeProto.Dim.newBuilder().setSize(3));
tensorProtoBuilder.setTensorShape(tensorShapeBuilder.build());
int[] inputImg = new int[INPUT_IMG_HEIGHT * INPUT_IMG_WIDTH];
inputImgBitmap.getPixels(inputImg, 0, INPUT_IMG_WIDTH, 0, 0, INPUT_IMG_WIDTH, INPUT_IMG_HEIGHT);
int pixel;
for (int i = 0; i < INPUT_IMG_HEIGHT; i++) {
    for (int j = 0; j < INPUT_IMG_WIDTH; j++) {
    // Extract RBG values from each pixel; alpha is ignored.
    pixel = inputImg[i * INPUT_IMG_WIDTH + j];
    tensorProtoBuilder.addIntVal((pixel >> 16) & 0xff);
    tensorProtoBuilder.addIntVal((pixel >> 8) & 0xff);
    tensorProtoBuilder.addIntVal((pixel) & 0xff);
    }
}
TensorProto tensorProto = tensorProtoBuilder.build();

builder.putInputs("input_tensor", tensorProto);

builder.addOutputFilter("num_detections");
builder.addOutputFilter("detection_boxes");
builder.addOutputFilter("detection_classes");
builder.addOutputFilter("detection_scores");

return builder.build();

ส่งคำขอ gRPC ไปยัง TensorFlow Serving

ตอนนี้คุณสามารถทำonClick(View view)ให้เสร็จสมบูรณ์ได้แล้ว

predictButton.setOnClickListener(
    new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (requestRadioGroup.getCheckedRadioButtonId() == R.id.rest) {

            }
            else {
                // TODO: gRPC request
            }
        }
    }
)
  • เพิ่มโค้ดนี้ลงในสาขา gRPC
try {
    Predict.PredictRequest request = createGRPCRequest();
    Predict.PredictResponse response = stub.predict(request);
    postprocessGRPCResponse(response);
} catch (Exception e) {
    Log.e(TAG, e.getMessage());
    responseTextView.setText(e.getMessage());
    return;
}

ประมวลผลการตอบกลับ gRPC จาก TensorFlow Serving

คุณจะใช้ฟังก์ชัน postprocessGRPCResponse() เพื่อจัดการการตอบกลับได้เช่นเดียวกับ gRPC

private void postprocessGRPCResponse(Predict.PredictResponse response) {

}
  • เพิ่มโค้ดนี้ลงในฟังก์ชัน postprocessGRPCResponse()
// Process the response.
float numDetections = response.getOutputsMap().get("num_detections").getFloatValList().get(0);
List<Float> detectionScores =    response.getOutputsMap().get("detection_scores").getFloatValList();
int maxIndex = 0;
for (int j = 0; j < numDetections; j++) {
    maxIndex = detectionScores.get(j) > detectionScores.get(maxIndex + 1) ? j : maxIndex;
}
Float detectionClass =    response.getOutputsMap().get("detection_classes").getFloatValList().get(maxIndex);
List<Float> boundingBoxValues =    response.getOutputsMap().get("detection_boxes").getFloatValList();
float ymin = boundingBoxValues.get(maxIndex * 4);
float xmin = boundingBoxValues.get(maxIndex * 4 + 1);
float ymax = boundingBoxValues.get(maxIndex * 4 + 2);
float xmax = boundingBoxValues.get(maxIndex * 4 + 3);
displayResult(detectionClass.intValue(), ymin, xmin, ymax, xmax);

ตอนนี้ฟังก์ชันการประมวลผลภายหลังสามารถดึงค่าที่คาดการณ์จากคำตอบและแสดงกล่องขอบเขตการตรวจหาใน UI ได้แล้ว

เรียกใช้

  1. คลิก execute.png เรียกใช้ "แอป" ในเมนูการนำทาง แล้วรอให้แอปโหลด
  2. เลือก gRPC > เรียกใช้การอนุมาน

แอปจะใช้เวลา 2-3 วินาทีก่อนที่จะแสดงกล่องขอบเขตของแมวและแสดง 17 เป็นหมวดหมู่ของออบเจ็กต์ ซึ่งแมปกับหมวดหมู่ cat ในชุดข้อมูล COCO

8. ขอแสดงความยินดี

คุณใช้ TensorFlow Serving เพื่อเพิ่มความสามารถในการตรวจหาออบเจ็กต์ลงในแอป

ดูข้อมูลเพิ่มเติม