معالجة بيانات المدخلات والمخرجات باستخدام مكتبة دعم TensorFlow Lite

يتفاعل مطورو تطبيقات الأجهزة المحمولة عادةً مع الكائنات المكتوبة مثل الصور النقطية أو العناصر الأولية مثل الأعداد الصحيحة. ومع ذلك، فإنّ واجهة برمجة التطبيقات TensorFlow Lite التي تشغّل نموذج تعلُّم الآلة على الجهاز تستخدم وحدات شدّة في شكل ByteBuffer، ما قد يصعُب تصحيحها ومعالجتها. تم تصميم TensorFlow Lite Android Support Library للمساعدة في معالجة إدخالات ومخرجات نماذج 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'
}

استكشِف TensorFlow Lite Support Library AAR الذي تمت استضافته في MavenCentral، للاطّلاع على إصدارات مختلفة من Support Library.

معالجة أساسية للصور وتحويلها

تحتوي مكتبة TensorFlow Lite Support Library على حزمة من الأساليب الأساسية لمعالجة الصور مثل الاقتصاص وتغيير الحجم. لاستخدامه، أنشِئ 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 Support Library أيضًا فئة 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 ما يلي:

  • أنواع البيانات الشائعة (float وuint8 والصور والصوت وصفيف هذه الكائنات) كمدخلات ومخرجات لنماذج tflite.
  • العمليات الأساسية للصور (اقتصاص الصورة وتغيير حجمها وتدويرها).
  • تسوية وتحديد الكمي
  • ملفات utils

ستعمل الإصدارات المستقبلية على تحسين التوافق مع التطبيقات ذات الصلة بالنصوص.

بنية معالج الصور

أتاح تصميم 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);

يمكن قراءة معلَمات تحديد الكمية للموت من خلال مكتبة أداة استخراج البيانات الوصفية.