Dodawanie metadanych do modeli LiteRT

Metadane LiteRT zapewniają standard opisów modeli. Metadane są ważnym źródłem wiedzy na temat działania modelu i jego dane wejściowe / wyjściowe. Metadane składają się

Wszystkie modele obrazów opublikowane w Kaggle Modele zostały wypełnione wartościami metadanych.

Model w formacie metadanych

model_with_metadata
Rysunek 1. Model TFLite z metadanymi i powiązanymi plikami.

Metadane modelu są zdefiniowane w metadata_schema.fbs w FlatBuffer . Jak widać na Rysunku 1, jest on przechowywany w metadane, pole modelu TFLite schemat, pod nazwiskiem "TFLITE_METADATA". Niektóre modele mogą mieć powiązane pliki, na przykład etykieta klasyfikacji . Te pliki są połączone na końcu oryginalnego pliku modelu jako pliki ZIP przy użyciu pliku ZipFile "append" tryb (tryb 'a'). TFLite Tłumacz może przyswajać nowy format pliku w taki sam sposób jak wcześniej. Zobacz pakiet powiązane pliki.

Poniżej znajdziesz instrukcje wypełniania, wizualizacji i odczytywania metadanych.

Konfiguracja narzędzi do obsługi metadanych

Przed dodaniem metadanych do modelu musisz zaprogramować w Pythonie konfigurację środowiska do uruchamiania TensorFlow. Dostępny jest szczegółowy przewodnik, skonfiguruj je tutaj.

Po skonfigurowaniu środowiska programistycznego w Pythonie musisz zainstalować dodatkowe narzędzia:

pip install tflite-support

Narzędzia do metadanych LiteRT obsługują język Python 3.

Dodawanie metadanych za pomocą interfejsu Flatbuffers Python API

Metadane modelu składają się z 3 części schemat:

  1. Informacje o modelu – ogólny opis modelu i produktów np. warunki licencji. Zobacz ModelMetadata
    1. Dane wejściowe – opis danych wejściowych i wstępnego przetwarzania takich jak normalizacja. Zobacz SubGraphMetadata.input_tensor_metadata.
      1. Informacje wyjściowe – opis danych wyjściowych np. mapowania na etykiety. Zobacz SubGraphMetadata.output_tensor_metadata.

LiteRT obsługuje w tym momencie tylko jeden podgraf, Generator kodu LiteRT oraz Android Studio ML Binding będzie używać ModelMetadata.name i ModelMetadata.description zamiast SubGraphMetadata.name i SubGraphMetadata.description, podczas wyświetlania metadanych i generowaniu kodu.

Obsługiwane typy wejścia / wyjścia

Metadane LiteRT dla danych wejściowych i wyjściowych nie mają konkretnego lecz także typy danych wejściowych i wyjściowych. Nie ma znaczenia jak funkcjonuje model, o ile typy danych wejściowych i wyjściowych składają się następujący lub ich kombinację jest obsługiwany przez TensorFlow Metadane Lite:

  • Cecha – liczby, które są liczbami całkowitymi bez znaku lub liczbą zmiennoprzecinkową zmiennoprzecinkową.
  • Obraz – metadane obecnie obsługują obrazy w kolorze RGB i w skali szarości.
  • Ramka ograniczająca – prostokątne ramki ograniczające kształtu. Schemat obsługuje a różne numery .

Spakuj powiązane pliki

Modele LiteRT mogą mieć różne powiązane pliki. Przykład: modele języków naturalnych zazwyczaj mają pliki ze słowami, które mapują fragmenty słów na słowa Identyfikatory; Modele klasyfikacji mogą mieć pliki etykiet wskazujące kategorie obiektów. Bez powiązanych plików (jeśli istnieją) model nie będzie działał poprawnie.

Powiązane pliki można teraz grupować z modelem za pomocą metadanych z biblioteki Pythona. Nowy model LiteRT stanie się plikiem ZIP zawierającym zarówno model, jak i powiązane pliki. Można go rozpakować za pomocą popularnego pliku ZIP narzędzi. W nowym formacie modelu nadal jest używane to samo rozszerzenie pliku: .tflite. it jest kompatybilna z dotychczasową platformą TFLite i funkcją tłumaczenia rozmowy. Patrz sekcja Spakowanie metadanych i powiązane pliki model, aby dowiedzieć się więcej.

