Zhvilluesit e aplikacioneve mobile zakonisht bashkëveprojnë me objekte të tipizuara siç janë bitmap-et ose primitivët siç janë numrat e plotë. Megjithatë, API-ja e interpretuesit LiteRT që ekzekuton modelin e të mësuarit automatik në pajisje përdor tenzorë në formën e ByteBuffer, të cilët mund të jenë të vështirë për t'u debuguar dhe manipuluar. Biblioteka e Mbështetjes LiteRT për Android është projektuar për të ndihmuar në përpunimin e hyrjes dhe daljes së modeleve LiteRT dhe për ta bërë interpretuesin LiteRT më të lehtë për t'u përdorur.
Fillimi
Importoni varësinë e Gradle dhe cilësime të tjera
Kopjoni skedarin e modelit .tflite në direktorinë e aseteve të modulit Android ku do të ekzekutohet modeli. Specifikoni që skedari nuk duhet të kompresohet dhe shtoni bibliotekën LiteRT në skedarin build.gradle të modulit:
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'
}
Eksploroni Bibliotekën e Mbështetjes LiteRT AAR të pritur në MavenCentral për versione të ndryshme të Bibliotekës së Mbështetjes.
Manipulimi dhe konvertimi bazë i imazhit
Biblioteka e Mbështetjes LiteRT ka një sërë metodash bazë të manipulimit të imazheve, të tilla si prerja dhe ndryshimi i madhësisë. Për ta përdorur atë, krijoni një ImagePreprocessor dhe shtoni operacionet e kërkuara. Për ta kthyer imazhin në formatin tensor të kërkuar nga interpretuesi LiteRT, krijoni një TensorImage që do të përdoret si input:
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 të një tensori mund të lexohet përmes bibliotekës së nxjerrësit të meta të dhënave , si dhe informacione të tjera të modelit.
Përpunimi bazë i të dhënave audio
Biblioteka e Mbështetjes LiteRT përcakton gjithashtu një klasë TensorAudio që mbështjell disa metoda themelore të përpunimit të të dhënave audio. Përdoret kryesisht së bashku me AudioRecord dhe kap mostrat audio në një buffer unazor.
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()
Krijo objekte dalëse dhe ekzekuto modelin
Para se të ekzekutojmë modelin, duhet të krijojmë objektet e kontejnerëve që do të ruajnë rezultatin:
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);
Ngarkimi i modelit dhe ekzekutimi i përfundimit:
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());
}
Qasja në rezultat
Zhvilluesit mund të qasen në rezultat direkt përmes probabilityBuffer.getFloatArray() . Nëse modeli prodhon një rezultat të kuantizuar, mos harroni ta konvertoni rezultatin. Për modelin e kuantizuar MobileNet, zhvilluesi duhet të pjesëtojë çdo vlerë të rezultatit me 255 për të marrë probabilitetin që varion nga 0 (më pak e mundshme) deri në 1 (më e mundshme) për secilën kategori.
Opsionale: Hartimi i rezultateve në etiketa
Zhvilluesit gjithashtu mund t'i lidhin rezultatet në mënyrë opsionale me etiketat. Së pari, kopjoni skedarin tekst që përmban etiketat në direktorinë e aseteve të modulit. Më pas, ngarkoni skedarin e etiketës duke përdorur kodin e mëposhtëm:
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);
}
Fragmenti i mëposhtëm tregon se si të shoqërohen probabilitetet me etiketat e kategorive:
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();
}
Mbulimi aktual i rasteve të përdorimit
Versioni aktual i Bibliotekës së Mbështetjes LiteRT mbulon:
- Llojet e zakonshme të të dhënave (float, uint8, imazhe, audio dhe varg i këtyre objekteve) si hyrje dhe dalje të modeleve tflite.
- operacione bazë të imazhit (prerja e imazhit, ndryshimi i madhësisë dhe rrotullimi).
- normalizimi dhe kuantizimi
- skedarë të dobishëm
Versionet e ardhshme do të përmirësojnë mbështetjen për aplikacionet që lidhen me tekstin.
Arkitektura e Përpunuesit të Imazheve
Dizajni i ImageProcessor lejoi që operacionet e manipulimit të imazhit të përcaktoheshin paraprakisht dhe të optimizoheshin gjatë procesit të ndërtimit. ImageProcessor aktualisht mbështet tre operacione bazë të përpunimit paraprak, siç përshkruhet në tre komentet në fragmentin e kodit më poshtë:
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();
Shihni më shumë detaje këtu rreth normalizimit dhe kuantizimit.
Qëllimi përfundimtar i bibliotekës mbështetëse është të mbështesë të gjitha transformimet tf.image . Kjo do të thotë që transformimi do të jetë i njëjtë me TensorFlow dhe zbatimi do të jetë i pavarur nga sistemi operativ.
Zhvilluesit janë gjithashtu të mirëpritur të krijojnë përpunues të personalizuar. Në këto raste është e rëndësishme që të jenë në përputhje me procesin e trajnimit - d.m.th., i njëjti përpunim paraprak duhet të zbatohet si për trajnimin ashtu edhe për nxjerrjen e përfundimeve për të rritur riprodhueshmërinë.
Kuantizimi
Kur inicioni objekte hyrëse ose dalëse si TensorImage ose TensorBuffer duhet të specifikoni llojet e tyre si DataType.UINT8 ose DataType.FLOAT32 .
TensorImage tensorImage = new TensorImage(DataType.UINT8);
TensorBuffer probabilityBuffer =
TensorBuffer.createFixedSize(new int[]{1, 1001}, DataType.UINT8);
TensorProcessor mund të përdoret për të kuantizuar tensorët e hyrjes ose për të dekuantizuar tensorët e daljes. Për shembull, kur përpunohet një TensorBuffer i daljes së kuantizuar, zhvilluesi mund të përdorë DequantizeOp për të dekuantizuar rezultatin në një probabilitet me pikë lundruese midis 0 dhe 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);
Parametrat e kuantizimit të një tensori mund të lexohen përmes bibliotekës së nxjerrësit të meta të dhënave .