Weź udział w sympozjum Women in ML 7 grudnia Zarejestruj się teraz

Dodawanie metadanych do modeli TensorFlow Lite

Metadane TensorFlow Lite zapewniają standard opisów modeli. Metadane są ważnym źródłem wiedzy o tym, czym zajmuje się model i jakie są jego informacje wejściowe/wyjściowe. Metadane składają się z obu

Wszystkie modele obrazów opublikowane w TensorFlow Hub zostały wypełnione metadanymi.

Model z formatem metadanych

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

Metadane modelu są zdefiniowane w metadata_schema.fbs , pliku FlatBuffer . Jak pokazano na rysunku 1, jest on przechowywany w polu metadanych schematu modelu TFLite pod nazwą "TFLITE_METADATA" . Niektóre modele mogą być dostarczane z powiązanymi plikami, takimi jak pliki etykiet klasyfikacji . Te pliki są łączone na końcu oryginalnego pliku modelu jako ZIP przy użyciu trybu „dołączania” ZipFile (tryb 'a' ). Interpreter TFLite może korzystać z nowego formatu pliku w taki sam sposób, jak poprzednio. Zobacz Pakowanie powiązanych plików, aby uzyskać więcej informacji.

Zapoznaj się z poniższą instrukcją dotyczącą wypełniania, wizualizacji i odczytywania metadanych.

Skonfiguruj narzędzia metadanych

Przed dodaniem metadanych do modelu będziesz potrzebować konfiguracji środowiska programistycznego w języku Python, aby uruchomić TensorFlow. Szczegółowy przewodnik, jak to skonfigurować, znajduje się tutaj .

Po skonfigurowaniu środowiska programowania Python będziesz musiał zainstalować dodatkowe narzędzia:

pip install tflite-support

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

Dodawanie metadanych za pomocą Flatbuffers Python API

Metadane modelu w schemacie składają się z trzech części:

  1. Informacje o modelu — ogólny opis modelu oraz elementów, takich jak warunki licencji. Zobacz Metadane modelu .
  2. Informacje wejściowe — opis danych wejściowych i wymagane wstępne przetwarzanie, takie jak normalizacja. Zobacz SubGraphMetadata.input_tensor_metadata .
  3. Informacje wyjściowe — opis danych wyjściowych i wymaganego przetwarzania końcowego, takiego jak mapowanie do etykiet. Zobacz SubGraphMetadata.output_tensor_metadata .

Ponieważ TensorFlow Lite obsługuje w tym momencie tylko jeden wykres podrzędny, generator kodu TensorFlow Lite i funkcja powiązania Android Studio ML będą używać ModelMetadata.name i ModelMetadata.description , zamiast SubGraphMetadata.name i SubGraphMetadata.description podczas wyświetlania metadanych i generowania kodu.

Obsługiwane typy wejść/wyjść

Metadane TensorFlow Lite dla danych wejściowych i wyjściowych nie są zaprojektowane z myślą o określonych typach modeli, ale raczej o typach danych wejściowych i wyjściowych. Nie ma znaczenia, co model robi funkcjonalnie, o ile typy wejściowe i wyjściowe składają się z następujących elementów lub ich kombinacji, jest on obsługiwany przez metadane TensorFlow Lite:

  • Cecha — liczby, które są liczbami całkowitymi bez znaku lub float32.
  • Obraz — Metadane obecnie obsługują obrazy RGB i w skali szarości.
  • Ramka ograniczająca — prostokątne ramki ograniczające. Schemat obsługuje różne schematy numeracji .

Spakuj powiązane pliki

Modele TensorFlow Lite mogą być dostarczane z różnymi powiązanymi plikami. Na przykład modele języka naturalnego zwykle mają pliki vocab, które odwzorowują fragmenty słów na identyfikatory słów; modele klasyfikacji mogą mieć pliki etykiet, które wskazują kategorie obiektów. Bez powiązanych plików (jeśli są), model nie będzie działał dobrze.