Informacje o powiązanych plikach można zarejestrować w metadanych. W zależności od typ pliku i miejsce jego dołączenia (np. ModelMetadata, SubGraphMetadata i TensorMetadata), kod LiteRT na Androida generator może zastosować odpowiednie wyniki przed/post i przetwarza dane automatycznie. Patrz zastosowanie kodu <Codegen>. sekcji każdy powiązany plik typu aby dowiedzieć się więcej.

Parametry normalizacji i kwantyzacji

Normalizacja to powszechna technika wstępnego przetwarzania danych w uczeniu maszynowym. celem normalizacji jest zmiana wartości na wspólną skalę, bez zniekształcanie różnic w zakresach wartości.

Kwantyzacja modelu to technika który pozwala zmniejszyć precyzję przedstawiania wag oraz opcjonalnie aktywacje pamięci i obliczenia.

W kontekście wstępnego i przetwarzania, normalizacji i kwantyzacji mamy do czynienia z 2 niezależnymi krokami. Oto szczegóły:

Normalizacja Kwantyfikacja

Oto przykład funkcji funkcji obraz wejściowy w MobileNet dla liczb zmiennoprzecinkowych i modele ilościowe, .
Model swobodny:
- średnia: 127,5
- standardowy: 127,5
Model ilościowy:
- średnia: 127,5
- standardowy: 127,5
Model swobodny:
– zeroPoint: 0
– skala: 1,0
Model ilościowy:
- zeroPoint: 128,0
- scale:0.0078125f




Kiedy wywoływać?


Dane wejściowe: jeśli dane wejściowe jest znormalizowane w trenowanie, dane wejściowe dane dotyczące wnioskowania do znormalizowania odpowiednio się zmienia.
Dane wyjściowe: dane wyjściowe nie będą znormalizowane.
Modele pływające nie wymagają kwantyzacji.
Model kwantowy może lub może nie potrzebować kwantyzacja przed i po o przetwarzaniu danych. To zależy na typie danych tensory wejściowe/wyjściowe.
- tensory zmiennoprzecinkowe: nie kwantyzacja przed i po potrzebne przetwarzanie. Quant Operacje i operacje pomniejszone są w modelu wykres.
- tensory int8/uint8: potrzebujesz kwantyzacji w przed przetwarzaniem danych i po ich przetworzeniu.


Wzór


znormalizowane_dane_wejściowe = (dane wejściowe – średnia) / standardowe
Kwantyfikacja danych wejściowych:
q = f / skala + zeroPoint
Zdekwantyzuj dla dane wyjściowe:
f = (q – punkt zerowy) * skala

Gdzie są parametry
Wypełnione przez twórcę modelu i zapisane w modelu metadanych, NormalizationOptions Wypełnione automatycznie przez konwertera TFLite, zapisane w modelu tflite .
Jak uzyskać ? Przez Interfejs API MetadataExtractor [2] Przez TFLite Tensor API [1] lub przez Interfejs API MetadataExtractor [2]
Stosuj metody zmiennoprzecinkowe i kwantowe modele mają takie same wartości ? Tak, używaj liczb zmiennoprzecinkowych i kwantowych modele mają takie same Normalizacja parametry Nie, model zmiennoprzecinkowy nie wymagają kwantyzacji.
Czy TFLite Code generatora lub Android Powiązanie Studio ML generuj automatycznie w przetwarzaniu danych?
Tak

Tak

[1] Jawa LiteRT Interfejs API oraz LiteRT C++ API.
[2] Biblioteka wyodrębniania metadanych

Podczas przetwarzania danych obrazu w modelach uint8 normalizacja i kwantyzacja są czasem pomijane. Jest to dozwolone, gdy wartości pikseli mieszczą się w zakresie [0, 255]. Ogólnie jednak dane należy przetwarzać zgodnie z w stosownych przypadkach parametry normalizacji i kwantyzacji.

Przykłady

Znajdziesz tu przykłady wypełniania metadanych dla różnych typy modeli tutaj:

Klasyfikacja obrazów

Pobierz skrypt tutaj , który uzupełnia metadane mobilenet_v1_0.75_160_quantized.tflite. Uruchom skrypt w ten sposób:

