ประมวลผลข้อมูลอินพุตและเอาต์พุตด้วย TensorFlow Lite Support Library

นักพัฒนาแอปพลิเคชันบนมือถือมักจะโต้ตอบกับวัตถุที่พิมพ์ เช่น บิตแมปหรือข้อมูลพื้นฐาน เช่น จำนวนเต็ม อย่างไรก็ตาม API ล่าม TensorFlow Lite ที่รันโมเดลแมชชีนเลิร์นนิงในอุปกรณ์ใช้เทนเซอร์ในรูปแบบของ ByteBuffer ซึ่งอาจแก้ไขจุดบกพร่องและจัดการได้ยาก ไลบรารีการสนับสนุน Android TensorFlow Lite ได้รับการออกแบบมาเพื่อช่วยประมวลผลอินพุตและเอาต์พุตของโมเดล TensorFlow Lite และทำให้ล่าม TensorFlow Lite ใช้งานง่ายขึ้น

เริ่มต้นใช้งาน

นำเข้าการพึ่งพา Gradle และการตั้งค่าอื่นๆ

คัดลอกไฟล์โมเดล .tflite ไปยังไดเร็กทอรีทรัพย์สินของโมดูล Android ที่จะเรียกใช้โมเดล ระบุว่าไม่ควรบีบอัดไฟล์ และเพิ่มไลบรารี TensorFlow Lite ลงในไฟล์ build.gradle ของโมดูล:

android {
    // Other settings

    // Specify tflite file should not be compressed for the app apk
    aaptOptions {
        noCompress "tflite"
    }

}

dependencies {
    // Other dependencies

    // Import tflite dependencies
    implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly-SNAPSHOT'
    // The GPU delegate library is optional. Depend on it as needed.
    implementation 'org.tensorflow:tensorflow-lite-gpu:0.0.0-nightly-SNAPSHOT'
    implementation 'org.tensorflow:tensorflow-lite-support:0.0.0-nightly-SNAPSHOT'
}

สำรวจ AAR ของ TensorFlow Lite Support Library ที่โฮสต์ที่ MavenCentral สำหรับ Support Library เวอร์ชันต่างๆ

การจัดการและการแปลงภาพขั้นพื้นฐาน

ไลบรารีการสนับสนุน TensorFlow Lite มีชุดวิธีจัดการรูปภาพพื้นฐาน เช่น การครอบตัดและการปรับขนาด หากต้องการใช้งาน ให้สร้าง ImagePreprocessor และเพิ่มการดำเนินการที่จำเป็น หากต้องการแปลงรูปภาพเป็นรูปแบบเทนเซอร์ที่ล่าม TensorFlow Lite ต้องการ ให้สร้าง TensorImage เพื่อใช้เป็นอินพุต:

import org.tensorflow.lite.DataType;
import org.tensorflow.lite.support.image.ImageProcessor;
import org.tensorflow.lite.support.image.TensorImage;
import org.tensorflow.lite.support.image.ops.ResizeOp;

// Initialization code
// Create an ImageProcessor with all ops required. For more ops, please
// refer to the ImageProcessor Architecture section in this README.
ImageProcessor imageProcessor =
    new ImageProcessor.Builder()
        .add(new ResizeOp(224, 224, ResizeOp.ResizeMethod.BILINEAR))
        .build();

// Create a TensorImage object. This creates the tensor of the corresponding
// tensor type (uint8 in this case) that the TensorFlow Lite interpreter needs.
TensorImage tensorImage = new TensorImage(DataType.UINT8);

// Analysis code for every frame
// Preprocess the image
tensorImage.load(bitmap);
tensorImage = imageProcessor.process(tensorImage);

DataType ของเทนเซอร์สามารถอ่านได้ผ่าน ไลบรารีตัวแยกข้อมูลเมตา และข้อมูลโมเดลอื่นๆ

การประมวลผลข้อมูลเสียงขั้นพื้นฐาน

ไลบรารีการสนับสนุน TensorFlow Lite ยังกำหนดคลาส TensorAudio ที่รวมวิธีการประมวลผลข้อมูลเสียงพื้นฐานบางอย่างไว้ด้วย ส่วนใหญ่จะใช้ร่วมกับ AudioRecord และจับตัวอย่างเสียงในบัฟเฟอร์แบบวงแหวน

import android.media.AudioRecord;
import org.tensorflow.lite.support.audio.TensorAudio;

// Create an `AudioRecord` instance.
AudioRecord record = AudioRecord(...)