Powiązane pliki można teraz połączyć z modelem za pomocą biblioteki metadanych Python. Nowy model TensorFlow Lite staje się plikiem zip, który zawiera zarówno model, jak i powiązane pliki. Można go rozpakować za pomocą popularnych narzędzi do zip. Ten nowy format modelu używa tego samego rozszerzenia pliku, .tflite . Jest kompatybilny z istniejącym frameworkiem TFLite i Interpreterem. Zobacz Pakowanie metadanych i skojarzonych plików do modelu, aby uzyskać więcej informacji.

Informacje o powiązanych plikach można zapisać w metadanych. W zależności od typu pliku i miejsca, do którego plik jest dołączony (tj. ModelMetadata , SubGraphMetadata i TensorMetadata ), generator kodu TensorFlow Lite Android może automatycznie zastosować odpowiednie przetwarzanie wstępne i końcowe do obiektu. Zobacz sekcję <Codegen usage> każdego typu pliku skojarzonego w schemacie, aby uzyskać więcej informacji.

Parametry normalizacji i kwantyzacji

Normalizacja jest powszechną techniką wstępnego przetwarzania danych w uczeniu maszynowym. Celem normalizacji jest zmiana wartości na wspólną skalę, bez zniekształcania różnic w przedziałach wartości.

Kwantyzacja modelu to technika, która pozwala na zmniejszoną precyzję reprezentacji wag i opcjonalnie aktywację zarówno przechowywania, jak i obliczeń.

Jeśli chodzi o przetwarzanie wstępne i przetwarzanie końcowe, normalizacja i kwantyzacja to dwa niezależne kroki. Oto szczegóły.

Normalizacja Kwantyzacja

Przykład wartości parametrów obrazu wejściowego w MobileNet odpowiednio dla modeli float i quant.
Model pływający :
- średnia: 127,5
- std: 127,5
Model ilościowy :
- średnia: 127,5
- std: 127,5
Model pływający :
- punkt zerowy: 0
- skala: 1,0
Model ilościowy :
- punkt zerowy: 128,0
- skala: 0,0078125f




Kiedy się powoływać?


Dane wejściowe : Jeśli dane wejściowe są znormalizowane podczas uczenia, dane wejściowe wnioskowania należy odpowiednio znormalizować.
Wyjścia : dane wyjściowe nie będą ogólnie znormalizowane.
Modele zmiennoprzecinkowe nie wymagają kwantyzacji.
Model skwantowany może, ale nie musi wymagać kwantyzacji w przetwarzaniu wstępnym i końcowym. Zależy to od typu danych tensorów wejścia/wyjścia.
- tensory zmiennoprzecinkowe: nie jest wymagana kwantyzacja w przetwarzaniu wstępnym i końcowym. Quant op i dequant op są umieszczane w grafie modelu.
- tensory int8/uint8: wymagają kwantyzacji w przetwarzaniu wstępnym i końcowym.


Formuła


normalized_input = (dane wejściowe - średnia) / std
Kwantyzacja dla danych wejściowych :
q = f / skala + punkt zerowy
Dekwantyzacja dla wyjść :
f = (q - punkt zerowy) * skala

Gdzie są parametry
Wypełniane przez twórcę modelu i przechowywane w metadanych modelu, jako NormalizationOptions Wypełniany automatycznie przez konwerter TFLite i przechowywany w pliku modelu tflite.
Jak uzyskać parametry? Poprzez interfejs API MetadataExtractor [2] Przez TFLite Tensor API [1] lub przez MetadataExtractor API [2]
Czy modele zmiennoprzecinkowe i ilościowe mają tę samą wartość? Tak, modele zmiennoprzecinkowe i kwantowe mają te same parametry normalizacji Nie, model zmiennoprzecinkowy nie wymaga kwantyzacji.
Czy generator kodu TFLite lub powiązanie Android Studio ML automatycznie generuje go podczas przetwarzania danych?
TAk

TAk

[1] TensorFlow Lite Java API i TensorFlow Lite C++ API .
[2] Biblioteka ekstraktora metadanych

