Metadane TensorFlow Lite zapewniają standard opisów modeli. Metadane są ważnym źródłem wiedzy o działaniu modelu oraz informacji wejściowych/wyjściowych. Metadane składają się z obu
- części czytelne dla człowieka, które przekazują najlepsze praktyki podczas korzystania z modelu, oraz
- części do odczytu maszynowego, które mogą być wykorzystywane przez generatory kodu, takie jak generator kodu TensorFlow Lite dla systemu Android i funkcja Android Studio ML Binding .
Wszystkie modele obrazów opublikowane w TensorFlow Hub zostały wypełnione metadanymi.
Model z formatem metadanych
![model_z_metadanymi](https://www.tensorflow.org/lite/images/convert/model_with_metadata.png?authuser=3&hl=pl)
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"
. Do niektórych modeli mogą być dołączone powiązane pliki, takie jak pliki etykiet klasyfikacyjnych . Pliki te są łączone na końcu oryginalnego pliku modelu w postaci pliku ZIP przy użyciu trybu „dołączania” pliku ZipFile (tryb 'a'
). Interpreter TFLite może korzystać z nowego formatu pliku w taki sam sposób jak poprzednio. Aby uzyskać więcej informacji, zobacz Spakowanie skojarzonych plików .
Zapoznaj się z poniższą instrukcją dotyczącą wypełniania, wizualizowania i odczytywania metadanych.
Skonfiguruj narzędzia metadanych
Przed dodaniem metadanych do modelu będziesz potrzebować konfiguracji środowiska programistycznego Python, aby uruchomić TensorFlow. Szczegółowy przewodnik dotyczący tego, jak to skonfigurować, znajduje się tutaj .
Po skonfigurowaniu środowiska programistycznego Python będziesz musiał zainstalować dodatkowe narzędzia:
pip install tflite-support
Narzędzia metadanych TensorFlow Lite obsługują język Python 3.
Dodawanie metadanych przy użyciu interfejsu API Flatbuffers Python
Metadane modelu w schemacie składają się z trzech części:
- Informacje o modelu — ogólny opis modelu oraz elementy, takie jak warunki licencji. Zobacz ModelMetadata .
- Informacje wejściowe — opis danych wejściowych i wymaganego przetwarzania wstępnego, takiego jak normalizacja. Zobacz SubGraphMetadata.input_tensor_metadata .
- Informacje wyjściowe — opis wyników i wymaganego przetwarzania końcowego, takiego jak mapowanie na etykiety. Zobacz SubGraphMetadata.output_tensor_metadata .
Ponieważ TensorFlow Lite obsługuje w tym momencie tylko pojedynczy podgraf, generator kodu TensorFlow Lite i funkcja Android Studio ML Binding 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ą projektowane z myślą o konkretnych typach modeli, ale raczej o typach danych wejściowych i wyjściowych. Nie ma znaczenia, co model funkcjonalnie robi, o ile typy danych wejściowych i wyjściowych składają się z następujących elementów lub ich kombinacji, jest on obsługiwany przez metadane TensorFlow Lite:
- Cecha - Liczby będące liczbami całkowitymi bez znaku lub zmiennoprzecinkowe32.
- Obraz — metadane obsługują obecnie obrazy RGB i w skali szarości.
- Obwiednia — prostokątne obwiednie. Schemat obsługuje różne schematy numeracji .
Spakuj powiązane pliki
Modele TensorFlow Lite mogą zawierać różne powiązane pliki. Na przykład modele języka naturalnego zwykle zawierają pliki słowników, które odwzorowują fragmenty słów na identyfikatory słów; modele klasyfikacji mogą zawierać pliki etykiet wskazujące kategorie obiektów. Bez powiązanych plików (jeśli istnieją) model nie będzie działał dobrze.
Powiązane pliki można teraz dołączyć do modelu za pośrednictwem biblioteki metadanych języka Python. Nowy model TensorFlow Lite staje się plikiem ZIP zawierającym zarówno model, jak i powiązane z nim pliki. Można go rozpakować za pomocą popularnych narzędzi zip. Ten nowy format modelu nadal używa tego samego rozszerzenia pliku, .tflite
. Jest kompatybilny z istniejącym frameworkiem i interpreterem TFLite. Aby uzyskać więcej informacji, zobacz Pakowanie metadanych i powiązanych plików do modelu .
Powiązane informacje o pliku 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 dla systemu Android może automatycznie zastosować odpowiednie przetwarzanie wstępne/końcowe dla obiektu. Aby uzyskać więcej informacji, zobacz sekcję <Użycie Codegen> każdego powiązanego typu pliku w schemacie.
Parametry normalizacyjne i kwantyzacyjne
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 zakresach wartości.
Kwantyzacja modelu to technika, która pozwala na zmniejszoną precyzję reprezentacji wag i opcjonalnie aktywację zarówno do przechowywania, jak i obliczeń.
Jeśli chodzi o przetwarzanie wstępne i przetwarzanie końcowe, normalizacja i kwantyzacja to dwa niezależne etapy. Oto szczegóły.
Normalizacja | Kwantyzacja | |
---|---|---|
Przykład wartości parametrów obrazu wejściowego w MobileNet odpowiednio dla modelu zmiennoprzecinkowego i kwantowego. | 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 wywołać? | Dane wejściowe : Jeśli dane wejściowe są znormalizowane podczas uczenia, dane wejściowe wnioskowania muszą zostać odpowiednio znormalizowane. Wyjścia : dane wyjściowe nie będą ogólnie normalizowane. | Modele pływakowe nie wymagają kwantyzacji. Model skwantowany może, ale nie musi, wymagać kwantyzacji w przetwarzaniu wstępnym/końcowym. Zależy to od typu danych tensorów wejścia/wyjścia. - tensory float: nie jest wymagana kwantyzacja w przetwarzaniu wstępnym/końcowym. Quant op i dequant op są wstawiane do wykresu modelu. - tensory int8/uint8: wymagają kwantyzacji w przetwarzaniu wstępnym/końcowym. |
Formuła | normalized_input = (wejście - średnia) / std | Kwantyzacja dla wejść : 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łniane automatycznie przez konwerter TFLite i zapisywane w pliku modelu tflite. |
Jak uzyskać parametry? | Poprzez API MetadataExtractor [2] | Poprzez API TFLite Tensor [1] lub poprzez API MetadataExtractor [2] |
Czy modele zmiennoprzecinkowe i ilościowe mają tę samą wartość? | Tak, modele zmiennoprzecinkowe i ilościowe mają te same parametry normalizacji | Nie, model pływakowy nie wymaga kwantyzacji. |
Czy generator kodu TFLite lub powiązanie Android Studio ML automatycznie generuje je podczas przetwarzania danych? | Tak | Tak |
[1] Interfejs API języka Java TensorFlow Lite i interfejs API TensorFlow Lite C++ .
[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]. Ogólnie jednak należy zawsze przetwarzać dane zgodnie z parametrami normalizacji i kwantyzacji, jeśli ma to zastosowanie.
Biblioteka zadań TensorFlow Lite może obsłużyć normalizację, jeśli skonfigurujesz NormalizationOptions
w metadanych. Przetwarzanie kwantyzacji i dekwantyzacji jest zawsze enkapsulowane.
Przykłady
Przykłady wypełniania metadanych dla różnych typów modeli znajdziesz tutaj:
Klasyfikacja obrazu
Pobierz tutaj skrypt, który zapełni metadane do pliku 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 specyfikacje modelu do skryptu. W pozostałej części tego przewodnika wyróżnione zostaną niektóre kluczowe sekcje przykładu klasyfikacji obrazów, aby zilustrować kluczowe elementy.
Zagłęb się w przykład klasyfikacji obrazów
Informacje o modelu
Metadane rozpoczynają się od utworzenia informacji o nowym 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ć informację wejściową lub wyjściową dotyczącą tensora:
# Creates input info.
input_meta = _metadata_fb.TensorMetadataT()
# Creates output info.
output_meta = _metadata_fb.TensorMetadataT()
Wejście obrazu
Obraz jest typowym typem danych wejściowych w przypadku uczenia maszynowego. Metadane TensorFlow Lite obsługują takie informacje, jak przestrzeń kolorów i informacje dotyczące wstępnego przetwarzania, takie jak normalizacja. Wymiar obrazu nie wymaga ręcznego określenia, ponieważ jest już zapewniony przez kształt tensora wejściowego i można go wywnioskować automatycznie.
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 etykiety
Etykietę można zmapować do tensora wyjściowego poprzez powiązany plik przy użyciu 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 metadanych Flatbuffers 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ć do modelu dowolną liczbę powiązanych plików, korzystając z 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 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 także wyświetlanie metadanych za pomocą funkcji Android Studio ML Binding .
Wersjonowanie metadanych
Wersjonowanie schematu metadanych odbywa się zarówno na podstawie numeru wersji Semantic, który śledzi zmiany w pliku schematu, jak i na podstawie identyfikacji pliku Flatbuffers, która wskazuje prawdziwą zgodność wersji.
Numer wersji semantycznej
Wersja schematu metadanych jest oparta na numerze wersji semantycznej , takim jak MAJOR.MINOR.PATCH. Śledzi zmiany schematu zgodnie z zasadami tutaj . Zobacz historię pól dodanych po wersji 1.0.0
.
Identyfikacja pliku Flatbuffers
Wersjonowanie semantyczne gwarantuje zgodność, jeśli przestrzega się zasad, ale nie oznacza prawdziwej niezgodności. Podbicie numeru MAJOR nie musi oznaczać, że kompatybilność wsteczna jest zepsuta. Dlatego używamy identyfikacji pliku Flatbuffers , identyfikator_pliku , aby wskazać prawdziwą zgodność schematu metadanych. Identyfikator pliku ma dokładnie 4 znaki. Jest on przypisany do określonego schematu metadanych i nie podlega zmianom przez użytkowników. Jeśli z jakiegoś powodu wsteczna kompatybilność schematu metadanych musi zostać przerwana, identyfikator pliku zostanie podniesiony, na przykład z „M001” na „M002”. Oczekuje się, że identyfikator pliku będzie zmieniany znacznie rzadziej niż wersja metadata_version.
Minimalna niezbędna wersja analizatora metadanych
Minimalna niezbędna wersja analizatora metadanych to minimalna wersja analizatora metadanych (kod wygenerowany przez Flatbuffers), która może w całości odczytać Flatbuffers metadanych. Wersja to w rzeczywistości największy numer wersji spośród wersji we wszystkich wypełnionych polach i najmniejsza kompatybilna wersja wskazywana przez identyfikator pliku. Minimalna niezbędna wersja analizatora metadanych jest automatycznie wypełniana przez MetadataPopulator
podczas wypełniania metadanych do modelu TFLite. Więcej informacji o tym, jak używana jest minimalna niezbędna wersja analizatora metadanych, można znaleźć w ekstraktorze metadanych .
Przeczytaj metadane z modeli
Biblioteka Metadata Extractor to wygodne narzędzie do odczytywania metadanych i powiązanych plików z modeli na różnych platformach (zobacz wersję Java i wersję C++ ). Możesz zbudować własne narzędzie do wyodrębniania 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 użycie TensorFlow Lite Metadata AAR hostowanego w MavenCentral . Zawiera klasę MetadataExtractor
, a także powiązania Java FlatBuffers 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 dodałeś repozytorium migawek Sonatype .
Możesz zainicjować obiekt MetadataExtractor
za pomocą ByteBuffer
wskazującego model:
public MetadataExtractor(ByteBuffer buffer);
ByteBuffer
musi pozostać niezmieniona przez cały okres istnienia obiektu MetadataExtractor
. Inicjalizacja może się nie powieść, jeśli identyfikator pliku Flatbuffers metadanych modelu nie jest zgodny z identyfikatorem analizatora metadanych. Aby uzyskać więcej informacji, zobacz wersjonowanie metadanych .
Dzięki pasującym identyfikatorom plików ekstraktor metadanych pomyślnie odczyta metadane wygenerowane ze wszystkich przeszłych i przyszłych schematów dzięki mechanizmowi kompatybilności do przodu i wstecz Flatbufferów. Jednak starsze moduły wyodrębniania metadanych nie mogą wyodrębniać pól z przyszłych schematów. Minimalna niezbędna wersja metadanych parsera wskazuje minimalną wersję parsera metadanych, która może w całości odczytać płaskie bufory metadanych. Możesz użyć następującej metody, aby sprawdzić, czy spełniony jest warunek minimalnej niezbędnej wersji analizatora składni:
public final boolean isMinimumParserVersionSatisfied();
Dozwolone jest przekazywanie modelu bez metadanych. Jednak wywoływanie metod odczytujących metadane 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 umożliwiające uzyskanie metadanych 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 obsługuje obecnie tylko jeden podgraf. Dlatego MetadataExtractor
pomija indeks podgrafu jako argument wejściowy w swoich metodach.
Przeczytaj powiązane pliki z modeli
Model TensorFlow Lite z metadanymi i powiązanymi plikami to zasadniczo plik ZIP, który można rozpakować za pomocą typowych narzędzi ZIP, aby uzyskać 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 odczytać 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;