Przewodnik po wnioskowaniu LLM na Androida

Interfejs LLM Inference API umożliwia uruchamianie dużych modeli językowych (LLM) w całości na urządzeniu w przypadku aplikacji na Androida. Możesz go używać do wykonywania wielu różnych zadań, takich jak generowanie tekstu, wyszukiwanie informacji w formie języka naturalnego i podsumowywanie dokumentów. Zadanie ma wbudowaną obsługę wielu dużych modeli językowych typu tekst na tekst, dzięki czemu możesz stosować w aplikacjach na Androida najnowsze modele generatywnej AI na urządzeniu.

Aby szybko dodać interfejs LLM Inference API do aplikacji na Androida, przeczytaj krótkie wprowadzenie. Podstawowy przykład aplikacji na Androida korzystającej z interfejsu LLM Inference API znajdziesz w przykładowej aplikacji. Szczegółowe informacje o działaniu interfejsu LLM Inference API znajdziesz w sekcjach opcje konfiguracji, konwersja modeludostrajanie LoRA.

Możesz zobaczyć to zadanie w działaniu w demonstracji MediaPipe Studio. Więcej informacji o możliwościach, modelach i opcjach konfiguracji tego zadania znajdziesz w tym artykule.

Krótkie wprowadzenie

Aby dodać interfejs LLM Inference API do aplikacji na Androida, wykonaj te czynności. Interfejs LLM Inference API jest zoptymalizowany pod kątem urządzeń z Androidem z wyższej półki, takich jak Pixel 8 i Samsung S23 lub nowsze, i nie obsługuje emulatorów urządzeń.

Dodawanie zależności

Interfejs LLM Inference API korzysta z biblioteki com.google.mediapipe:tasks-genai. Dodaj tę zależność do pliku build.gradle w aplikacji na Androida:

dependencies {
    implementation 'com.google.mediapipe:tasks-genai:0.10.27'
}

Pobieranie modelu

Pobierz model Gemma-3 1B w 4-bitowym formacie skwantowanym z Hugging Face. Więcej informacji o dostępnych modelach znajdziesz w dokumentacji dotyczącej modeli.

Przekaż zawartość folderu output_path na urządzenie z Androidem.

$ adb shell rm -r /data/local/tmp/llm/ # Remove any previously loaded models
$ adb shell mkdir -p /data/local/tmp/llm/
$ adb push output_path /data/local/tmp/llm/model_version.task

Inicjowanie zadania

Zainicjuj zadanie za pomocą podstawowych opcji konfiguracji:

// Set the configuration options for the LLM Inference task
val taskOptions = LlmInferenceOptions.builder()
        .setModelPath('/data/local/tmp/llm/model_version.task')
        .setMaxTopK(64)
        .build()

// Create an instance of the LLM Inference task
llmInference = LlmInference.createFromOptions(context, taskOptions)

Uruchamianie zadania

Użyj metody generateResponse(), aby wygenerować odpowiedź tekstową. W ten sposób powstaje jedna wygenerowana odpowiedź.

val result = llmInference.generateResponse(inputPrompt)
logger.atInfo().log("result: $result")

Aby przesyłać strumieniowo odpowiedź, użyj metody generateResponseAsync().

val options = LlmInference.LlmInferenceOptions.builder()
  ...
  .setResultListener { partialResult, done ->
    logger.atInfo().log("partial result: $partialResult")
  }
  .build()

llmInference.generateResponseAsync(inputPrompt)

Przykładowa aplikacja

Aby zobaczyć interfejsy LLM Inference API w działaniu i poznać szeroki zakres funkcji generatywnej AI na urządzeniu, wypróbuj aplikację Google AI Edge Gallery.

Galeria Google AI Edge to aplikacja na Androida typu open source, która służy deweloperom jako interaktywne środowisko testowe. Wyświetla:

  • Praktyczne przykłady użycia interfejsu LLM Inference API do różnych zadań, w tym:
    • Zapytaj o obraz: prześlij obraz i zadaj pytania na jego temat. uzyskiwać opisy, rozwiązywać problemy lub identyfikować obiekty.
    • Prompt Lab: podsumowuj, przekształcaj, generuj kod lub używaj promptów w dowolnej formie, aby poznać przypadki użycia LLM w jednej turze.
    • Czat AI: prowadź rozmowy wieloetapowe.
  • Możliwość odkrywania, pobierania i testowania różnych modeli zoptymalizowanych pod kątem LiteRT z Hugging Face LiteRT Community i oficjalnych wersji Google (np. Gemma 3N).
  • Testy porównawcze wydajności różnych modeli w czasie rzeczywistym na urządzeniu (czas do pierwszego tokena, szybkość dekodowania itp.).
  • Jak importować i testować własne modele niestandardowe .litertlm lub .task.

