Programiści aplikacji mobilnych zwykle wchodzą w interakcję z typami obiektów, takimi jak map bitowych ani elementów podstawowych, takich jak liczby całkowite. Tłumacz LiteRT Interfejs API, który uruchamia model systemów uczących się na urządzeniu, używa tensorów w postaci: ByteBuffer, który może być trudny do debugowania i manipulacji. Biblioteka pomocy LiteRT Android ma pomóc w przetwarzaniu danych wejściowych i wyjściowych modeli LiteRT oraz ułatwienie tłumaczenia przy użyciu LiteRT.
Pierwsze kroki
Importuj zależność Gradle i inne ustawienia
Skopiuj plik modelu .tflite
do katalogu zasobów modułu Androida
w którym będzie uruchamiany model. Określ, że plik nie powinien być skompresowany.
dodaj bibliotekę LiteRT do pliku build.gradle
modułu:
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'
}
Dowiedz się więcej AAR w bibliotece pomocy LiteRT hostowane w MavenCentral dla różnych wersji Biblioteki pomocy.
Podstawowe operacje na obrazach i ich konwertowaniu
Biblioteka pomocy LiteRT obejmuje pakiet podstawowych operacji na obrazach
takie jak przycinanie
i zmiana rozmiaru. Aby go używać, utwórz ImagePreprocessor
i
dodaj wymagane operacje. Aby przekonwertować obraz na format tensora
wymagane przez tłumacza LiteRT, utwórz TensorImage
do użycia
jako dane wejściowe:
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
tensora można odczytać za pomocą funkcji
biblioteka wyodrębniania metadanych
oraz inne informacje o modelu.
Podstawowe przetwarzanie danych audio
Biblioteka pomocy LiteRT definiuje też pakowanie klas TensorAudio
za pomocą kilku podstawowych metod przetwarzania danych audio. Jest używany głównie razem z
AudioRecord
i rejestruje próbki dźwięku w buforze pierścieniowym.
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()
Utwórz obiekty wyjściowe i uruchom model
Przed uruchomieniem modelu musimy utworzyć obiekty kontenera, które będą zapisz wynik:
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);
Wczytuję model i uruchomione wnioskowanie:
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());
}
Uzyskiwanie dostępu do wyniku
Programiści mogą uzyskać dostęp do danych wyjściowych bezpośrednio
probabilityBuffer.getFloatArray()
Jeśli model generuje kwantyzowane dane wyjściowe,
pamiętaj o przekonwertowaniu wyniku. W przypadku kwantowego modelu MobileNet
musi podzielić każdą wartość wyjściową przez 255, aby uzyskać prawdopodobieństwo w zakresie od
Od 0 (najmniejsze prawdopodobieństwo) do 1 (najprawdopodobniej) w każdej kategorii.
Opcjonalnie: mapowanie wyników na etykiety
Programiści mogą też opcjonalnie zmapować wyniki na etykiety. Najpierw skopiuj tekst zawierający etykiety do katalogu zasobów modułu. Następnie wczytaj etykietę za pomocą tego kodu:
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);
}
Ten fragment kodu pokazuje, jak powiązać prawdopodobieństwa z etykiety kategorii:
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();
}
Obecny zasięg przypadku użycia
Obecna wersja Biblioteki pomocy LiteRT obejmuje:
- najpopularniejsze typy danych (liczba zmiennoprzecinkowa, uint8, obrazy, dźwięk oraz tablica tych obiektów) jako dane wejściowe i wyjściowe modeli tflite.
- podstawowych operacji na obrazie (przycinanie obrazu, zmiana rozmiaru i obracanie).
- normalizacja i kwantyzacja
- pliki narzędzi
Kolejne wersje ulepszą obsługę aplikacji związanych z tekstem.
Architektura procesora ImageProcessor
ImageProcessor
umożliwia operacje manipulacji obrazami.
powinny zostać zdefiniowane na początku i zoptymalizowane w trakcie procesu tworzenia. ImageProcessor
obecnie obsługuje trzy podstawowe operacje wstępnego przetwarzania, zgodnie z opisem
trzy komentarze w poniższym fragmencie kodu:
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();
Pokaż więcej szczegółów tutaj o ich normalizacji i kwantyzacji.
Głównym celem biblioteki pomocy jest
obsługa wszystkich
tf.image
przekształcenia danych. Oznacza to, że przekształcenie będzie takie samo jak w TensorFlow
a implementacja będzie niezależna od systemu operacyjnego.
Programiści mogą również tworzyć niestandardowe procesory. Ważne jest, aby dostosować je do procesu trenowania. Trzeba więc pamiętać, wstępne przetwarzanie powinno mieć zastosowanie zarówno do trenowania, jak i wnioskowania, aby zwiększyć odtwarzalność.
Kwantyfikacja
Podczas inicjowania obiektów wejściowych lub wyjściowych, np. TensorImage
lub TensorBuffer
musisz określić ich typy jako DataType.UINT8
lub DataType.FLOAT32
.
TensorImage tensorImage = new TensorImage(DataType.UINT8);
TensorBuffer probabilityBuffer =
TensorBuffer.createFixedSize(new int[]{1, 1001}, DataType.UINT8);
Interfejsu TensorProcessor
można używać do kwantyzacji tensorów wejściowych lub dekwantyzacji danych wyjściowych
tensorów. Na przykład podczas przetwarzania kwantyzowanych danych wyjściowych TensorBuffer
funkcja
deweloper może użyć DequantizeOp
do dekwantyzacji wyniku do postaci zmiennoprzecinkowej
prawdopodobieństwo między 0 a 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);
Parametry kwantyzacji tensora można odczytać za pomocą funkcji bibliotekę wyodrębniania metadanych.