Nie musisz już wybierać między wygodą gotowej AI a elastycznością niestandardowego modelu – możesz wdrożyć oba te rozwiązania w jednej, bardzo prostej aplikacji bez dodawania megabajtów niepotrzebnych danych binarnych.
Podczas tej sesji pokażemy, jak utworzyć taką architekturę dual-stack w jednej aplikacji na Androida. Dowiesz się, jak wykorzystać ML Kit do gotowych klasycznych zadań ML (takich jak skanowanie dokumentów) oraz LiteRT w Usługach Play do niestandardowych zadań związanych z rozpoznawaniem obrazów lub dźwiękiem. Szczegółowo omówimy, jak obie ścieżki implementacji łączą się, aby wykorzystać nowoczesne środowisko wykonawcze LiteRT, zapewniając aplikacji płynne działanie z akceleracją sprzętową na procesorach i GPU przy praktycznie zerowym rozmiarze pobierania.
Najważniejsze wnioski dla deweloperów:
– Bezkompromisowa wydajność: zarówno gotowe, jak i niestandardowe modele są automatycznie akcelerowane sprzętowo za pomocą ujednoliconego interfejsu CompiledModel API.
– Mikropliki APK: znacznie zmniejsz rozmiar pobieranej aplikacji, przenosząc środowiska wykonawcze ML Kit i LiteRT do usług Google Play.
– Integracja hybrydowa: opanuj uruchamianie wielu przepływów pracy ML obok siebie w środowisku produkcyjnym bez konfliktów zasobów.
play-services-litert, wywołanie LiteRt.initialize w celu uzyskania środowiska i przekazanie go do CompiledModel.create.Transkrypcja
Dobry wieczór.
Zaraz zaczynamy.
Dlatego gdy obecnie mówi się o „AI na urządzeniu”, często ma się na myśli duże modele językowe.
Wcześniej dzisiaj odbyło się kilka prelekcji na temat Gemini Nano, które zostały omówione w ML Kit, Firebase i wielu innych usługach Google.
Ta sesja dotyczy drugiej połowy: klasycznego uczenia maszynowego i modelu, który przynosisz ze sobą.
Prawdopodobnie zdarzyło Ci się już dzisiaj skorzystać z niej kilka razy, nawet o tym nie wiedząc.
Zastanów się, czy używasz aplikacji, w których rozmywasz tło, używasz skanera kodów kreskowych lub edytujesz obrazy.
Wiele z nich opiera się na klasycznym uczeniu maszynowym i zwykle działa na urządzeniu.
Jeśli kiedykolwiek dodawaliście którąś z tych funkcji do własnej aplikacji lub pakietu APK, często musieliście wybierać między gotowym interfejsem API a własnym modelem.
Jak wpłynie to na rozmiar aplikacji?
Dzisiaj przekonacie się, że nie musicie wybierać między gotowym rozwiązaniem a własnym modelem.
Możesz zrobić obie te rzeczy za pomocą jednego środowiska wykonawczego.
Nazywam się Chintan Parikh.
Jestem menedżerem produktu LiteRT, a ze mną jest Fergus, kierownik techniczny ds. usług ML na Androidzie.
Cześć.
Na koniec dowiesz się, jak utworzyć jedną aplikację, która uruchamia 2 modele na każdej klatce z kamery z szybkością około 30 klatek na sekundę.
Ta prezentacja składa się z 4 części.
W pierwszej części omówimy rozwiązania Google AI na urządzeniu, skupiając się na klasycznych systemach uczących się, czyli ML Kit i LiteRT.
Następnie omówimy nowości w LiteRT i usługach Google Play.
Omówimy też nowy interfejs API CompiledModel z LiteRT i obsługiwane przez nas urządzenia.
Po trzecie, pokażemy Ci, jak utworzyć nową aplikację.
Fergus omówi tworzenie aplikacji za pomocą ML Kit i niestandardowego modelu w jednym pliku APK.
Na koniec pokażemy, jak uaktualnić istniejącą aplikację za pomocą trybu agenta.
Możesz też utworzyć szkielet nowej aplikacji przy pomocy tego agenta.
OK.
Zacznijmy od tego, czym jest LiteRT.
LiteRT to środowisko wykonawcze Google do wnioskowania na urządzeniu dla Twoich modeli.
Używa tego samego formatu pliku .tflite, który był używany wcześniej w TensorFlow Lite.
Został on przeprojektowany pod kątem wydajności i obsługuje wiele platform.
Oznacza to, że możesz importować modele z PyTorch, TensorFlow, a nawet JAX, aby przekonwertować je na format FlatBuffer dla LiteRT.
Od 2022 roku TensorFlow Lite w usługach Google Play jest oficjalnym środowiskiem wykonawczym Androida na urządzeniu dla modeli niestandardowych.
Dzisiaj wprowadzamy dużą aktualizację, o której będziemy dużo mówić.
Uaktualnienie wprowadzi najnowszy interfejs API LiteRT CompiledModel, w tym nowe, ulepszone wnioskowanie GPU, które będzie 1,4 raza szybsze, a także umożliwi tworzenie mniejszych aplikacji o znacznie mniejszych rozmiarach plików APK.
Dlaczego więc udostępniamy ją przez Usługi Google Play?
Jest kilka zalet, a rozmiar aplikacji i rozdęte pliki APK to zdecydowanie duży problem, o którym słyszę w wielu rozmowach. To prawdziwe wyzwanie, prawda?
Dzięki temu środowisko wykonawcze jest niewielkie.
Środowisko wykonawcze nie znajduje się w pliku APK, więc korzystasz z cienkiego klienta, co zmniejsza rozmiar pliku APK o około 8 MB.
Druga korzyść to skuteczność.
Masz jedną kopię środowiska wykonawczego, więc środowisko wykonawcze LiteRT jest udostępniane wszystkim aplikacjom.
Jeśli masz wiele aplikacji, każda z nich może zaoszczędzić 8 MB.
To bardzo dużo, gdy próbujesz zaoszczędzić miejsce na dysku i mieć mniejszą aplikację.
Po drugie, jest utrzymywany.
Google dostarcza poprawki błędów, rozwiązuje problemy ze sterownikami GPU, których nie musisz rozwiązywać, a wszelkie inne aktualizacje zabezpieczeń są dostarczane w ramach automatycznych aktualizacji.
Jak już wspominałem, GPU jest szybszy – 1,4 raza szybszy.O tym też opowiem bardziej szczegółowo.
Jeśli chodzi o zasięg, możemy wysyłać wiadomości na starsze urządzenia z Androidem.
LiteRT w usługach Google Play obsługuje urządzenia z Androidem 7 z 2016 r.
Fergus pokaże też inne nowe urządzenia, na które rozszerzamy naszą ofertę.
To jest pojazd dostawczy, a teraz porozmawiajmy o następnym kroku, czyli środowisku wykonawczym.
LiteRT nie jest więc nowym ani eksperymentalnym rozwiązaniem.
TensorFlow Lite i LiteRT działają już w ponad 250 tys. aplikacji.
Obecnie działa na ponad 3,8 miliarda urządzeń.
Wiele aplikacji, których używasz, może działać na tej platformie, nawet jeśli o tym nie wiesz.
To oznacza też ponad bilion wnioskowań dziennie, prawda?
Przy tej skali z pewnością napotkaliśmy każdy możliwy problem z chipsetem, udało nam się rozwiązać problemy z pamięcią ROM i sterownikami GPU, a teraz mamy dla Ciebie rozwiązanie.
LiteRT jest również używany przez Google w flagowych aplikacjach, na różnych platformach, a nawet na kilku urządzeniach.
Efekty w YouTube Shorts, segmentacja tła w Meet czy usuwanie rozmycia to tylko niektóre przykłady, w których filmy w czasie rzeczywistym i ciężkie modele do generowania obrazów działają na LiteRT.
To również bardzo ważne, ponieważ szybkie i angażujące użytkowników przypadki użycia stają się niezwykle istotne.
Jest to więc to samo środowisko wykonawcze, które wzmocniliśmy na potrzeby tych flagowych funkcji, i to właśnie otrzymujesz dzięki Usługom Google Play.
Omówmy też, dlaczego warto korzystać z AI na urządzeniu.
Jeśli zależy Ci na krótkim czasie oczekiwania, prywatności, pracy offline lub niskich kosztach, uruchom model offline.
Może być ich więcej, ale te są najbardziej oczywiste i najczęściej wymieniane w kontekście działania na urządzeniu.
Uruchamianie na urządzeniu nie zawsze jest bezpłatne.
Ma ono pewne niuanse i wyzwania.
Omówimy też niektóre z tych wyzwań i pokażemy, jak sobie z nimi poradzić.
Wydajność: jak widzieliście w niektórych przykładach z poprzednich aplikacji, budżety na opóźnienia i pamięć są zawsze napięte.
Wideo i audio w czasie rzeczywistym wymagają najwyższej wydajności.
Nawet proste funkcje interaktywne muszą działać szybko.
W przeciwnym razie stracisz zaangażowanie użytkowników.
Różnorodność sprzętu: istnieją setki układów SoC z różnymi konfiguracjami procesorów i GPU.
Nie możesz napisać kodu dla wszystkich tych przypadków, prawda?
Jak sobie z tym poradzić?
Rozmiar pliku APK: dołączenie środowiska wykonawczego zwiększa rozmiar każdego pobrania, co może mieć wpływ na współczynniki konwersji.
Dostosowywanie: trenowanie modelu, jakość, rozmiar modelu – wszystkie te kwestie są niezwykle ważne jeszcze przed wdrożeniem.
Tak, stworzenie świetnej aplikacji na urządzenie może być trudne.
W każdej z tych sytuacji chcemy, aby platforma wykonywała pracę za Ciebie, a nie na odwrót, prawda?
Oferta Google dotycząca urządzeń powstała, aby sprostać tym wyzwaniom. Omówimy ją w następnej kolejności.
Skupimy się dziś na 2 prostych rozwiązaniach.
Istnieją 2 proste sposoby dodawania AI na urządzeniu za pomocą Usług Google Play.
Ścieżka 1 to gotowa ścieżka z użyciem ML Kit, prawda?
Są to gotowe do użycia interfejsy API do rozpoznawania obrazów i języka, które wymagają ograniczonej wiedzy z zakresu uczenia maszynowego. Dostępnych jest wiele modeli, które są dostarczane przez Usługi Google Play.
Na kolejnych slajdach omówimy kilka przykładów.
Ścieżka niestandardowa, która jest realizowana przez LiteRT.
LiteRT umożliwia korzystanie z własnego modelu i uruchamianie go na procesorze lub GPU.
Środowisko wykonawcze również pochodzi z Usług Google Play.
Nie musisz więc umieszczać go w pliku APK.
Te opcje nie wykluczają się wzajemnie.
Można też zawsze połączyć je w pary.
I właśnie to stworzymy dzisiaj w ciągu kilku minut.
Najpierw jednak omówmy, co obejmuje ML Kit.
Oto co ML Kit oferuje od razu po zainstalowaniu.
Jeśli więc uważasz, że niektóre z tych funkcji spełniają Twoje potrzeby, to świetny punkt wyjścia i masz już przewagę.
Mamy funkcje rozpoznawania obrazów, kodów kreskowych, dokumentów, tekstu, pozycji i wiele innych, interfejsy API do obsługi języków, takie jak tłumaczenie, inteligentne odpowiedzi, a nawet wyodrębnianie encji.
Najważniejsze jest to, że wiele z tych interfejsów API do rozpoznawania obrazów i języka działa z LiteRT.
Jeśli więc ML Kit spełnia Twoje potrzeby, możesz zacząć od niego.
A gdy nie jest, możesz użyć własnego modelu.
I tu dochodzimy do kluczowej kwestii: ML Kit i Twój model niestandardowy nie będą 2 środowiskami wykonawczymi, jak już wspomniałem.
Można je traktować jako 2 drzwi wejściowe prowadzące do tego samego LiteRT, który będzie działać pod maską.
LiteRT będzie więc środowiskiem wykonawczym, które będzie koordynować obie te funkcje.
Jeśli więc Twoja aplikacja korzysta już ze Sklepu Play, możesz użyć ML Kit.
W przeciwnym razie omówimy też ścieżkę LiteRT.
Omówmy też nowości w LiteRT.
Jak już wspomnieliśmy, LiteRT to rozwinięcie TensorFlow Lite.
Największe ulepszenia to szybszy GPU.
Szybszy procesor graficzny obsługuje OpenCL, OpenGL, a także zapewnia obsługę wielu platform, nawet w przypadku backendów Metal.
Możesz więc używać tego rozwiązania na wielu platformach, jeśli jest taka potrzeba.
Jest też prostsza.
Mamy jeden ujednolicony przepływ pracy na potrzeby akceleracji CPU, GPU i NPU.
Procesory i GPU są obecnie dostępne w usługach Google Play, natomiast NPU jest obecnie dołączony do LiteRT i nadal nad nim pracujemy.
Wcześniej każdy akcelerator wymagał innej konfiguracji delegata, prawda?
Wystarczy to zrobić tylko raz.
Dzięki temu istnieje jeden interfejs API z automatycznym przełączaniem na procesor i nie trzeba konfigurować dedykowanych delegatów.
Możesz po prostu użyć wywołań akceleratora, które mogą zarządzać tym znacznie prościej i przy użyciu mniejszej ilości kodu.
Jest też bardzo wydajny – ten sam model działa na wielu platformach, jak już wspominałem.
Elastyczność będzie miała kluczowe znaczenie.
Format .tflite pozostaje więc taki sam.
Jeśli masz już aplikację, nadal możesz używać tego formatu.
Jeśli tworzysz nową aplikację, możesz ponownie użyć tego formatu pliku.
Co ciekawe, obsługujemy też interfejs Interpreter API, który wcześniej był dostępny w TensorFlow Lite.
Jeśli więc chcesz przeprowadzić migrację etapami, interfejs Interpreter API jest dołączony do nowego LiteRT, co ułatwia migrację.
To jest środowisko wykonawcze.
Porozmawiajmy o tym, co można dzięki temu stworzyć.
Oto co obecnie tworzą deweloperzy aplikacji na Androida.
Wszystko – od efektów aparatu, edycji zdjęć, inteligentnego pisania po gry i awatary, prawda?
Wiele z tych aplikacji będzie wymagać funkcji działających w czasie rzeczywistym.
GPU wysyła klatki bezpośrednio z aparatu, więc ważne jest, aby wszystko działało szybko i w czasie rzeczywistym.
Niektóre z tych modeli do edycji zdjęć również stają się coraz bardziej wymagające.
To samo dotyczy funkcji AR/VR, które widzieliście w niektórych wersjach demonstracyjnych z okularami. Wiele z nich działa na bazie LiteRT.
To samo środowisko wykonawcze, które obsługuje teraz flagowe funkcje Google, a także usługi Google Play, dzięki czemu masz dostęp do wszystkich tych funkcji bez konieczności dołączania czegokolwiek do pakietu APK.
Teraz utwórzmy aplikację. Fergus pokaże nam, jak to zrobić.
Zróbmy to.
Dziękuję, Chintan.
Opowiem trochę o nowościach w LiteRT w usługach Google Play.
Zanim zaczniemy tworzyć, jeszcze jedna informacja: wszystko, co właśnie widzieliście, działa teraz nie tylko na telefonie. LiteRT w usługach Google Play jest też dostępny na Wear OS i systemie operacyjnym Android Automotive.
Możesz więc mieć modele działające na urządzeniu na zegarku lub innym urządzeniu do noszenia albo w samochodzie.
Wcześniej można było używać aplikacji na telefonie, która była aplikacją towarzyszącą dla Wear, ale teraz można ją uruchomić na samym urządzeniu do noszenia. To samo dotyczy Androida Automotive.
Dzięki temu masz ten sam interfejs API i ten sam model .tflite, ale więcej platform.
Nie musisz tworzyć osobnej implementacji dla każdego formatu – możesz użyć tej samej implementacji na wszystkich tych urządzeniach.
Piękno modelu dystrybucji usług Google Play polega na tym, że możemy przenieść tę funkcję na starsze urządzenia.
W przypadku systemu operacyjnego Android Automotive obsługujemy wersje od Androida 11 wydanego w 2020 r., a w przypadku Wear OS – od Wear OS 4.
OK.
Teraz omówię 2 różne ścieżki: tworzenie nowej aplikacji i uaktualnianie istniejącej.
To wszystko, co chcieliśmy omówić w tej prezentacji.
Zacznę od przykładowej aplikacji, która łączy użycie ML Kit z niestandardowym modelem GPU działającym na LiteRT.
W przypadku uaktualniania istniejącej aplikacji trzeba będzie wprowadzić 3 niewielkie zmiany: zmianę w Gradle, aby zaktualizować zależności, zmianę w init, aby włączyć LiteRT w Usługach Google Play, oraz przejście z interfejsu Interpreter API na interfejs CompiledModel API.
Zaczniemy jednak od nowej aplikacji, ponieważ przejście na nią ma o wiele więcej sensu, gdy zobaczysz, co zyskujesz.
Tworzymy więc nową aplikację.
Oto aplikacja, którą utworzymy.
Będzie to widok z kamery na żywo, w którym Ty będziesz ostry, a tło będzie miało artystyczny styl.
Zaczniemy od kadru.
Obrazy z kadru aparatu będziemy przesyłać strumieniowo przez segmentację selfie w pakiecie ML Kit.
To jeden z istniejących gotowych interfejsów API ML Kit.
W ten sposób powstanie maska pierwszego planu, która w zasadzie określi, które piksele na obrazie odpowiadają osobie na obrazie.
Następnie weźmiemy nasz model niestandardowy, który jest modelem typu przeniesienie stylu, i zastosujemy styl do obrazu.
Zastosujemy go do całej klatki, ale tak naprawdę interesuje nas tylko tło, ponieważ na koniec weźmiemy oryginalną klatkę, maskę i tło ze stylem i połączymy je za pomocą prostej logiki, aby uzyskać klatkę, w której zachowaliśmy obiekt, a tło ma styl.
Dlatego chcemy mieć Korzystamy z gotowych interfejsów API, jeśli są dostępne, i niestandardowych interfejsów API, jeśli wyróżniają naszą aplikację.
To jest pierwsza część, w której wywołujemy interfejs API ML Kit do segmentacji selfie.
// 1. Configure and create segmenter client
val segmenter = Segmentation.getClient(
SelfieSegmenterOptions.Builder()
.setDetectorMode(
SelfieSegmenterOptions.STREAM_MODE)
.build())
// 2. Prepare image & run inference
fun processFrame(mediaImage: Image) {
val image = InputImage.fromMediaImage(
mediaImage, /* rotationDegrees= */ 0)
segmenter.process(image)
.addOnSuccessListener { mask -> … }
}Czyli to jest jak zwykły interfejs API, prawda?
To jest podstawowa wiedza dla deweloperów aplikacji na Androida.
Wystarczy, że zajrzysz do dokumentacji interfejsu API lub poprosisz Gemini o stworzenie kodu.
Ale jest to dość proste.
Podczas tworzenia klienta przekazujesz mu pewne opcje.
W tym przypadku określamy tryb strumieniowania, aby móc przetwarzać strumień klatek wideo.
Następnie wywołujesz metodę process, a wywołanie zwrotne z niej pobierze maskę, która jest zwracana i obliczana przez segmentację selfie.
Dane wejściowe to obraz z aparatu.
Wszystkie te interfejsy API używają typów na poziomie aplikacji, a nie nieprzetworzonych tensorów, więc programowanie odbywa się na bardzo wysokim poziomie i jest bardzo proste.
W drugiej części, czyli w przypadku modelu niestandardowego, użyjemy modelu PyTorch.
Myślę, że Chintan pobrał go z Kaggle lub Hugging Face…
Po prawej.
Tak, możesz też przekonwertować własne.
Możesz utworzyć własny model.
Przepraszam, wracam.
Tak wygląda ten stos.
Możesz przekonwertować i skwantyzować model PyTorch, aby uzyskać model LiteRT.
Następnie możesz rozpowszechniać go wraz z aplikacją w dowolny sposób.
Może być dołączony do aplikacji jako komponent lub pobrany osobno.
Obie metody są prawidłowe.
A to z kolei działa na środowisku wykonawczym LiteRT w usługach Google Play.
Dostępne są też jądra procesora do optymalizacji na procesorze, a ML Drift to nazwa akceleratora GPU.
Tak, jak powiedziałem, otrzymujesz model TFLite. Możesz go wytrenować samodzielnie lub znaleźć istniejący model. Obie opcje działają.
Konwersja z PyTorch wymaga tylko kilku wierszy kodu w Pythonie.
import litert_torch
model = my_models.Stylizer().eval()
# Convert with torch.export under the hood
edge_model = litert_torch.convert(
model, sample_inputs)
edge_model.export("stylizer_f32.tflite")Wystarczy, że zainstalujesz LiteRT-Torch za pomocą pip, wywołasz litert_torch.convert, przekażesz sample_inputs, które mogą być losowymi danymi wejściowymi, i wyeksportujesz plik TFLite.
LiteRT-Torch to nowa nazwa ai-edge-torch, jeśli znasz to narzędzie.
Kwantyzacja jest bardzo prosta.
# Python
# previously ai_edge_quantizer
from litert_quantizer import quantizer, recipe
qt = quantizer.Quantizer("stylizer_f32.tflite")
# int8 weights, float activations
qt.load_quantization_recipe(
recipe.dynamic_wi8_afp32())
qt.quantize().export_model("stylizer_int8.tflite")Importujesz kwantyzator i przepis z LiteRT Quantizer.
Podczas tworzenia kwantyzatora przekazujesz oryginalny model z reprezentacją zmiennoprzecinkową i przepis, który jest standardowym przepisem zalecanym dla GPU, który używa 8-bitowych wag liczb całkowitych, ale zachowuje aktywacje jako 32-bitowe liczby zmiennoprzecinkowe.
Następnie wystarczy wywołać funkcję quantize, a potem export_model, aby zapisać model wyjściowy.
Otrzymasz skwantyzowany model, który możesz uruchomić. Będzie on miał znacznie mniejsze wagi i będzie działał wydajniej.
Tak, interfejs API CompiledModel i GPU to mocne strony tego urządzenia.
Jak wspomniał Chintan, oznacza to znaczne przyspieszenie w porównaniu ze starszymi GPU TFLite.
Dokładne liczby będą się nieco różnić w zależności od modelu, ale możesz oczekiwać 1,4 raza więcej.
Do 10 razy szybciej niż wnioskowanie na procesorze, więc to duża zaleta.
Jeśli większość z Was korzysta obecnie z modeli, prawdopodobnie uruchamiacie je na procesorze, przez co tracicie około 10-krotnie większą wydajność, którą można uzyskać dzięki GPU.
To naprawdę zachęca.
Co sprawia, że jest szybki?
Obsługujemy wiele rzeczy, na przykład asynchroniczne wykonywanie, dzięki czemu można pobrać AHardwareBuffer i przekazać go bezpośrednio lub bufor OpenGL z potoku renderowania aparatu i przekazać go bezpośrednio do bufora tensora.
Obsługujemy optymalizację bez kopiowania, więc gdy próbujesz przetwarzać dane z niskim budżetem opóźnienia, np. gdy musisz przetworzyć każdą klatkę w ciągu kilkudziesięciu milisekund, nawet zwykłe skopiowanie bufora pamięci może być nietrywialnym obciążeniem.
Dlatego w przypadku aplikacji, które wymagają bardzo wysokiej wydajności w czasie rzeczywistym, warto użyć optymalizacji bez kopiowania, którą obsługujemy.
Jak wspomniał Chintan, jest to rozwiązanie na wielu platformach z obsługą OpenGL, OpenCL i Metal jako backendów GPU.
I wreszcie, co nie mniej ważne, optymalizator ML Drift jest dostępny na zasadach open source.
Jest dostępny na licencji Apache.
Google niedawno udostępniło go jako open source.
OK, a tutaj jest kod aplikacji.
// Kotlin
// Build once, off the main thread.
private val model: CompiledModel =
CompiledModel.create(
context.assets,
"stylizer_int8.tflite",
// Simple GPU setup!
CompiledModel.Options(Accelerator.GPU),
environment
)
// Reuse buffers across frames.
private val inputBuffers = model.createInputBuffers()
private val outputBuffers = model.createOutputBuffers()
fun stylize(input: FloatArray): FloatArray {
inputBuffers[0].writeFloat(input)
model.run(inputBuffers, outputBuffers) // sync
return outputBuffers[0].readFloat()
}Jak widać, jest on dość mały i prosty.
Wystarczy, że utworzysz model raz, a potem możesz go używać w każdym kadrze.
W tym przypadku CompiledModel.create przekazuje plik .tflite.
Wystarczy określić, że chcesz uruchomić na GPU, a następnie skonstruować dane wejściowe i outputBuffers.
Następnie w głównej pętli, w której przetwarzasz każdą klatkę, wywołujesz model.run, przekazując dane wejściowe i wyjściowe.
Po napisaniu do inputBuffers zadzwoń do model.run, a następnie przeczytaj z outputBuffers.
OK.
Tak, a jeśli określisz tam GPU, będzie działać na GPU.
Jeśli określisz tam również procesor i GPU, spróbuje uruchomić GPU.
Jeśli z jakiegoś powodu GPU jest niedostępny, zostanie użyty CPU.
W niektórych przypadkach procesor może nie być wystarczająco wydajny dla aplikacji. Wtedy warto określić GPU w ten sposób.
Częściej jednak chcesz mieć procesor jako rozwiązanie zastępcze.
OK.
Dlatego utworzyliśmy go z dołączonym LiteRT, który nie korzysta jeszcze z Usług Google Play.
Pokażę Ci, jak używać LiteRT w usługach Google Play.
Wprowadziliśmy 3 zmiany. Pierwsza dotyczy zależności.
// Easier with CompiledModel API: 3 steps
// 1. app/build.gradle: replace litert with play-services-litert
- implementation 'com.google.ai.edge.litert:litert:...'
+ implementation 'com.google.android.gms:play-services-litert:17.0.0' // also pulls in litert-apiWystarczy, że zastąpisz zależność w pliku Gradle lub w innym miejscu, w którym określasz zależności pakietu Maven, niezależnie od używanego systemu kompilacji.
Usuń zależność litert lub dowolną zależność starszego pakietu Maven TensorFlow Lite i zastąp ją zależnością play-services-litert.
Spowoduje to również pobranie pakietu litert-api.
Jeśli piszesz warstwę pośrednią, która ma zależeć od LiteRT, ale nie ma znaczenia, czy środowisko wykonawcze pochodzi z aplikacji czy z Usług Google Play, możesz po prostu polegać na interfejsie LiteRT API i użyć środowiska jako parametru wejściowego.
Drugi krok to parametr środowiska.
W tym miejscu podajesz wstrzykiwanie zależności, aby określić, że chcesz używać LiteRT w Usługach Google Play.
Importujesz więc gms.litert.LiteRt i wywołujesz funkcję inicjowania, przekazując kontekst, czyli aktywność na Androidzie.
// 2. Initialize the LiteRT Environment from Play services (context = your Activity)
- val environment = Environment.create(...)
+ import com.google.android.gms.litert.LiteRt
+ val environment = LiteRt.initialize(context).await()
// 3. Pass environment whenever you call CompiledModel.create
// That's it! The rest of your app uses the normal CompiledModel APIs from litert-api.Jest to operacja asynchroniczna, więc musisz wywołać .await lub oprzeć resztę na wywołaniu zwrotnym.
Na koniec, gdy masz już to środowisko, przekazujesz je za każdym razem, gdy wywołujesz CompiledModel.create.
Dzięki temu będzie używać środowiska wykonawczego LiteRT z usług Google Play.
To wszystko.
Oznacza to, że pozostałe części aplikacji używają dokładnie tych samych interfejsów API LiteRT CompiledModel z interfejsu LiteRT API.
Pozostała część kodu wnioskowania nie zmienia się w przypadku korzystania z usług Google Play.
Migrację można przeprowadzać stopniowo.
Nie musisz robić tego od razu – możesz przenosić po jednym komponencie.
Jeśli masz dużą aplikację, warto przenieść każdy komponent, który używa LiteRT, a następnie możesz przenosić i testować po jednym komponencie.
Jedynym zastrzeżeniem jest to, że oszczędność miejsca uzyskasz dopiero po usunięciu ostatniej zależności od dołączonego środowiska wykonawczego.
Jeśli tak, pamiętaj, że nie należy mieszać obiektów między LiteRT w Usługach Google Play a dołączonym LiteRT.
Jeśli więc otrzymujesz tensory, skompilowane modele lub interpretery z LiteRT w usługach Google Play, nie przekazuj ich do dołączonego LiteRT ani odwrotnie.
Poza tym jednak łączenie tych elementów działa bez zarzutu.
OK.
To było tworzenie nowej aplikacji.
Teraz omówię, jak uaktualnić istniejącą aplikację.
Możesz mieć już aplikację, która korzysta z interfejsu Interpreter API.
To jest starszy interfejs API TFLite, który używa interpretera jako głównej klasy.
Po lewej stronie widzisz kod korzystający z interfejsu Interpreter API, a po prawej – nowy kod interfejsu CompiledModel API.
// Dependencies (Gradle):
// play-services-tflite-java and/or litert (bundled)
// Init
TfLite.initialize(context).await()
// Load
val interpreterOptions =
InterpreterApi.Options().apply {
runtime = TfLiteRuntime.FROM_SYSTEM_ONLY
}
val interpreter =
InterpreterApi.create(modelFile, interpreterOptions)
// Prepare inputs/outputs
val inputs = …
val outputs = …
// Execute
interpreter.run(inputs, outputs)// Dependencies (Gradle):
// play-services-litert
// Init
val environment =
LiteRt.initialize(context).await()
// Load
val modelOptions = CompiledModel.Options(Accelerator.CPU)
val model =
CompiledModel.create(modelPath, modelOptions, environment)
// Prepare inputs/outputs
val inputBuffers = model.createInputBuffers()
val outputBuffers = model.createOutputBuffers()
// Execute
model.run(inputBuffers, outputBuffersZmieniasz więc TfLite.initialize na LiteRt.initialize, co teraz zwraca środowisko.
Następnie przekazujesz środowisko do CompiledModel.create.
To niewielka zmiana, która nie zwiększa rozmiaru pakietu APK.
Na następnym slajdzie pokażemy, jak to zrobić za pomocą GPU, co jest kolejną opcją.
To jest dodatkowy kod, który jest potrzebny do włączenia GPU.
// Dependencies (Gradle):
// play-services-tflite-java and/or litert (bundled)
// Init
val initOptions = TfLiteInitializationOptions.builder()
.setEnableGpuDelegateSupport(true).build()
TfLite.initialize(context, initOptions).await()
val useGpu =
TfLiteGpu.isGpuDelegateAvailable(context).await()
// Load
val interpreterOptions =
InterpreterApi.Options().apply {
runtime = TfLiteRuntime.FROM_SYSTEM_ONLY
}
if (useGpu) {
interpreterOptions.addDelegateFactory(
GpuDelegateFactory());
}
val interpreter =
InterpreterApi.create(modelFile, interpreterOptions)
// Prepare inputs/outputs
val inputs = …
val outputs = …
// Execute
interpreter.run(inputs, outputs)// Dependencies (Gradle):
// play-services-litert
// Init
val initOptions = LiteRtInitializationOptions.builder()
.setEnableGpu(true).build()
val environment = LiteRt.initialize(context, initOptions).await()
// Load
val modelOptions =
CompiledModel.Options(Accelerator.CPU, Accelerator.GPU)
val model =
CompiledModel.create(modelPath, modelOptions, environment)
// Prepare inputs/outputs
val inputBuffers = model.createInputBuffers()
val outputBuffers = model.createOutputBuffers()
// Execute
model.run(inputBuffers, outputBuffers)Jak widać, kod w nowym interfejsie API do włączania GPU jest nieco prostszy niż wcześniej.
Pierwsze wywołanie setEnableGpu w opcjach inicjowania LiteRT, które przekazujesz do LiteRt.initialize, spowoduje wczytanie kodu akceleratora GPU do aplikacji.
Następnie, gdy tworzysz modelOptions i przekazujesz je do CompiledModel.create, określasz, który akcelerator będzie używany w przypadku konkretnego modelu, czy chcesz, aby inny model działał tylko na GPU, na GPU z rezerwowym CPU czy tylko na CPU.
OK.
Jak widać, włączenie GPU jest znacznie prostsze dzięki nowemu interfejsowi API.
Co dokładnie zyskujesz?
Chintan Ci o tym opowie.
OK.
Dziękuję, Fergus.
Porozmawiajmy o tym, co nam to wszystko daje.
Pamiętasz, że mieliśmy utworzyć aplikację? Zobaczmy, co udało nam się stworzyć.
To ja. Wykorzystaliśmy ML Kit, aby mnie znaleźć, więc segmentacja jest wykonywana przez gotowy interfejs API, taki jak ML Kit.
To jest moja głowa.
Następnie LiteRT używa innego modelu podobnego do przeniesienia stylu, aby pomalować tło.
Inne korzyści, o których wspominaliśmy, to oszczędność około 8 MB miejsca, jedno środowisko wykonawcze używane przez wszystkie aplikacje (lub przynajmniej te, które są tutaj udostępniane), automatyczne aktualizacje oraz szybszy procesor graficzny, który zapewnia blisko 30 klatek na sekundę w przypadku treści, które muszą być wyświetlane w czasie rzeczywistym, aby zapewnić użytkownikom bogate wrażenia.
Co więcej, nie musisz robić tego wszystkiego ręcznie.
Wprowadziliśmy też nową umiejętność w Androidzie, czyli opublikowaliśmy umiejętność Android LiteRT, która w kilka minut ulepsza systemy uczące się na urządzeniu.
Możesz więc zrobić kilka rzeczy: uaktualnić istniejącą aplikację, utworzyć nową aplikację, a także uaktualnić aplikację, aby korzystała z nowej integracji z Usługami Google Play.
Wszystkie te informacje są dostępne.
Link znajduje się na slajdzie, jest też na GitHubie i pojawi się w naszej dokumentacji oraz na naszym blogu.
To powinno być przydatne dla każdego, kto chce wkrótce wprowadzić zmiany.
Fergus powie nam, co będzie dalej.
Dlatego stawiamy na AI na urządzeniu z LiteRT.
Nadal inwestujemy znaczne środki w ulepszanie akceleracji GPU i zakresu modeli oraz regularnie aktualizujemy LiteRT 2.x, zarówno w przypadku pakietu LiteRT open source, jak i pakietu LiteRT Maven w Usługach Google Play, który jest LiteRT w Usługach Google Play.
Będziemy też nadal zapewniać zgodność wsteczną.
Środowisko wykonawcze usług Google Play będzie nadal obsługiwać aplikacje utworzone za pomocą starszych pakietów SDK.
Tak.
To bardzo ważne dla naszych użytkowników i dla nas.
Pakiety SDK LiteRT 1.x są obecnie w trybie konserwacji, więc otrzymują tylko krytyczne poprawki zabezpieczeń.
Interfejs NNAPI, który wycofaliśmy w 2024 r., zostanie usunięty prawdopodobnie w 2027 r.
Jeśli więc używasz NNAPI, przełącz się na akcelerację GPU lub NPU z dołączonym LiteRT.
OK.
Tak.
Im szybciej przejdziesz na wersję 2.x i CompiledModel, tym mniej pracy będziesz mieć później.
Podsumowując, warto zapamiętać 3 rzeczy.
Dlatego twórz.
Zacznij od ML Kit. Jeśli spełnia Twoje potrzeby, to świetnie.
Jeśli jednak nie, użyj LiteRT w przypadku modeli niestandardowych.
Przejdź na LiteRT w usługach Google Play, aby zmniejszyć rozmiar pliku APK i korzystać ze wspólnego środowiska wykonawczego.
Rozważ też użycie interfejsu API CompiledModel, aby przyspieszyć i uprościć wnioskowanie na GPU.
Tak.
Wszystko jest opisane w naszej witrynie z dokumentacją LiteRT na AI Edge pod podanym adresem URL.
No więc tak.
Dziękujemy, że jesteście z nami. Nie możemy się doczekać, aby zobaczyć, co stworzycie.
// 1. Configure and create segmenter client
val segmenter = Segmentation.getClient(
SelfieSegmenterOptions.Builder()
.setDetectorMode(
SelfieSegmenterOptions.STREAM_MODE)
.build())
// 2. Prepare image & run inference
fun processFrame(mediaImage: Image) {
val image = InputImage.fromMediaImage(
mediaImage, /* rotationDegrees= */ 0)
segmenter.process(image)
.addOnSuccessListener { mask -> … }
}import litert_torch
model = my_models.Stylizer().eval()
# Convert with torch.export under the hood
edge_model = litert_torch.convert(
model, sample_inputs)
edge_model.export("stylizer_f32.tflite")# Python
# previously ai_edge_quantizer
from litert_quantizer import quantizer, recipe
qt = quantizer.Quantizer("stylizer_f32.tflite")
# int8 weights, float activations
qt.load_quantization_recipe(
recipe.dynamic_wi8_afp32())
qt.quantize().export_model("stylizer_int8.tflite")// Kotlin
// Build once, off the main thread.
private val model: CompiledModel =
CompiledModel.create(
context.assets,
"stylizer_int8.tflite",
// Simple GPU setup!
CompiledModel.Options(Accelerator.GPU),
environment
)
// Reuse buffers across frames.
private val inputBuffers = model.createInputBuffers()
private val outputBuffers = model.createOutputBuffers()
fun stylize(input: FloatArray): FloatArray {
inputBuffers[0].writeFloat(input)
model.run(inputBuffers, outputBuffers) // sync
return outputBuffers[0].readFloat()
}// Easier with CompiledModel API: 3 steps
// 1. app/build.gradle: replace litert with play-services-litert
- implementation 'com.google.ai.edge.litert:litert:...'
+ implementation 'com.google.android.gms:play-services-litert:17.0.0' // also pulls in litert-api// 2. Initialize the LiteRT Environment from Play services (context = your Activity)
- val environment = Environment.create(...)
+ import com.google.android.gms.litert.LiteRt
+ val environment = LiteRt.initialize(context).await()
// 3. Pass environment whenever you call CompiledModel.create
// That's it! The rest of your app uses the normal CompiledModel APIs from litert-api.// Dependencies (Gradle):
// play-services-tflite-java and/or litert (bundled)
// Init
TfLite.initialize(context).await()
// Load
val interpreterOptions =
InterpreterApi.Options().apply {
runtime = TfLiteRuntime.FROM_SYSTEM_ONLY
}
val interpreter =
InterpreterApi.create(modelFile, interpreterOptions)
// Prepare inputs/outputs
val inputs = …
val outputs = …
// Execute
interpreter.run(inputs, outputs)// Dependencies (Gradle):
// play-services-litert
// Init
val environment =
LiteRt.initialize(context).await()
// Load
val modelOptions = CompiledModel.Options(Accelerator.CPU)
val model =
CompiledModel.create(modelPath, modelOptions, environment)
// Prepare inputs/outputs
val inputBuffers = model.createInputBuffers()
val outputBuffers = model.createOutputBuffers()
// Execute
model.run(inputBuffers, outputBuffers// Dependencies (Gradle):
// play-services-tflite-java and/or litert (bundled)
// Init
val initOptions = TfLiteInitializationOptions.builder()
.setEnableGpuDelegateSupport(true).build()
TfLite.initialize(context, initOptions).await()
val useGpu =
TfLiteGpu.isGpuDelegateAvailable(context).await()
// Load
val interpreterOptions =
InterpreterApi.Options().apply {
runtime = TfLiteRuntime.FROM_SYSTEM_ONLY
}
if (useGpu) {
interpreterOptions.addDelegateFactory(
GpuDelegateFactory());
}
val interpreter =
InterpreterApi.create(modelFile, interpreterOptions)
// Prepare inputs/outputs
val inputs = …
val outputs = …
// Execute
interpreter.run(inputs, outputs)// Dependencies (Gradle):
// play-services-litert
// Init
val initOptions = LiteRtInitializationOptions.builder()
.setEnableGpu(true).build()
val environment = LiteRt.initialize(context, initOptions).await()
// Load
val modelOptions =
CompiledModel.Options(Accelerator.CPU, Accelerator.GPU)
val model =
CompiledModel.create(modelPath, modelOptions, environment)
// Prepare inputs/outputs
val inputBuffers = model.createInputBuffers()
val outputBuffers = model.createOutputBuffers()
// Execute
model.run(inputBuffers, outputBuffers)