Ta aplikacja to źródło informacji o praktycznym wdrożeniu interfejsu LLM Inference API i potencjale generatywnej AI na urządzeniu. Poznaj kod źródłowy i pobierz aplikację z  repozytorium GitHub Google AI Edge Gallery.

Opcje konfiguracji

Aby skonfigurować aplikację na Androida, użyj tych opcji konfiguracji:

Nazwa opcji Opis Zakres wartości Wartość domyślna
modelPath Ścieżka do miejsca, w którym model jest przechowywany w katalogu projektu. PATH Nie dotyczy
maxTokens Maksymalna liczba tokenów (tokenów wejściowych i wyjściowych), które obsługuje model. Liczba całkowita 512
topK Liczba tokenów, które model bierze pod uwagę na każdym etapie generowania. Ogranicza prognozy do k najbardziej prawdopodobnych tokenów. Liczba całkowita 40
temperature Wielkość losowości wprowadzanej podczas generowania. Wyższa temperatura zapewnia większą kreatywność generowanego tekstu, a niższa – bardziej przewidywalne generowanie. Liczba zmiennoprzecinkowa 0,8
randomSeed Losowy seed użyty podczas generowania tekstu. Liczba całkowita 0
loraPath Ścieżka bezwzględna do modelu LoRA na urządzeniu. Uwaga: ta opcja jest zgodna tylko z modelami GPU. PATH Nie dotyczy
resultListener Ustawia odbiorcę wyników, aby otrzymywać wyniki asynchronicznie. Ma zastosowanie tylko w przypadku korzystania z metody generowania asynchronicznego. Nie dotyczy Nie dotyczy
errorListener Ustawia opcjonalny odbiornik błędów. Nie dotyczy Nie dotyczy

Multimodalne prompty

Interfejsy LLM Inference API na Androida obsługują promptowanie multimodalne za pomocą modeli, które akceptują dane wejściowe w postaci tekstu, obrazu i dźwięku. Po włączeniu multimodalności użytkownicy mogą uwzględniać w promptach kombinację obrazów i tekstu lub dźwięku i tekstu.Duży model językowy generuje wtedy odpowiedź tekstową.

Aby rozpocząć, użyj wariantu modelu Gemma 3n zgodnego z MediaPipe:

Więcej informacji znajdziesz w dokumentacji Gemma-3n.

Aby włączyć wprowadzanie obrazów lub dźwięku w interfejsie LLM Inference API, wykonaj te czynności.

Obraz wejściowy

Aby podać obrazy w prompcie, przekonwertuj obrazy lub klatki wejściowe na obiekt com.google.mediapipe.framework.image.MPImage przed przekazaniem go do interfejsu LLM Inference API:

import com.google.mediapipe.framework.image.BitmapImageBuilder
import com.google.mediapipe.framework.image.MPImage

// Convert the input Bitmap object to an MPImage object to run inference
val mpImage = BitmapImageBuilder(image).build()

Aby włączyć obsługę obrazu w interfejsie LLM Inference API, ustaw opcję konfiguracji EnableVisionModality na true w opcjach wykresu:

LlmInferenceSession.LlmInferenceSessionOptions sessionOptions =
  LlmInferenceSession.LlmInferenceSessionOptions.builder()
    ...
    .setGraphOptions(GraphOptions.builder().setEnableVisionModality(true).build())
    .build();

Ustaw maksymalnie 10 obrazów na sesję.

LlmInferenceOptions options = LlmInferenceOptions.builder()
  ...
  .setMaxNumImages(10)
  .build();

Poniżej znajdziesz przykładową implementację interfejsu LLM Inference API skonfigurowanego do obsługi danych wejściowych w postaci obrazów i tekstu:

MPImage image = getImageFromAsset(BURGER_IMAGE);

LlmInferenceSession.LlmInferenceSessionOptions sessionOptions =
  LlmInferenceSession.LlmInferenceSessionOptions.builder()
    .setTopK(10)
    .setTemperature(0.4f)
    .setGraphOptions(GraphOptions.builder().setEnableVisionModality(true).build())
    .build();

try (LlmInference llmInference =
    LlmInference.createFromOptions(ApplicationProvider.getApplicationContext(), options);
  LlmInferenceSession session =
    LlmInferenceSession.createFromOptions(llmInference, sessionOptions)) {
  session.addQueryChunk("Describe the objects in the image.");
  session.addImage(image);
  String result = session.generateResponse();
}

Wejście audio

Włączanie obsługi dźwięku w LlmInferenceOptions

val inferenceOptions = LlmInference.LlmInferenceOptions.builder()
  ...
  .setAudioModelOptions(AudioModelOptions.builder().build())
  .build()