// Create a `TensorAudio` object from Android AudioFormat.
TensorAudio tensorAudio = new TensorAudio(record.getFormat(), size)

// Load all audio samples available in the AudioRecord without blocking.
tensorAudio.load(record)

// Get the `TensorBuffer` for inference.
TensorBuffer buffer = tensorAudio.getTensorBuffer()

สร้างวัตถุเอาท์พุตและรันโมเดล

ก่อนที่จะรันโมเดล เราจำเป็นต้องสร้างออบเจ็กต์คอนเทนเนอร์ที่จะเก็บผลลัพธ์:

import org.tensorflow.lite.DataType;
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer;

// Create a container for the result and specify that this is a quantized model.
// Hence, the 'DataType' is defined as UINT8 (8-bit unsigned integer)
TensorBuffer probabilityBuffer =
    TensorBuffer.createFixedSize(new int[]{1, 1001}, DataType.UINT8);

กำลังโหลดโมเดลและการอนุมานที่กำลังรันอยู่:

import java.nio.MappedByteBuffer;
import org.tensorflow.lite.InterpreterFactory;
import org.tensorflow.lite.InterpreterApi;

// Initialise the model
try{
    MappedByteBuffer tfliteModel
        = FileUtil.loadMappedFile(activity,
            "mobilenet_v1_1.0_224_quant.tflite");
    InterpreterApi tflite = new InterpreterFactory().create(
        tfliteModel, new InterpreterApi.Options());
} catch (IOException e){
    Log.e("tfliteSupport", "Error reading model", e);
}

// Running inference
if(null != tflite) {
    tflite.run(tImage.getBuffer(), probabilityBuffer.getBuffer());
}

การเข้าถึงผลลัพธ์

นักพัฒนาสามารถเข้าถึงเอาต์พุตได้โดยตรงผ่าน probabilityBuffer.getFloatArray() หากโมเดลสร้างเอาต์พุตเชิงปริมาณ อย่าลืมแปลงผลลัพธ์ สำหรับโมเดลเชิงปริมาณของ MobileNet นักพัฒนาจำเป็นต้องหารค่าเอาท์พุตแต่ละค่าด้วย 255 เพื่อให้ได้ความน่าจะเป็นตั้งแต่ 0 (มีแนวโน้มน้อยที่สุด) ถึง 1 (มีแนวโน้มมากที่สุด) สำหรับแต่ละหมวดหมู่

ทางเลือก: การจับคู่ผลลัพธ์กับป้ายกำกับ

นักพัฒนายังสามารถเลือกแมปผลลัพธ์กับป้ายกำกับได้ ขั้นแรก ให้คัดลอกไฟล์ข้อความที่มีป้ายกำกับลงในไดเร็กทอรีทรัพย์สินของโมดูล ถัดไป โหลดไฟล์ฉลากโดยใช้รหัสต่อไปนี้:

import org.tensorflow.lite.support.common.FileUtil;

final String ASSOCIATED_AXIS_LABELS = "labels.txt";
List<String> associatedAxisLabels = null;

try {
    associatedAxisLabels = FileUtil.loadLabels(this, ASSOCIATED_AXIS_LABELS);
} catch (IOException e) {
    Log.e("tfliteSupport", "Error reading label file", e);
}

ตัวอย่างต่อไปนี้สาธิตวิธีเชื่อมโยงความน่าจะเป็นกับป้ายกำกับหมวดหมู่:

import java.util.Map;
import org.tensorflow.lite.support.common.TensorProcessor;
import org.tensorflow.lite.support.common.ops.NormalizeOp;
import org.tensorflow.lite.support.label.TensorLabel;

// Post-processor which dequantize the result
TensorProcessor probabilityProcessor =
    new TensorProcessor.Builder().add(new NormalizeOp(0, 255)).build();

if (null != associatedAxisLabels) {
    // Map of labels and their corresponding probability
    TensorLabel labels = new TensorLabel(associatedAxisLabels,
        probabilityProcessor.process(probabilityBuffer));

    // Create a map to access the result based on label
    Map<String, Float> floatMap = labels.getMapWithFloatValue();
}

ความครอบคลุมกรณีการใช้งานในปัจจุบัน

เวอร์ชันปัจจุบันของ TensorFlow Lite Support Library ครอบคลุมถึง:

  • ประเภทข้อมูลทั่วไป (float, uint8, รูปภาพ, เสียง และอาร์เรย์ของออบเจ็กต์เหล่านี้) เป็นอินพุตและเอาต์พุตของโมเดล tflite
  • การใช้งานรูปภาพขั้นพื้นฐาน (ครอบตัดรูปภาพ ปรับขนาด และหมุน)
  • การทำให้เป็นมาตรฐานและการหาปริมาณ
  • ไฟล์ยูทิลิตี้

