플러그 앤 플레이 AI의 편리함과 커스텀 모델의 유연성 사이에서 고민하지 마세요. 바이너리 비대화 없이 하나의 초경량 앱에 두 가지를 모두 배포할 수 있습니다.
이 세션에서는 단일 Android 앱에서 이러한 이중 스택 아키텍처를 빌드하는 방법을 보여드립니다. ML Kit를 활용하여 즉시 사용 가능한 기존 ML 작업 (예: 문서 스캔)을 처리하는 동시에, Play 서비스의 LiteRT 독립형을 사용하여 커스텀 컴퓨터 비전 또는 오디오 워크로드를 처리하는 방법을 알아봅니다. 두 구현 경로가 내부적으로 어떻게 통합되어 최신 LiteRT 런타임을 활용하는지 자세히 살펴보겠습니다. 이를 통해 앱은 CPU와 GPU에서 다운로드 용량이 거의 0바이트에 가까운 원활한 하드웨어 가속 성능을 제공할 수 있습니다.
개발자를 위한 핵심 사항:
-타협 없는 성능: 턴키 모델과 커스텀 모델 모두 통합 CompiledModel API를 사용하여 자동으로 하드웨어 가속됩니다.
-마이크로 APK: ML Kit와 LiteRT 런타임을 모두 Play 서비스로 오프로드하여 앱의 다운로드 크기를 대폭 줄입니다.
-하이브리드 통합: 리소스 충돌 없이 프로덕션에서 여러 ML 워크플로를 나란히 실행하는 방법을 마스터합니다.
play-services-litert로 업데이트하고, LiteRt.initialize를 호출하여 환경을 가져오고, 이를 CompiledModel.create에 전달해야 합니다.스크립트
여러분, 안녕하세요.
곧 대화가 시작됩니다.
따라서 오늘날 사람들이 '온디바이스 AI'라고 말할 때는 LLM을 의미하는 경우가 많습니다.
오늘 앞서 ML Kit, Firebase, 기타 여러 Google 제품과 함께 Gemini Nano에 관한 여러 세션이 진행되었습니다.
이 세션에서는 나머지 절반인 기존 ML과 직접 가져오는 모델에 대해 다룹니다.
오늘도 자신도 모르게 몇 번 사용했을 것입니다.
배경을 흐리게 처리하거나 바코드 스캐너를 사용하거나 이미지 편집을 사용하는 앱을 사용한다고 생각해 보세요.
이러한 기능은 대부분 기존 ML을 기반으로 하며, 일반적으로 기기 내에서 실행됩니다.
이러한 기능을 앱이나 APK에 추가해 본 적이 있다면, 턴키 API를 사용할지 아니면 자체 모델을 가져올지 고민해 보셨을 것입니다.
앱 크기에 어떤 영향을 미칠까요?
오늘, 턴키 모델과 자체 모델 중 하나를 선택할 필요가 없다는 것을 알게 되실 겁니다.
하나의 간결한 런타임으로 두 가지를 모두 수행할 수 있습니다.
제 이름은 친탄 파리크입니다.
저는 LiteRT의 제품 관리자이고, Android ML 서비스의 엔지니어링 리드인 퍼거스도 함께합니다.
안녕하세요.
마지막에는 초당 약 30프레임으로 모든 카메라 프레임에서 두 모델을 실행하는 하나의 앱을 빌드하는 방법을 알아봅니다.
이 강연은 네 부분으로 구성되어 있습니다.
1부에서는 기존 ML에 초점을 맞춘 Google의 온디바이스 AI 솔루션인 ML Kit와 LiteRT에 대해 이야기하겠습니다.
두 번째로 LiteRT와 Play 서비스의 새로운 기능도 살펴보겠습니다.
또한 LiteRT의 새로운 CompiledModel API와 지원되는 기기도 다룹니다.
세 번째로, 새 앱을 빌드하는 방법을 보여드리겠습니다.
퍼거스가 ML Kit와 커스텀 모델을 모두 하나의 APK에 포함하여 앱을 빌드하는 방법을 설명합니다.
마지막으로 에이전트 모드를 사용하여 기존 앱을 업그레이드하는 방법을 보여드리겠습니다.
또한 이 에이전트 지원을 통해 새 앱을 스캐폴딩할 수도 있습니다.
좋습니다.
먼저 LiteRT란 무엇일까요?
LiteRT는 자체 모델을 위한 Google의 온디바이스 추론 런타임입니다.
이전에 TensorFlow Lite를 사용한 적이 있다면 동일한 .tflite 파일 형식을 사용합니다.
성능을 위해 재설계되었으며 멀티 프레임워크도 지원합니다.
즉, PyTorch, TensorFlow, JAX의 모델을 가져와 LiteRT용 플랫 버퍼 형식으로 변환할 수 있습니다.
2022년부터 Google Play 서비스의 TensorFlow Lite는 Android의 공식 맞춤 모델용 온디바이스 런타임이 되었습니다.
오늘 대대적인 업그레이드가 이루어지며, 이번 발표에서 이 내용을 중점적으로 다룰 예정입니다.
업그레이드를 통해 1.4배 더 빠른 새로운 개선된 GPU 추론을 포함한 최신 LiteRT CompiledModel API가 제공되며, 훨씬 더 작은 APK 크기로 더 작은 앱을 빌드할 수 있습니다.
그렇다면 Play 서비스를 통해 제공하는 이유는 무엇일까요?
몇 가지 장점이 있습니다. 앱 크기와 APK 비대화가 실질적인 문제가 되고 있는 많은 대화에서 제가 보고 있는 큰 고충입니다.
따라서 런타임이 작아집니다.
런타임이 APK에 없으므로 씬 클라이언트를 사용하며, 이로 인해 APK가 약 8MB 작아집니다.
두 번째 이점은 효율성입니다.
런타임의 사본이 하나 있으므로 LiteRT 런타임인 런타임이 모든 앱에서 공유됩니다.
따라서 앱이 여러 개 있다면 각각 8MB씩 절약할 수 있습니다.
디스크 공간을 절약하고 더 가벼운 앱을 만들려고 할 때 이 점은 매우 중요합니다.
두 번째는 유지보수입니다.
Google에서 버그 수정을 제공하고, GPU 드라이버 문제를 해결하므로 사용자가 직접 할 필요가 없으며, 다른 보안 업데이트도 모두 자동 업데이트를 통해 제공됩니다.
앞서 언급했듯이 GPU가 더 빠르므로 1.4배 더 빠른 GPU를 사용할 수 있습니다. 이에 대해서도 자세히 살펴보겠습니다.
또한 적용 범위 측면에서 이전 Android 기기로 전송할 수 있습니다.
Play 서비스의 LiteRT는 2016년의 Android 7까지 지원합니다.
퍼거스가 보여주겠지만, 다음 슬라이드에서는 지원을 확대할 다른 새로운 기기도 소개합니다.
이것이 전송 수단입니다. 다음 단계인 런타임에 대해 이야기해 보겠습니다.
따라서 LiteRT는 새로운 것도 아니고 실험적인 것도 아닙니다.
TensorFlow Lite와 LiteRT는 이미 250,000개가 넘는 앱에서 실행되고 있습니다.
현재 38억 대가 넘는 기기에서 실행되고 있습니다.
따라서 여러분이 사용하고 있는 많은 앱이 이 기술을 기반으로 실행되고 있다는 사실을 모르고 계실 수도 있습니다.
이는 매일 1조 건 이상의 추론을 수행하는 것과 같습니다.
이러한 규모에서 Google은 모든 이상한 칩셋 문제를 해결하고 ROM 문제 또는 GPU 드라이버 문제를 해결할 수 있었으며, 이를 위한 해결 방법이 있습니다.
LiteRT는 Google이 앱, 플랫폼, 여러 기기에서 자사의 주요 앱을 실행하는 데 사용하는 기술이기도 합니다.
YouTube Shorts 효과, Meet 배경 세분화, 사진 선명하게 하기 등은 실시간 동영상 및 대용량 이미지 모델이 모두 LiteRT에서 실행되는 예입니다.
사용 사례를 사용자에게 빠르고 흥미롭게 만드는 것이 매우 중요해지기 때문에 이 점도 매우 중요합니다.
이것은 Google이 이러한 핵심 기능을 위해 강화한 것과 동일한 런타임이며, Play 서비스를 통해 제공됩니다.
온디바이스를 사용해야 하는 이유도 살펴보겠습니다.
지연 시간, 개인 정보 보호, 오프라인 작업, 저렴한 비용 중 하나라도 중요하다면 오프라인으로 실행하세요.
이 외에도 여러 이유가 있을 수 있지만, 온디바이스 실행을 선택하는 가장 명확한 이유를 몇 가지 소개해 드렸습니다.
기기 내 실행이 항상 무료인 것은 아닙니다.
여기에는 몇 가지 미묘한 차이와 어려움이 있습니다.
따라서 이러한 과제 중 일부를 살펴보고 앞으로 나아갈 방향도 제시해 드리겠습니다.
성능: 이전 앱의 몇 가지 예에서 보았듯이 지연 시간과 메모리 예산은 항상 빠듯합니다.
실시간 동영상 및 오디오에는 극도의 효율성이 필요합니다.
간단한 상호작용 기능도 빠르게 작동해야 합니다.
그렇지 않으면 사용자 참여를 잃게 됩니다.
하드웨어 다양성: CPU 구성과 GPU 구성이 서로 다른 수백 개의 SoC가 있습니다.
이 모든 것에 대한 코드를 작성할 수는 없겠죠?
이러한 문제를 어떻게 해결할 수 있을까요?
APK 크기: 네이티브 런타임을 번들로 묶으면 다운로드 크기가 커져 전환율에 영향을 미칠 수 있습니다.
맞춤설정: 모델 학습, 품질, 모델 크기는 배포 전에도 매우 중요합니다.
따라서 훌륭한 온디바이스 앱을 빌드하는 것은 어려울 수 있습니다.
하지만 이 모든 상황에서 플랫폼이 사용자를 위해 작업을 수행하기를 원하지, 그 반대를 원하지는 않습니다.
Google의 온디바이스 포트폴리오는 이러한 문제를 해결하기 위해 존재하며, 다음으로 이 포트폴리오를 살펴보겠습니다.
오늘은 두 가지 간단한 솔루션에 집중할 예정입니다.
Play 서비스를 통해 기기 내 AI를 추가하는 두 가지 쉬운 방법이 있습니다.
경로 1은 ML Kit를 사용하는 턴키 경로입니다.
바로 사용할 수 있는 비전, 언어 API이며, 필요한 ML 전문 지식이 제한적이고, 많은 모델이 모두 제공되며, 모두 Play 서비스를 통해 제공됩니다.
다음 슬라이드에서 몇 가지 예시를 살펴보겠습니다.
커스텀 경로는 LiteRT를 통해 이루어집니다.
LiteRT를 사용하면 자체 모델을 가져와 CPU, GPU에서 실행할 수 있습니다.
런타임도 Play 서비스에서 제공됩니다.
따라서 APK에 번들로 포함하지 않습니다.
이러한 요소는 양자택일의 문제가 아닙니다.
함께 사용하면 더 좋습니다.
바로 이 기능을 오늘 몇 분 안에 빌드해 보겠습니다.
먼저 ML Kit에서 다루는 내용을 살펴보겠습니다.
ML Kit에서 기본적으로 제공하는 기능은 다음과 같습니다.
따라서 이러한 기능 중 일부가 필요에 부합한다고 생각한다면 좋은 출발점이며 이미 앞서 나가고 있는 것입니다.
비전, 바코드, 문서, 텍스트, 포즈, 이러한 많은 기능, 번역, 스마트 답장, 항목 추출과 같은 언어 API를 지원합니다.
핵심은 이러한 비전, 언어 API 중 상당수가 내부적으로 LiteRT를 사용하여 실행된다는 점입니다.
따라서 ML Kit가 필요한 기능을 제공한다면 여기에서 시작할 수 있습니다.
그렇지 않은 경우 자체 모델을 가져올 수 있습니다.
여기서 핵심은 ML Kit와 커스텀 모델이 두 개의 런타임이 아니라는 점입니다. 앞서 언급했듯이 말이죠.
이 두 가지는 내부에서 실행되는 동일한 LiteRT로 연결되는 두 개의 정문이라고 생각하면 됩니다.
따라서 LiteRT는 이 두 가지 기능을 모두 조정하는 런타임이 될 것입니다.
따라서 앱이 이미 Play 스토어를 사용하고 있다면 ML Kit를 사용하세요.
그렇지 않으면 LiteRT 경로도 살펴보겠습니다.
LiteRT의 새로운 기능도 살펴보겠습니다.
앞서 말씀드렸듯이 LiteRT는 TensorFlow Lite의 발전된 형태입니다.
가장 큰 개선사항은 더 빠른 GPU입니다.
더 빠른 GPU는 OpenCL, OpenGL을 지원하며 Metal 백엔드에 대한 크로스 플랫폼 지원도 제공합니다.
따라서 필요에 따라 여러 플랫폼에서 사용할 수 있습니다.
또한 더 간단합니다.
CPU, GPU, NPU 가속을 위한 통합 워크플로가 있습니다.
CPU와 GPU는 현재 Play 서비스에 있지만 NPU는 현재 LiteRT를 통해 번들로 제공되며, 이 작업은 진행 중입니다.
이전에는 가속기마다 위임 설정이 달랐죠?
이제 한 번만 하면 됩니다.
따라서 CPU로 자동 대체되는 API가 하나 있으며, 전용 위임 설정을 할 필요가 없습니다.
가속기 호출을 사용하면 훨씬 더 간단하고 적은 코드로 이를 관리할 수 있습니다.
또한 앞서 언급했듯이 동일한 모델이 여러 플랫폼에서 실행되므로 강력합니다.
유연성이라는 측면이 매우 중요합니다.
따라서 .tflite 형식은 동일하게 유지됩니다.
기존 앱이 있는 경우 이 형식을 계속 사용할 수 있습니다.
새 앱을 빌드하는 경우 이 파일 형식을 다시 사용할 수 있습니다.
또한 TensorFlow Lite에 있던 Interpreter API를 지원한다는 점도 흥미롭습니다.
따라서 단계적으로 이전하려는 경우 Interpreter API가 포함되어 있으며 새로운 LiteRT의 일부이기도 하므로 쉽게 이전할 수 있습니다.
이것이 런타임입니다.
이를 통해 무엇을 빌드할 수 있는지 알아보겠습니다.
현재 Android 앱은 다음과 같은 기능을 빌드하고 있습니다.
카메라 효과, 사진 편집, 스마트 입력, 게임, 아바타 등 모든 것이 포함됩니다.
이러한 앱 중 상당수는 실시간 기능이 필요합니다.
GPU가 카메라에서 직접 프레임을 전송하므로 빠르고 실시간으로 처리하는 것이 중요합니다.
이러한 사진 편집 모델 중 일부는 점점 더 무거워지고 있습니다.
안경을 사용한 일부 데모에서 본 AR/VR 기능도 마찬가지로, 대부분 내부에서 LiteRT를 실행합니다.
이제 Google의 주요 기능과 Play 서비스에서 사용되는 것과 동일한 런타임이므로 APK에 아무것도 번들로 묶지 않고도 이 모든 것을 이용할 수 있습니다.
이제 앱을 빌드해 보겠습니다. 퍼거스가 방법을 알려줄 것입니다.
설치해 봅시다.
감사합니다. Chintan
Google Play 서비스의 LiteRT에 새로 추가된 기능을 간단히 살펴보겠습니다.
빌드하기 전에 한 가지 소식을 더 전해드리겠습니다. 방금 보신 모든 기능은 휴대전화뿐만 아니라 Wear OS와 Android Automotive OS에서도 실행됩니다. Play 서비스의 LiteRT는 Wear OS와 Android Automotive OS에서도 사용할 수 있습니다.
따라서 시계나 기타 웨어러블 기기 또는 자동차 자체에서 기기 내 모델을 실행할 수 있습니다.
이전에는 휴대전화에서 Wear의 호환 앱으로 앱을 사용할 수 있었지만 이제는 웨어러블 기기 자체에서 실제로 실행할 수 있으며 Android Automotive에서도 마찬가지입니다.
따라서 동일한 API, 동일한 .tflite 모델을 사용하지만 더 많은 노출 영역을 사용할 수 있습니다.
폼 팩터별로 별도로 구현할 필요 없이 이러한 다양한 기기에 모두 동일한 구현을 사용할 수 있습니다.
Play 서비스 배포 패러다임의 장점은 이전 기기에서 실행되도록 백포트할 수 있다는 것입니다.
Android Automotive OS의 경우 2020년에 출시된 Android 11까지 지원하고, Wear OS의 경우 Wear OS 4 이상을 지원합니다.
좋습니다.
이제 새 앱을 빌드하는 경로와 기존 앱을 업그레이드하는 경로, 두 가지 경로에 대해 이야기해 보겠습니다.
이것이 나머지 발표에서 다룰 내용입니다.
먼저 ML Kit와 LiteRT에서 실행되는 커스텀 GPU 모델을 함께 사용하는 예시 앱을 살펴보겠습니다.
기존 앱을 업그레이드하는 경우 세 가지 작은 변경사항이 있습니다. 종속 항목을 업데이트하는 Gradle 변경사항, Play 서비스에서 LiteRT를 사용 설정하는 초기화 변경사항, Interpreter API에서 CompiledModel API로 전환하는 변경사항입니다.
하지만 먼저 새 앱을 살펴보겠습니다. 업그레이드할 대상을 확인한 후에 업그레이드하는 것이 훨씬 더 합리적이기 때문입니다.
새 앱을 빌드하는 경우
빌드할 앱은 다음과 같습니다.
실시간 카메라 뷰가 표시되며, 이 뷰에서 내 모습은 선명하게 유지되고 배경은 예술적인 스타일로 바뀝니다.
카메라 프레임을 가져와서
카메라 프레임의 이미지를 ML Kit 셀카 세그먼테이션을 통해 스트리밍합니다.
이는 기존 ML Kit 턴키 API 중 하나입니다.
그러면 이미지의 어떤 픽셀이 이미지의 사람에 해당하는지 기본적으로 알려주는 전경 마스크가 생성됩니다.
그런 다음 스타일 트랜스퍼 유형 모델과 같은 커스텀 모델을 사용하여 이미지에 스타일을 적용합니다.
이 스타일을 전체 카메라 프레임에 적용할 예정이지만, 실제로 중요한 것은 배경 부분입니다. 결국 원본 카메라 프레임, 마스크, 스타일 배경을 가져와 간단한 로직으로 결합하여 피사체는 유지하고 배경에 스타일이 적용된 합성 프레임을 만들 것이기 때문입니다.
따라서 기존의 턴키 API를 사용하고, 앱을 차별화하는 맞춤 API를 사용하고자 합니다.
이것이 ML Kit 셀피 세분화 API를 호출하는 첫 번째 부분입니다.
// 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 -> … }
}일반적인 API와 같다고 보면 되나요?
이는 Android 개발자에게 가장 기본적인 부분입니다.
API 문서를 살펴보거나 Gemini에게 빌드를 요청하면 됩니다.
하지만 꽤 간단합니다.
클라이언트를 구성할 때 몇 가지 옵션을 전달합니다.
이 경우 동영상 프레임 스트림을 처리할 수 있도록 스트리밍 모드를 지정합니다.
그런 다음 이 프로세스 메서드를 호출하면 셀피 세분화로 계산된 마스크가 반환됩니다.
입력은 카메라의 이미지입니다.
이러한 모든 API는 원시 텐서가 아닌 애플리케이션 수준 유형을 사용하므로 매우 높은 수준에서 프로그래밍할 수 있으며 매우 간단합니다.
두 번째 부분인 커스텀 모델에서는 PyTorch 모델을 사용합니다.
친탄이 Kaggle이나 Hugging Face 같은 곳에서 가져온 것 같은데…
실제로
예, 아니면 직접 변환할 수도 있습니다.
자체 모델을 빌드할 수 있습니다.
죄송합니다. 돌아갑니다.
네, 이것이 바로 스택의 모습입니다.
PyTorch 모델을 가져와 변환하고 양자화하면 LiteRT 모델을 얻을 수 있습니다.
그런 다음 원하는 방식으로 앱과 함께 배포합니다.
앱의 일부로 애셋으로 번들로 묶거나 별도로 다운로드할 수 있습니다.
어느 쪽이든 가능합니다.
그리고 이는 Play 서비스의 LiteRT 런타임 위에 위치합니다.
CPU에서 최적화하기 위한 CPU 커널이 있으며, ML Drift는 GPU 가속기의 이름입니다.
네, 말씀드린 것처럼 TFLite 모델을 가져와서 직접 학습시키거나 기존 모델을 찾아서 사용할 수 있습니다. 어느 쪽이든 작동합니다.
PyTorch에서 변환하는 것은 몇 줄의 Python 코드만으로 가능합니다.
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")따라서 LiteRT-Torch를 pip 설치하고 litert_torch.convert를 호출하여 무작위 입력이 될 수 있는 sample_inputs를 전달하고 TFLite 파일을 내보냅니다.
참고로 LiteRT-Torch는 ai-edge-torch의 새 이름입니다.
양자화도 매우 간단합니다.
# 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")LiteRT 양자화기에서 양자화기와 레시피를 가져옵니다.
양자화기를 구성할 때 원래 부동 소수점 모델을 전달하고, GPU에 권장하는 표준 레시피인 레시피를 전달합니다. 이 레시피는 8비트 정수 가중치를 사용하지만 활성화는 32비트 부동 소수점으로 유지합니다.
그런 다음 quantize를 호출하고 export_model를 호출하여 출력 모델을 저장합니다.
그러면 양자화된 모델이 생성되어 실행할 수 있으며, 가중치가 훨씬 작아지고 더 효율적으로 실행됩니다.
네, CompiledModel API GPU가 진가를 발휘하는 부분입니다.
친탄이 언급했듯이 기존 TFLite GPU에 비해 속도가 크게 향상되었습니다.
정확한 수치는 모델마다 조금씩 다르지만 1.4배는 합리적으로 기대할 수 있는 수치입니다.
CPU 추론보다 최대 10배 빠르므로 큰 이점이 있습니다.
현재 모델을 사용하는 대부분의 사용자는 CPU에서 모델을 실행하고 있으며, GPU를 통해 얻을 수 있는 성능의 10배에 달하는 성능을 놓치고 있습니다.
이것이 실질적인 인센티브입니다.
빠른 속도의 비결은 무엇인가요?
Google에서는 다양한 기능을 지원합니다. 예를 들어 비동기 실행을 지원하므로 AHardwareBuffer를 가져와 직접 전달하거나 카메라 렌더링 파이프라인에서 OpenGL 버퍼를 가져와 텐서 버퍼에 직접 전달할 수 있습니다.
제로 카피는 Google에서 지원하는 제로 카피를 최적화합니다. 따라서 기본적으로 몇십 밀리초 내에 모든 프레임을 처리해야 하는 경우와 같이 지연 시간이 짧은 예산으로 작업을 처리하려고 할 때 메모리 버퍼를 단순히 복사하는 것만으로도 상당한 오버헤드가 발생할 수 있습니다.
따라서 실시간 요구사항이 매우 높은 애플리케이션의 경우 제로 카피 최적화를 사용할 수 있으며, Google은 이를 지원합니다.
그리고 친탄이 언급했듯이 GPU 백엔드로 OpenGL, OpenCL, Metal을 지원하는 크로스 플랫폼입니다.
마지막으로 ML Drift Optimizer는 오픈소스입니다.
Apache 라이선스에 따라 사용할 수 있습니다.
최근 Google에서 오픈소스로 공개했습니다.
좋습니다. 그런 다음 앱 코드가 있습니다.
// 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()
}보시다시피 매우 작고 간단합니다.
따라서 모델을 한 번 만들고 모든 프레임에서 재사용합니다.
따라서 .tflite 파일에 CompiledModel.create가 전달됩니다.
GPU에서 실행하도록 지정한 다음 입력과 outputBuffers를 구성하면 됩니다.
그런 다음 실제로 모든 프레임을 처리하는 기본 루프에서 입력, 출력을 전달하는 이 model.run를 호출합니다.
inputBuffers에 쓴 후 model.run를 호출한 다음 outputBuffers에서 읽습니다.
좋습니다.
아, 네. 그런 다음 GPU를 지정하면 GPU에서 실행됩니다.
CPU와 GPU도 지정하면 GPU 실행을 시도합니다.
어떤 이유로든 GPU를 사용할 수 없는 경우 CPU로 대체됩니다.
따라서 경우에 따라 CPU 대체가 앱에 충분히 효율적이지 않을 수 있으며, 이 경우 GPU를 지정하여 사용하면 됩니다.
일반적으로 CPU 대체가 필요합니다.
좋습니다.
따라서 아직 Play 서비스를 사용하지 않는 번들 LiteRT로 빌드했습니다.
그럼 Play 서비스에서 LiteRT를 사용하는 방법을 보여드리겠습니다.
세 가지 변경사항이 있습니다. 첫 번째는 종속 항목 변경사항입니다.
// 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-apiGradle 파일이나 다른 곳에서, 사용 중인 빌드 시스템에서, Maven 패키지 종속 항목을 지정하는 다른 곳에서 변경하면 됩니다.
litert 종속 항목 또는 이전 TensorFlow Lite Maven 패키지 종속 항목을 삭제하고 이를 play-services-litert로 바꿉니다.
이렇게 하면 litert-api 패키지도 가져옵니다.
이제 LiteRT에만 종속되고 런타임이 앱에서 오는지 Play 서비스에서 오는지 상관하지 않는 중간 레이어를 작성하는 경우 LiteRT API에만 종속되고 환경을 입력 매개변수로 사용할 수 있습니다.
두 번째 단계는 환경 매개변수입니다.
여기에서 종속 항목 삽입을 제공하여 Play 서비스 LiteRT를 사용하고 싶다고 지정합니다.
따라서 gms.litert.LiteRt를 가져오고 초기화 함수를 호출하여 Android 활동인 컨텍스트를 전달합니다.
// 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.이는 비동기식이므로 .await를 호출하거나 나머지를 콜백 기반으로 만들어야 합니다.
마지막으로 환경을 가져온 후에는 CompiledModel.create를 호출할 때마다 해당 환경을 전달하면 됩니다.
이렇게 하면 Play 서비스에서 Play 서비스 LiteRT 런타임을 사용하게 됩니다.
이상입니다.
앱의 나머지 부분은 LiteRT API의 동일한 LiteRT CompiledModel API를 사용합니다.
나머지 추론 코드는 Play 서비스를 사용하기 위해 변경되지 않습니다.
그리고 이전을 점진적으로 수행할 수 있습니다.
한 번에 모두 이전할 필요는 없으며 한 번에 하나의 구성요소를 이전할 수 있습니다.
대규모 앱이 있는 경우 LiteRT를 사용하는 각 구성요소를 이전한 다음 한 번에 하나씩 이전하고 한 번에 하나씩 테스트하는 것이 좋습니다.
유일한 주의점은 번들 런타임에 대한 마지막 종속 항목을 삭제할 때만 크기 이점, 즉 공간 절약 효과를 얻을 수 있다는 것입니다.
그리고 사용 중인 경우, Play 서비스의 LiteRT와 번들 LiteRT 간에 객체를 혼합해서는 안 된다는 점도 주의해야 합니다.
따라서 Play 서비스의 LiteRT에서 텐서, 컴파일된 모델 또는 인터프리터를 가져오는 경우 이를 번들 LiteRT에 전달해서는 안 되며 그 반대의 경우도 마찬가지입니다.
그 외에는 이러한 항목을 혼합해도 정상적으로 작동합니다.
좋습니다.
지금까지 새 앱을 빌드하는 방법을 알아봤습니다.
이제 기존 앱을 업그레이드하는 방법을 설명하겠습니다.
따라서 Interpreter API를 사용하는 기존 앱이 있을 수 있습니다.
이것은 인터프리터를 기본 클래스로 사용하는 이전 TFLite API입니다.
왼쪽은 Interpreter API를 사용하는 코드이고 오른쪽은 새로운 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, outputBuffers따라서 TfLite.initialize를 LiteRt.initialize로 변경하면 이제 환경이 반환됩니다.
그런 다음 환경을 CompiledModel.create에 전달합니다.
따라서 APK 크기가 증가하지 않는 작은 변화입니다.
다음 슬라이드에서는 GPU를 사용하여 이 작업을 수행하는 방법을 보여드리겠습니다. 이는 또 다른 옵션일 뿐입니다.
이것이 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)보시다시피 GPU를 사용 설정하는 새 API의 코드는 이전 코드보다 약간 더 간단합니다.
따라서 LiteRT 초기화 옵션에서 setEnableGpu를 처음 호출한 후 LiteRt.initialize에 전달하면 GPU 가속기 코드가 앱에 로드됩니다.
그런 다음 modelOptions를 구성하고 CompiledModel.create에 전달할 때 특정 모델에 사용할 가속기를 지정합니다. 다른 모델을 GPU에서만 실행할지, CPU 대체가 있는 GPU에서 실행할지, CPU에서만 실행할지 지정할 수 있습니다.
좋습니다.
예, 보시다시피 새 API를 사용하면 GPU를 훨씬 더 간단하게 사용 설정할 수 있습니다.
그렇다면 실제로 어떤 이점이 있을까요?
친탄이 알려줄 거야.
좋습니다.
좋습니다. 퍼거스, 감사합니다.
그렇다면 이 모든 것이 우리에게 어떤 이점을 가져다주는지 이야기해 보겠습니다.
앱을 빌드할 것이라고 말씀드렸으니 실제로 무엇을 빌드했는지 살펴보겠습니다.
어쨌든 저를 찾기 위해 ML Kit를 사용했습니다. ML Kit와 같은 턴키 API를 통해 세분화가 지금 진행 중입니다.
저기 있는 제 머리를 찾는 거죠.
그런 다음 LiteRT는 스타일 트랜스퍼와 유사한 다른 모델을 사용하여 배경을 그립니다.
앞서 언급한 다른 이점으로는 약 8MB의 공간 절약, 모든 앱 간에 사용되는 하나의 런타임(또는 적어도 여기에서 공유되는 런타임), 자동 업데이트, 풍부한 사용자 환경을 위해 실시간으로 필요한 항목에서 초당 약 30프레임을 제공하는 더 빠른 GPU가 있습니다.
또한 이 모든 작업을 수동으로 할 필요가 없습니다.
Android에서 방금 출시한 새로운 기술도 있습니다. 기본적으로 몇 분 만에 기기 내 ML을 업그레이드하는 Android LiteRT 기술을 게시했습니다.
이 기능을 사용하면 기존 앱을 업그레이드하거나, 새 앱을 스캐폴딩하거나, 이 새로운 Play 서비스 통합을 사용하도록 앱을 업그레이드할 수 있습니다.
이 모든 것이 가능합니다.
링크는 슬라이드에 있으며 GitHub에도 있고 문서와 블로그에도 표시됩니다.
곧 변경하려는 사용자에게도 유용할 것입니다.
퍼거스가 이어서 설명해 주겠습니다.
따라서 Google은 LiteRT를 사용한 온디바이스 AI에 전념하고 있습니다.
Google은 GPU 가속 및 모델 적용 범위를 개선하는 데 계속해서 많은 투자를 하고 있으며, 오픈소스 번들 LiteRT와 Google Play 서비스의 LiteRT인 Google Play 서비스 LiteRT Maven 패키지 모두에 대해 LiteRT 2.x의 정기 업데이트를 계속 제공하고 있습니다.
또한 이전 버전과의 호환성도 계속 제공할 예정입니다.
Play 서비스 런타임은 이전 SDK로 빌드된 앱을 계속 지원합니다.
네.
이는 사용자에게도, YouTube에게도 매우 중요한 일입니다.
LiteRT 1.x SDK는 현재 유지보수 모드이므로 중요한 보안 수정사항만 제공됩니다.
2024년에 지원 중단된 NNAPI는 2027년부터 삭제될 예정입니다.
따라서 NNAPI를 사용하는 경우 번들로 제공되는 LiteRT와 함께 GPU 가속 또는 NPU 가속을 사용하도록 전환하세요.
좋습니다.
네.
따라서 2.x 및 CompiledModel로 빨리 이전할수록 나중에 해야 할 일이 줄어듭니다.
세 가지를 기억해 두세요.
그러니 빌드하세요.
ML Kit로 시작하고, 필요한 작업을 이미 수행하고 있다면 좋습니다.
그렇지 않은 경우 맞춤 모델에 LiteRT를 사용하세요.
APK 절감 및 공유 런타임을 위해 Google Play 서비스의 LiteRT로 업그레이드하세요.
더 빠르고 간단한 GPU 추론을 위해 CompiledModel API를 사용하는 것도 고려해 보세요.
네.
모든 내용은 AI Edge의 LiteRT 문서 사이트(URL: ai.google.dev/edge/litert)에 문서화되어 있습니다.
그렇습니다.
참여해 주셔서 감사합니다. 여러분이 어떤 것을 빌드할지 기대됩니다.
// 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)