python ./metadata_writer_for_image_classifier.py \
    --model_file=./model_without_metadata/mobilenet_v1_0.75_160_quantized.tflite \
    --label_file=./model_without_metadata/labels.txt \
    --export_directory=model_with_metadata

Aby wypełnić metadane innych modeli klasyfikacji obrazów, dodaj specyfikację modelu polubienie to w scenariusz. W dalszej części tego przewodnika omawiamy najważniejsze sekcje w przykładzie klasyfikacji obrazów, aby zilustrować kluczowe elementy.

Szczegółowa analiza przykładu klasyfikacji obrazów

Informacje o modelu

Metadane zaczynają się od utworzenia nowych informacji o modelu:

from tflite_support import flatbuffers
from tflite_support import metadata as _metadata
from tflite_support import metadata_schema_py_generated as _metadata_fb

""" ... """
"""Creates the metadata for an image classifier."""

# Creates model info.
model_meta = _metadata_fb.ModelMetadataT()
model_meta.name = "MobileNetV1 image classifier"
model_meta.description = ("Identify the most prominent object in the "
                          "image from a set of 1,001 categories such as "
                          "trees, animals, food, vehicles, person etc.")
model_meta.version = "v1"
model_meta.author = "TensorFlow"
model_meta.license = ("Apache License. Version 2.0 "
                      "http://www.apache.org/licenses/LICENSE-2.0.")

Informacje wejściowe / wyjściowe

Ta sekcja pokazuje, jak opisać podpis wejściowy i wyjściowy modelu. Automatyczne generatory kodu mogą używać tych metadanych do tworzenia Przetwarzanie kodu. Aby utworzyć dane wejściowe lub wyjściowe dotyczące tensora:

# Creates input info.
input_meta = _metadata_fb.TensorMetadataT()

# Creates output info.
output_meta = _metadata_fb.TensorMetadataT()

Dane wejściowe obrazu

Obraz to typowy typ danych wejściowych systemów uczących się. Metadane LiteRT obsługuje takie informacje, jak przestrzeń kolorów i dane dotyczące wstępnego przetwarzania danych, takie jak z normalizacją. Wymiary obrazu nie wymagają ręcznego określania ponieważ jest on określony przez kształt tensora wejściowego i można go określić automatycznie wywnioskować.

input_meta.name = "image"
input_meta.description = (
    "Input image to be classified. The expected image is {0} x {1}, with "
    "three channels (red, blue, and green) per pixel. Each value in the "
    "tensor is a single byte between 0 and 255.".format(160, 160))
input_meta.content = _metadata_fb.ContentT()
input_meta.content.contentProperties = _metadata_fb.ImagePropertiesT()
input_meta.content.contentProperties.colorSpace = (
    _metadata_fb.ColorSpaceType.RGB)
input_meta.content.contentPropertiesType = (
    _metadata_fb.ContentProperties.ImageProperties)
input_normalization = _metadata_fb.ProcessUnitT()
input_normalization.optionsType = (
    _metadata_fb.ProcessUnitOptions.NormalizationOptions)
input_normalization.options = _metadata_fb.NormalizationOptionsT()
input_normalization.options.mean = [127.5]
input_normalization.options.std = [127.5]
input_meta.processUnits = [input_normalization]
input_stats = _metadata_fb.StatsT()
input_stats.max = [255]
input_stats.min = [0]
input_meta.stats = input_stats

Dane wyjściowe etykiety

Etykieta można zmapować na tensor wyjściowy za pomocą powiązanego pliku za pomocą TENSOR_AXIS_LABELS

# Creates output info.
output_meta = _metadata_fb.TensorMetadataT()
output_meta.name = "probability"
output_meta.description = "Probabilities of the 1001 labels respectively."
output_meta.content = _metadata_fb.ContentT()
output_meta.content.content_properties = _metadata_fb.FeaturePropertiesT()
output_meta.content.contentPropertiesType = (
    _metadata_fb.ContentProperties.FeatureProperties)
output_stats = _metadata_fb.StatsT()
output_stats.max = [1.0]
output_stats.min = [0.0]
output_meta.stats = output_stats
label_file = _metadata_fb.AssociatedFileT()
label_file.name = os.path.basename("your_path_to_label_file")
label_file.description = "Labels for objects that the model can recognize."
label_file.type = _metadata_fb.AssociatedFileType.TENSOR_AXIS_LABELS
output_meta.associatedFiles = [label_file]