เวอร์ชันในอนาคตจะปรับปรุงการรองรับแอปพลิเคชันที่เกี่ยวข้องกับข้อความ

สถาปัตยกรรมตัวประมวลผลภาพ

การออกแบบ ImageProcessor ช่วยให้สามารถกำหนดการดำเนินการจัดการรูปภาพล่วงหน้าและปรับให้เหมาะสมในระหว่างกระบวนการสร้าง ขณะนี้ ImageProcessor รองรับการดำเนินการประมวลผลล่วงหน้าขั้นพื้นฐานสามประการ ดังที่อธิบายไว้ในความคิดเห็นสามประการในข้อมูลโค้ดด้านล่าง:

import org.tensorflow.lite.support.common.ops.NormalizeOp;
import org.tensorflow.lite.support.common.ops.QuantizeOp;
import org.tensorflow.lite.support.image.ops.ResizeOp;
import org.tensorflow.lite.support.image.ops.ResizeWithCropOrPadOp;
import org.tensorflow.lite.support.image.ops.Rot90Op;

int width = bitmap.getWidth();
int height = bitmap.getHeight();

int size = height > width ? width : height;

ImageProcessor imageProcessor =
    new ImageProcessor.Builder()
        // Center crop the image to the largest square possible
        .add(new ResizeWithCropOrPadOp(size, size))
        // Resize using Bilinear or Nearest neighbour
        .add(new ResizeOp(224, 224, ResizeOp.ResizeMethod.BILINEAR));
        // Rotation counter-clockwise in 90 degree increments
        .add(new Rot90Op(rotateDegrees / 90))
        .add(new NormalizeOp(127.5, 127.5))
        .add(new QuantizeOp(128.0, 1/128.0))
        .build();

ดูรายละเอียดเพิ่มเติมเกี่ยวกับการทำให้เป็นมาตรฐานและการหาปริมาณ ได้ที่นี่

เป้าหมายสุดท้ายของไลบรารีการสนับสนุนคือการรองรับการแปลง tf.image ทั้งหมด ซึ่งหมายความว่าการเปลี่ยนแปลงจะเหมือนกับ TensorFlow และการนำไปใช้งานจะไม่ขึ้นอยู่กับระบบปฏิบัติการ

นักพัฒนายังยินดีที่จะสร้างโปรเซสเซอร์แบบกำหนดเองอีกด้วย ในกรณีเหล่านี้เป็นสิ่งสำคัญที่จะต้องสอดคล้องกับกระบวนการฝึกอบรม กล่าวคือ การประมวลผลล่วงหน้าแบบเดียวกันควรนำไปใช้กับทั้งการฝึกอบรมและการอนุมานเพื่อเพิ่มความสามารถในการทำซ้ำ

การหาปริมาณ

เมื่อเริ่มต้นออบเจ็กต์อินพุตหรือเอาต์พุต เช่น TensorImage หรือ TensorBuffer คุณต้องระบุประเภทให้เป็น DataType.UINT8 หรือ DataType.FLOAT32

TensorImage tensorImage = new TensorImage(DataType.UINT8);
TensorBuffer probabilityBuffer =
    TensorBuffer.createFixedSize(new int[]{1, 1001}, DataType.UINT8);

TensorProcessor สามารถใช้หาปริมาณเทนเซอร์อินพุตหรือแยกเทนเซอร์เอาท์พุตได้ ตัวอย่างเช่น เมื่อประมวลผลเอาต์พุต TensorBuffer เชิงปริมาณ นักพัฒนาสามารถใช้ DequantizeOp เพื่อแยกผลลัพธ์ออกเป็นความน่าจะเป็นจุดลอยตัวระหว่าง 0 ถึง 1:

import org.tensorflow.lite.support.common.TensorProcessor;

// Post-processor which dequantize the result
TensorProcessor probabilityProcessor =
    new TensorProcessor.Builder().add(new DequantizeOp(0, 1/255.0)).build();
TensorBuffer dequantizedBuffer = probabilityProcessor.process(probabilityBuffer);

พารามิเตอร์การหาปริมาณของเทนเซอร์สามารถอ่านได้ผ่าน ไลบรารีตัวแยกข้อมูลเมตา