Podczas przetwarzania danych obrazu dla modeli uint8 czasami pomija się normalizację i kwantyzację. Można to zrobić, gdy wartości pikseli mieszczą się w zakresie [0, 255]. Ale ogólnie rzecz biorąc, zawsze należy przetwarzać dane zgodnie z parametrami normalizacji i kwantyzacji, jeśli ma to zastosowanie.

Biblioteka zadań TensorFlow Lite może obsługiwać normalizację, jeśli skonfigurujesz NormalizationOptions w metadanych. Przetwarzanie kwantyzacji i dekwantyzacji jest zawsze hermetyzowane.

Przykłady

Przykłady wypełniania metadanych dla różnych typów modeli znajdziesz tutaj:

Klasyfikacja obrazu

Pobierz skrypt tutaj , który wypełnia metadane w 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 dla innych modeli klasyfikacji obrazów, dodaj takie specyfikacje modelu do skryptu. W pozostałej części tego przewodnika zostaną wyróżnione niektóre kluczowe sekcje w przykładzie klasyfikacji obrazów, aby zilustrować kluczowe elementy.

Zanurz się głęboko w przykład 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

W tej sekcji pokazano, jak opisać sygnaturę wejściową i wyjściową modelu. Te metadane mogą być wykorzystywane przez automatyczne generatory kodu do tworzenia kodu przed i po przetwarzaniu. Aby utworzyć informacje wejściowe lub wyjściowe dotyczące tensora:

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

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

Wejście obrazu

Obraz to typowy typ danych wejściowych w uczeniu maszynowym. Metadane TensorFlow Lite obsługują informacje, takie jak przestrzeń kolorów i informacje o przetwarzaniu wstępnym, takie jak normalizacja. Wymiar obrazu nie wymaga ręcznego określania, ponieważ jest już określany przez kształt tensora wejściowego i można go 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

Wyjście etykiet

Etykietę można odwzorować na tensor wyjściowy za pomocą skojarzonego 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]

Utwórz metadane Flatbuffers

Poniższy kod łączy informacje o modelu z informacjami wejściowymi i wyjściowymi:

# 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()

Spakuj metadane i powiązane pliki do modelu

Po utworzeniu Flatbuffers metadanych, metadane i plik etykiety są zapisywane w pliku TFLite za pomocą metody 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 spakować dowolną liczbę powiązanych plików do modelu poprzez load_associated_files . Wymagane jest jednak spakowanie przynajmniej tych plików, które są udokumentowane w metadanych. W tym przykładzie spakowanie pliku etykiety jest obowiązkowe.

Wizualizuj metadane

Możesz użyć Netron do wizualizacji swoich metadanych lub możesz odczytać metadane z modelu TensorFlow Lite do formatu json za pomocą 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ą funkcji Android Studio ML Binding .

Wersjonowanie metadanych

Schemat metadanych jest wersjonowany zarówno przez numer wersji Semantic, który śledzi zmiany w pliku schematu, jak i przez identyfikację pliku Flatbuffers, która wskazuje na prawdziwą zgodność wersji.

Numer wersji semantycznej

Schemat metadanych jest wersjonowany przez numer wersji Semantic , taki jak MAJOR.MINOR.PATCH. Śledzi zmiany schematu zgodnie z regułami tutaj . Zobacz historię pól dodanych po wersji 1.0.0 .

Identyfikacja pliku Flatbuffers

Wersjonowanie semantyczne gwarantuje zgodność przy przestrzeganiu reguł, ale nie oznacza prawdziwej niezgodności. Podbijanie numeru MAJOR nie musi koniecznie oznaczać, że kompatybilność wsteczna jest zepsuta. Dlatego używamy identyfikacji pliku Flatbuffers , file_identifier , aby oznaczyć prawdziwą zgodność schematu metadanych. Identyfikator pliku ma dokładnie 4 znaki. Jest on przypisany do określonego schematu metadanych i nie może być zmieniany przez użytkowników. Jeśli z jakiegoś powodu musi zostać naruszona zgodność wsteczna schematu metadanych, identyfikator_pliku wzrośnie, na przykład z „M001” do „M002”. Oczekuje się, że identyfikator_pliku będzie zmieniany znacznie rzadziej niż wersja_metadanych.

