Gli sviluppatori di applicazioni mobile in genere interagiscono con oggetti digitati come bitmap o primitive come i numeri interi. Tuttavia, l'interprete LiteRT L'API che esegue il modello di machine learning on-device utilizza tensori sotto forma di ByteBuffer, che può essere difficile da sottoporre a debug e manipolare. La Libreria di supporto Android LiteRT è progettato per aiutare a elaborare l'input e l'output dei modelli LiteRT. facilitano l'uso dell'interprete LiteRT.
Per iniziare
Importa la dipendenza da Gradle e altre impostazioni
Copia il file del modello .tflite
nella directory degli asset del modulo per Android
in cui verrà eseguito il modello. Specifica che il file non deve essere compresso.
aggiungi la libreria LiteRT al file build.gradle
del modulo:
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'
}
Esplora il AAR della libreria di supporto LiteRT ospitata su MavenCentral per le diverse versioni della Libreria di supporto.
Manipolazione di base delle immagini e conversione
La libreria di supporto LiteRT offre una suite di manipolazioni di base delle immagini
come ritaglio e ridimensionamento. Per usarla, crea un ImagePreprocessor
e
e aggiungere le operazioni richieste. Per convertire l'immagine nel formato tensore
richiesto dall'interprete LiteRT, crea un TensorImage
da utilizzare
come 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
di un tensore può essere letto attraverso
libreria di estrazione dei metadati
nonché altre informazioni sul modello.
Elaborazione dati audio di base
La libreria di supporto LiteRT definisce anche un wrapping di classi TensorAudio
alcuni metodi di base per il trattamento dei dati audio. Viene utilizzato principalmente insieme
AudioRecord
e acquisisce i campioni audio in un ring buffer.
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()
crea oggetti di output ed esegui il modello
Prima di eseguire il modello, dobbiamo creare gli oggetti container archivia il risultato:
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);
Caricamento del modello ed esecuzione dell'inferenza:
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());
}
Accesso al risultato
Gli sviluppatori possono accedere all'output direttamente tramite
probabilityBuffer.getFloatArray()
. Se il modello produce un output quantizzato,
ricordati di convertire il risultato. Per il modello quantizzato MobileNet, lo sviluppatore
deve dividere ciascun valore di output per 255 per ottenere la probabilità che
Da 0 (meno probabile) a 1 (più probabile) per ogni categoria.
(Facoltativo) Mappare i risultati alle etichette
Gli sviluppatori possono anche mappare i risultati alle etichette. Innanzitutto, copia il testo contenente le etichette nella directory degli asset del modulo. Quindi, carica l'etichetta utilizzando il seguente codice:
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);
}
Lo snippet seguente mostra come associare le probabilità a etichette delle categorie:
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();
}
Copertura dei casi d'uso attuali
La versione attuale della libreria di supporto LiteRT copre:
- tipi di dati comuni (float, uint8, immagini, audio e array di questi oggetti) come input e output dei modelli tflite.
- operazioni di base sulle immagini (ritaglio, ridimensionamento e rotazione dell'immagine).
- normalizzazione e quantizzazione
- file utils
Le versioni future miglioreranno il supporto per le applicazioni testuali.
Architettura del processore Image
La progettazione di ImageProcessor
ha consentito alle operazioni di manipolazione dell'immagine di
essere definiti fin da subito e ottimizzati durante il processo di creazione. ImageProcessor
attualmente supporta tre operazioni di pre-elaborazione di base, come descritto
nello snippet di codice riportato di seguito:
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();
Visualizza altri dettagli qui su la normalizzazione e la quantizzazione.
L'obiettivo finale della libreria di assistenza è aiutare tutti
tf.image
e piccole trasformazioni. Ciò significa che la trasformazione sarà la stessa di TensorFlow
e l'implementazione sarà indipendente dal sistema operativo.
Gli sviluppatori sono anche invitati a creare processori personalizzati. È importante questi casi devono essere allineati con il processo di addestramento, cioè lo stesso la pre-elaborazione dovrebbe applicarsi sia all'addestramento che all'inferenza per aumentare per la riproducibilità.
Quantizzazione
Quando si avviano oggetti di input o output come TensorImage
o TensorBuffer
devi specificare il tipo DataType.UINT8
o DataType.FLOAT32
.
TensorImage tensorImage = new TensorImage(DataType.UINT8);
TensorBuffer probabilityBuffer =
TensorBuffer.createFixedSize(new int[]{1, 1001}, DataType.UINT8);
TensorProcessor
può essere utilizzato per quantificare i tensori di input o dequantizzare l'output
tensori. Ad esempio, quando elabori un output quantizzato TensorBuffer
, il valore
sviluppatore può utilizzare DequantizeOp
per dequantizzare il risultato in una virgola mobile
probabilità tra 0 e 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);
I parametri di quantizzazione di un tensore possono essere letti attraverso libreria di estrazione dei metadati.