توسعه دهندگان برنامه های موبایل معمولاً با اشیاء تایپ شده مانند بیت مپ یا موارد اولیه مانند اعداد صحیح تعامل دارند. با این حال، API مفسر LiteRT که مدل یادگیری ماشین روی دستگاه را اجرا میکند، از تانسورهایی به شکل ByteBuffer استفاده میکند که اشکالزدایی و دستکاری آن دشوار است. کتابخانه پشتیبانی Android LiteRT برای کمک به پردازش ورودی و خروجی مدلهای LiteRT و سهولت استفاده از مترجم LiteRT طراحی شده است.
شروع به کار
وابستگی Gradle و تنظیمات دیگر را وارد کنید
فایل مدل .tflite
را در فهرست داراییهای ماژول Android که در آن مدل اجرا میشود، کپی کنید. مشخص کنید که فایل نباید فشرده شود و کتابخانه LiteRT را به فایل 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 'com.google.ai.edge.litert:litert-gpu:0.0.0-nightly-SNAPSHOT'
implementation 'com.google.ai.edge.litert:litert-support:0.0.0-nightly-SNAPSHOT'
}
کتابخانه پشتیبانی LiteRT AAR میزبانی شده در MavenCentral را برای نسخههای مختلف کتابخانه پشتیبانی کاوش کنید.
دستکاری و تبدیل تصویر اولیه
کتابخانه پشتیبانی LiteRT مجموعهای از روشهای دستکاری تصویر مانند برش و تغییر اندازه دارد. برای استفاده از آن، یک ImagePreprocessor
ایجاد کنید و عملیات مورد نیاز را اضافه کنید. برای تبدیل تصویر به فرمت تانسور مورد نیاز مفسر LiteRT، یک 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 LiteRT interpreter needs.
TensorImage tensorImage = new TensorImage(DataType.UINT8);
// Analysis code for every frame
// Preprocess the image
tensorImage.load(bitmap);
tensorImage = imageProcessor.process(tensorImage);
DataType
تانسور را می توان از طریق کتابخانه استخراج کننده ابرداده و همچنین سایر اطلاعات مدل خواند.
پردازش داده های صوتی اولیه
کتابخانه پشتیبانی LiteRT همچنین یک کلاس 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();
}
پوشش مورد استفاده فعلی
نسخه فعلی کتابخانه پشتیبانی LiteRT شامل موارد زیر است:
- انواع داده های رایج (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);
پارامترهای کوانتیزاسیون یک تانسور را می توان از طریق کتابخانه استخراج کننده فراداده خواند.