Tworzenie metadanych Flatbuffers

Ten kod łączy informacje o modelu z danymi wejściowymi i wyjściowymi informacje:

# Creates subgraph info.
subgraph = _metadata_fb.SubGraphMetadataT()
subgraph.inputTensorMetadata = [input_meta]
subgraph.outputTensorMetadata = [output_meta]
model_meta.subgraphMetadata = [subgraph]

b = flatbuffers.Builder(0)
b.Finish(
    model_meta.Pack(b),
    _metadata.MetadataPopulator.METADATA_FILE_IDENTIFIER)
metadata_buf = b.Output()

Zapakuj do modelu metadane i powiązane pliki

Po utworzeniu metadanych Flatbuffers metadane i plik etykiety zostaną zapisane w pliku TFLite metodą populate:

populator = _metadata.MetadataPopulator.with_model_file(model_file)
populator.load_metadata_buffer(metadata_buf)
populator.load_associated_files(["your_path_to_label_file"])
populator.populate()

Możesz zapakować do modelu dowolną liczbę powiązanych plików load_associated_files Należy jednak zapakować co najmniej te pliki co jest omówione w metadanych. W tym przykładzie spakowanie pliku etykiety będzie wyglądać tak: obowiązkowe.

Wizualizacja metadanych

Narzędzie Netron pozwala zwizualizować metadanych lub odczytać metadane z modelu LiteRT do pliku json w formacie MetadataDisplayer:

displayer = _metadata.MetadataDisplayer.with_model_file(export_model_path)
export_json_file = os.path.join(FLAGS.export_directory,
                                os.path.splitext(model_basename)[0] + ".json")
json_file = displayer.get_metadata_json()
# Optional: write out the metadata as a json file
with open(export_json_file, "w") as f:
  f.write(json_file)

Android Studio obsługuje również wyświetlanie metadanych za pomocą Android Studio ML Powiązanie .

Obsługa wersji metadanych

Metadane schemat jest objęta wersjami według semantycznego numeru wersji, który śledzi zmiany pliku schema.org, a dzięki identyfikacji plików Flatbuffers, która wskazuje prawdziwą zgodność wersji.

Numer semantycznej obsługi wersji

Schemat metadanych jest obsługiwany przez semantyczną obsługę wersji , na przykład GŁÓWNA.PODRZĘDNA.POPRAWKA. Śledzi zmiany schematu na podstawie reguł tutaj. Zobacz historię dodane po wersji 1.0.0.

Identyfikacja pliku Flatbuffers

Semantyczna obsługa wersji gwarantuje zgodność, jeśli jest zgodna z regułami, ale nie oznacza rzeczywistej niezgodności. Zwiększenie liczby GŁÓWNA powoduje, że nie musi oznaczać, że zgodność wsteczna jest uszkodzona. Dlatego użyj pliku Flatbuffers, dane identyfikacyjne, file_identifier, aby wskazać prawdziwą zgodność schematu metadanych. Identyfikator pliku to dokładnie 4 znaki. Jest ustalony na podstawie określonego schematu metadanych, a nie mogą ulec zmianie przez użytkowników. Jeśli zgodność wsteczna schematu metadanych musi zostać złamany z jakiegoś powodu, parametr file_identifier wyświetla się np. od „M001” do „M002”. File_identifier powinien być znacznie rzadziej zmieniany częściej niż parametr metadata_version.

Minimalna wymagana wersja parsera metadanych

Minimalny niezbędny parser metadanych wersja to minimalna wersja parsera metadanych (wygenerowanego kodu Flatbuffers), który może w całości odczytać metadane Flatbuffers w całości. Ta wersja jest w praktyce o największym numerze wersji spośród wszystkich wypełnionych pól najmniejszą zgodną wersję wskazywaną przez identyfikator pliku. Minimalne niezbędna wersja parsera metadanych jest automatycznie wypełniana przez MetadataPopulator, gdy metadane zostaną umieszczone w modelu TFLite. Zobacz wyodrębnianie metadanych minimalnej wymaganej wersji parsera metadanych.

Odczytywanie metadanych z modeli