Włącz obsługę dźwięku w obiekcie sessionOptions.

    val sessionOptions =  LlmInferenceSessionOptions.builder()
      ...
      .setGraphOptions(GraphOptions.builder().setEnableAudioModality(true).build())
      .build()

Wysyłanie danych audio podczas wnioskowania. Uwaga: dźwięk musi być w formacie mono (.wav).


val audioData: ByteArray = ...
inferenceEngine.llmInferenceSession.addAudio(audioData)

Poniżej znajdziesz przykładową implementację interfejsu LLM Inference API skonfigurowaną do obsługi danych wejściowych w postaci audio i tekstu:

val audioData: ByteArray = ...
val inferenceOptions = LlmInference.LlmInferenceOptions.builder()
  ...
  .setAudioModelOptions(AudioModelOptions.builder().build())
  .build()
val sessionOptions =  LlmInferenceSessionOptions.builder()
  ...
  .setGraphOptions(GraphOptions.builder().setEnableAudioModality(true).build())
  .build()

LlmInference.createFromOptions(context, inferenceOptions).use { llmInference ->
  LlmInferenceSession.createFromOptions(llmInference, sessionOptions).use { session ->
    session.addQueryChunk("Transcribe the following speech segment:")
    session.addAudio(audioData)
    val result = session.generateResponse()
  }
}

Dostosowywanie LoRA

Interfejs LLM Inference API obsługuje dostrajanie LoRA (Low-Rank Adaptation) za pomocą biblioteki PEFT (Parameter-Efficient Fine-Tuning). Dostrajanie LoRA dostosowuje działanie dużych modeli językowych za pomocą ekonomicznego procesu trenowania, który tworzy mały zestaw wag podlegających trenowaniu na podstawie nowych danych treningowych, zamiast ponownie trenować cały model.

Interfejs LLM Inference API obsługuje dodawanie wag LoRA do warstw uwagi modeli Gemma-2 2B, Gemma 2B i Phi-2. Pobierz model w formacie safetensors.

Aby utworzyć wagi LoRA, model podstawowy musi być w formacie safetensors. Po wytrenowaniu modelu LoRA możesz przekonwertować go do formatu FlatBuffers, aby uruchomić go w MediaPipe.

Przygotowywanie wag LoRA

Skorzystaj z przewodnika LoRA Methods z biblioteki PEFT, aby wytrenować dostrojony model LoRA na własnym zbiorze danych.

Interfejs LLM Inference API obsługuje LoRA tylko w przypadku warstw uwagi, więc w polu LoraConfig należy określić tylko warstwy uwagi:

# For Gemma
from peft import LoraConfig
config = LoraConfig(
    r=LORA_RANK,
    target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
)

# For Phi-2
config = LoraConfig(
    r=LORA_RANK,
    target_modules=["q_proj", "v_proj", "k_proj", "dense"],
)

Po wytrenowaniu modelu na przygotowanym zbiorze danych i zapisaniu modelu dostrojone wagi modelu LoRA są dostępne w adapter_model.safetensors. Plik safetensors to punkt kontrolny LoRA używany podczas konwersji modelu.

Konwersja modelu

Użyj pakietu MediaPipe Python, aby przekonwertować wagi modelu na format Flatbuffer. Symbol ConversionConfig określa opcje modelu podstawowego wraz z dodatkowymi opcjami LoRA.

import mediapipe as mp
from mediapipe.tasks.python.genai import converter

config = converter.ConversionConfig(
  # Other params related to base model
  ...
  # Must use gpu backend for LoRA conversion
  backend='gpu',
  # LoRA related params
  lora_ckpt=LORA_CKPT,
  lora_rank=LORA_RANK,
  lora_output_tflite_file=LORA_OUTPUT_FILE,
)

converter.convert_checkpoint(config)

Konwerter utworzy 2 pliki Flatbuffer: jeden dla modelu podstawowego, a drugi dla modelu LoRA.

Wnioskowanie modelu LoRA

Android obsługuje statyczne LoRA podczas inicjowania. Aby wczytać model LoRA, podaj ścieżkę do modelu LoRA oraz podstawowy model LLM.

// Set the configuration options for the LLM Inference task
val options = LlmInferenceOptions.builder()
        .setModelPath(BASE_MODEL_PATH)
        .setMaxTokens(1000)
        .setTopK(40)
        .setTemperature(0.8)
        .setRandomSeed(101)
        .setLoraPath(LORA_MODEL_PATH)
        .build()

// Create an instance of the LLM Inference task
llmInference = LlmInference.createFromOptions(context, options)

Aby uruchomić wnioskowanie LLM za pomocą LoRA, użyj tych samych metod generateResponse() lub generateResponseAsync() co w przypadku modelu podstawowego.