Minimalna niezbędna wersja parsera metadanych

Minimalna niezbędna wersja parsera metadanych to minimalna wersja parsera metadanych (kod wygenerowany przez Flatbuffers), który może w pełni odczytać metadane Flatbuffers. Wersja jest faktycznie największym numerem wersji wśród wersji wszystkich wypełnionych pól i najmniejszą kompatybilną wersją wskazaną przez identyfikator pliku. Minimalna wymagana wersja parsera metadanych jest automatycznie wypełniana przez MetadataPopulator , gdy metadane są wypełniane w modelu TFLite. Zobacz ekstraktor metadanych , aby uzyskać więcej informacji o tym, jak używana jest minimalna wymagana wersja parsera metadanych.

Przeczytaj metadane z modeli

Biblioteka Metadata Extractor jest wygodnym narzędziem do odczytywania metadanych i powiązanych plików z modeli na różnych platformach (patrz wersja Java i wersja C++ ). Możesz zbudować własne narzędzie do ekstrakcji metadanych w innych językach, korzystając z biblioteki Flatbuffers.

Przeczytaj metadane w Javie

Aby korzystać z biblioteki Metadata Extractor w aplikacji na Androida, zalecamy korzystanie z narzędzia TensorFlow Lite Metadata AAR hostowanego w MavenCentral . Zawiera klasę MetadataExtractor , a także powiązania FlatBuffers Java dla schematu metadanych i schematu modelu .

Możesz to określić w zależnościach build.gradle w następujący sposób:

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

Aby korzystać z nocnych migawek, upewnij się, że dodano repozytorium migawek Sonatype .

Możesz zainicjować obiekt MetadataExtractor za pomocą ByteBuffer , który wskazuje na model:

public MetadataExtractor(ByteBuffer buffer);

ByteBuffer musi pozostać niezmieniony przez cały okres istnienia obiektu MetadataExtractor . Inicjalizacja może się nie powieść, jeśli identyfikator pliku Flatbuffers metadanych modelu nie jest zgodny z parserem metadanych. Zobacz wersjonowanie metadanych , aby uzyskać więcej informacji.

Z pasującymi identyfikatorami plików, ekstraktor metadanych z powodzeniem odczyta metadane wygenerowane ze wszystkich przeszłych i przyszłych schematów dzięki mechanizmowi kompatybilności w przód i wstecz Flatbuffers. Jednak pola z przyszłych schematów nie mogą być wyodrębniane przez starsze ekstraktory metadanych. Minimalna niezbędna wersja metadanych parsera wskazuje minimalną wersję parsera metadanych, która może w pełni odczytać metadane Flatbuffers. Możesz użyć następującej metody, aby sprawdzić, czy spełniony jest minimalny wymagany warunek wersji parsera:

public final boolean isMinimumParserVersionSatisfied();

Dozwolone jest przekazywanie modelu bez metadanych. Jednak wywoływanie metod odczytujących z metadanych spowoduje błędy w czasie wykonywania. Możesz sprawdzić, czy model posiada metadane, wywołując metodę hasMetadata :

public boolean hasMetadata();

MetadataExtractor zapewnia wygodne funkcje, aby uzyskać metadane tensorów wejścia/wyjścia. 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ż schemat modelu TensorFlow Lite obsługuje wiele podgrafów, interpreter TFLite obecnie obsługuje tylko jeden podwykres. Dlatego MetadataExtractor pomija indeks podwykresu jako argument wejściowy w swoich metodach.

Przeczytaj powiązane pliki z modeli

Model TensorFlow Lite z metadanymi i powiązanymi plikami jest zasadniczo plikiem zip, który można rozpakować za pomocą popularnych narzędzi zip, aby pobrać powiązane pliki. Na przykład możesz rozpakować mobilenet_v1_0.75_160_quantized i wyodrębnić plik etykiety w modelu w następujący 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

Możesz także czytać powiązane pliki za pomocą biblioteki Metadata Extractor.

W Javie przekaż nazwę pliku do metody 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;