Les développeurs d'applications mobiles interagissent généralement avec des objets typés tels que les bitmaps ou les primitives tels que les entiers. Cependant, l'interpréteur LiteRT L'API qui exécute le modèle de machine learning sur l'appareil utilise des Tensors sous la forme de ByteBuffer, qui peut être difficile à déboguer et à manipuler. La Bibliothèque LiteRT Android Support est conçu pour faciliter le traitement des entrées et sorties des modèles LiteRT ; rendre l'interpréteur LiteRT plus facile à utiliser.
Premiers pas
Importer la dépendance Gradle et d'autres paramètres
Copiez le fichier de modèle .tflite
dans le répertoire d'éléments du module Android.
où le modèle sera exécuté. Spécifier que le fichier ne doit pas être compressé
Ajoutez la bibliothèque LiteRT au fichier build.gradle
du module:
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'
}
Explorez les AAR de la bibliothèque Support pour LiteRT hébergée sur MavenCentral pour les différentes versions de la bibliothèque Support.
Manipulation et conversion d'images de base
La bibliothèque LiteRT Support propose une suite
de manipulations d'images de base
comme le recadrage et le redimensionnement. Pour l'utiliser, créez un ImagePreprocessor
et
ajouter les opérations requises. À convertir l'image au format de Tensor
requise par l'interpréteur LiteRT, créez un TensorImage
à utiliser
comme entrée:
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);
La fonction DataType
d'un Tensor peut être lue via la
bibliothèque d'extracteurs de métadonnées
ainsi que d'autres informations du modèle.
Traitement de base des données audio
La bibliothèque Support LiteRT définit également l'encapsulation d'une classe TensorAudio
.
quelques méthodes de base
de traitement des données audio. Il est principalement
utilisé avec
AudioRecord
et capture des échantillons audio
dans un tampon circulaire.
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()
Créer des objets de sortie et exécuter le modèle
Avant d'exécuter le modèle, nous devons créer les objets conteneur stockez le résultat:
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);
Chargement du modèle et exécution de l'inférence:
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());
}
Accéder au résultat
Les développeurs peuvent accéder à la sortie directement via
probabilityBuffer.getFloatArray()
Si le modèle produit une sortie quantifiée,
n'oubliez pas de convertir le résultat. Pour le modèle quantifié MobileNet, le développeur
doit diviser chaque valeur de sortie par 255 pour obtenir une probabilité allant de
De 0 (le moins probable) à 1 (le plus probable) pour chaque catégorie.
Facultatif: Mapper les résultats avec des étiquettes
Les développeurs peuvent également mapper les résultats sur des étiquettes. Tout d'abord, copiez le texte contenant des étiquettes dans le répertoire d'éléments du module. Ensuite, chargez l'étiquette à l'aide du code suivant:
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);
}
L'extrait de code suivant montre comment associer les probabilités libellés de catégorie:
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();
}
Couverture des cas d'utilisation actuels
La version actuelle de la bibliothèque Support pour LiteRT couvre les sujets suivants:
- Types de données courants (float, uint8, images, audio et Array de ces objets) comme entrées et sorties des modèles tflite.
- les opérations de base sur l'image (recadrer, redimensionner et faire pivoter l'image).
- normalisation et quantification
- utilitaires de fichier
Les futures versions amélioreront la prise en charge des applications textuelles.
Architecture d'ImageProcessor
La conception de ImageProcessor
a permis aux opérations de manipulation d'image de
être définis en amont et optimisés
pendant le processus de compilation. ImageProcessor
prend actuellement en charge trois opérations de prétraitement de base, décrites dans le
trois commentaires dans l'extrait de code ci-dessous:
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();
Afficher plus de détails cliquez ici sur la normalisation et la quantification.
L'objectif final de la bibliothèque Support est de permettre
tf.image
Transformer. Cela signifie que la transformation sera la même que TensorFlow
et l'implémentation est indépendante du système d'exploitation.
Les développeurs peuvent également créer des processeurs personnalisés. Il est important de ces cas pour qu'ils soient alignés sur le processus d'entraînement, c'est-à-dire le prétraitement doit s'appliquer à la fois à l'entraînement et à l'inférence pour augmenter la reproductibilité.
Quantification
Lors du lancement d'objets d'entrée ou de sortie tels que TensorImage
ou TensorBuffer
vous devez spécifier la valeur DataType.UINT8
ou DataType.FLOAT32
.
TensorImage tensorImage = new TensorImage(DataType.UINT8);
TensorBuffer probabilityBuffer =
TensorBuffer.createFixedSize(new int[]{1, 1001}, DataType.UINT8);
TensorProcessor
permet de quantifier les Tensors d'entrée ou de déquantifier la sortie
Tensors. Par exemple, lors du traitement d'une sortie quantifiée TensorBuffer
,
le développeur peut utiliser DequantizeOp
pour déquantifier le résultat en virgule flottante.
probabilité comprise entre 0 et 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);
Les paramètres de quantification d'un Tensor peuvent être lus bibliothèque d'extracteurs de métadonnées.