Biblioteka wyodrębniania metadanych to wygodne narzędzie do odczytu metadanych i powiązanych plików z modeli na różnych platformach (zobacz artykuł w języku JavaScript wersja oraz język C++ wersji). Możesz utworzyć własne narzędzie do wyodrębniania metadanych w innych językach za pomocą Biblioteka Flatbuffers.

Odczytywanie metadanych w Javie

Jeśli chcesz używać biblioteki wyodrębniania metadanych w aplikacji na Androida, zalecamy użycie narzędzie AAR metadanych LiteRT hostowane pod adresem MavenCentral. Zawiera klasę MetadataExtractor oraz środowisko FlatBuffers Java. powiązania metadanych, schemat oraz model schemat.

Możesz to określić w zależnościach build.gradle w ten sposób:

dependencies {
    implementation 'org.tensorflow:tensorflow-lite-metadata:0.1.0'
}

Aby korzystać z nocnych zrzutów ekranu, dodaj opcję Sonatype (ujęcie) .

Możesz zainicjować obiekt MetadataExtractor obiektem ByteBuffer wskazującym do modelu:

public MetadataExtractor(ByteBuffer buffer);

Wartość ByteBuffer musi pozostać niezmieniona przez cały okres istnienia MetadataExtractor obiekt. Inicjalizacja może się nie udać, jeśli plik Flatbuffers identyfikator metadanych modelu nie jest zgodny z identyfikatorem parsera metadanych. Zobacz obsługi wersji metadanych.

Wyodrębnianie metadanych z pasujących identyfikatorów plików umożliwi odczyt metadanych wygenerowanych na podstawie wszystkich przeszłych i przyszłych schematów ze względu na tag Flatbuffers mechanizm zgodności wstecznej i standardowej. Jednak pola z przyszłości Starsze moduły wyodrębniania metadanych nie mogą wyodrębniać schematów. Minimalna wymagana liczba wersji parsera metadanych. wskazuje minimalną wersję parsera metadanych, która może odczytywać metadane Pełne bufory. Aby sprawdzić, czy wartość minimalna wymagany warunek wersji parsera:

public final boolean isMinimumParserVersionSatisfied();

Dozwolone jest przekazywanie modelu bez metadanych. Wywołanie metod, które odczyt metadanych spowoduje błędy podczas działania. Możesz sprawdzić, czy model metadanych przez wywołanie metody hasMetadata:

public boolean hasMetadata();

MetadataExtractor udostępnia wygodne funkcje umożliwiające uzyskanie tensorów wejściowych/wyjściowych metadanych. Na przykład

public int getInputTensorCount();
public TensorMetadata getInputTensorMetadata(int inputIndex);
public QuantizationParams getInputTensorQuantizationParams(int inputIndex);
public int[] getInputTensorShape(int inputIndex);
public int getoutputTensorCount();
public TensorMetadata getoutputTensorMetadata(int inputIndex);
public QuantizationParams getoutputTensorQuantizationParams(int inputIndex);
public int[] getoutputTensorShape(int inputIndex);

Chociaż model LiteRT schemat obsługuje wiele podgrafów, narzędzie TFLite Interpreter obsługuje obecnie tylko jednego podgrafu. Dlatego funkcja MetadataExtractor pomija indeks podgrafu jako dane wejściowe. w jego metodach.

Odczytywanie powiązanych plików z modeli

Model LiteRT z metadanymi i powiązanymi plikami .zip, które można rozpakować za pomocą popularnych narzędzi do spakowania, aby pobrać powiązane pliki. Możesz na przykład rozpakować plik mobilenet_v1_0.75_160_quantized i wyodrębnij w modelu plik etykiety w ten sposób:

$ unzip mobilenet_v1_0.75_160_quantized_1_metadata_1.tflite
Archive:  mobilenet_v1_0.75_160_quantized_1_metadata_1.tflite
 extracting: labels.txt

Powiązane pliki możesz też odczytywać za pomocą biblioteki ekstraktora metadanych.

W języku Java przekaż nazwę pliku do narzędzia MetadataExtractor.getAssociatedFile. :

public InputStream getAssociatedFile(String fileName);

Podobnie w C++ można to zrobić za pomocą metody ModelMetadataExtractor::GetAssociatedFile:

tflite::support::StatusOr<absl::string_view> GetAssociatedFile(
      const std::string& filename) const;