מדריך להסקת מודלים של LLM ל-Android

‫LLM Inference API מאפשר להריץ מודלים גדולים של שפה (LLM) באופן מלא במכשיר עבור אפליקציות ל-Android. אפשר להשתמש בו כדי לבצע מגוון רחב של משימות, כמו יצירת טקסט, אחזור מידע בצורה של שפה טבעית וסיכום מסמכים. המשימה מספקת תמיכה מובנית במודלים גדולים של שפה (LLM) להמרת טקסט לטקסט, כך שתוכלו להחיל את המודלים העדכניים ביותר של AI גנרטיבי במכשיר על אפליקציות Android.

כדי להוסיף במהירות את LLM Inference API לאפליקציית Android, אפשר לעיין במדריך למתחילים. דוגמה בסיסית לאפליקציית Android שמריצה את LLM Inference API זמינה באפליקציה לדוגמה. כדי להבין יותר לעומק איך פועל ה-API של LLM Inference, אפשר לעיין בקטעים אפשרויות הגדרה, המרת מודל וכוונון LoRA.

אפשר לראות את המשימה הזו בפעולה באמצעות הדמו של MediaPipe Studio. מידע נוסף על היכולות, המודלים ואפשרויות ההגדרה של המשימה הזו זמין במאמר סקירה כללית.

מדריך למתחילים

כדי להוסיף את LLM Inference API לאפליקציית Android: ממשק ה-API של LLM Inference מותאם למכשירי Android מתקדמים, כמו Pixel 8 ו-Samsung S23 ואילך, ולא תומך באופן מהימן באמולטורים של מכשירים.

הוספת יחסי תלות

‫LLM Inference API משתמש בספרייה com.google.mediapipe:tasks-genai. מוסיפים את התלות הזו לקובץ build.gradle של אפליקציית Android:

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

הורדת מודל

מורידים את Gemma-3 1B בפורמט מכומת של 4 ביט מ-Hugging Face. מידע נוסף על המודלים הזמינים מופיע במסמכי התיעוד בנושא מודלים.

מעבירים את התוכן של התיקייה output_path למכשיר Android.

$ 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

הפעלת המשימה

מאחלים את המשימה עם אפשרויות הגדרה בסיסיות:

// 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)

הרצת המשימה

משתמשים ב-generateResponse() method כדי ליצור תשובת טקסט. כך נוצרת תשובה אחת.

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

כדי להזרים את התשובה, משתמשים בשיטה generateResponseAsync().

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

llmInference.generateResponseAsync(inputPrompt)

אפליקציה לדוגמה

כדי לראות את ממשקי ה-API של LLM Inference בפעולה ולבדוק מגוון רחב של יכולות AI גנרטיבי במכשיר, כדאי לעיין באפליקציית Google AI Edge Gallery.

‫Google AI Edge Gallery היא אפליקציית Android בקוד פתוח שמשמשת כמגרש משחקים אינטראקטיבי למפתחים. היא כוללת:

  • דוגמאות מעשיות לשימוש ב-LLM Inference API למשימות שונות, כולל:
    • שאילת שאלות על תמונה: מעלים תמונה ושואלים עליה שאלות. לקבל תיאורים, לפתור בעיות או לזהות אובייקטים.
    • מעבדת ההנחיות: אפשר לסכם, לכתוב מחדש, ליצור קוד או להשתמש בהנחיות חופשיות כדי לבחון תרחישים לדוגמה של מודלים גדולים של שפה (LLM) עם אינטראקציה אחת.
    • צ'אט עם AI: השתתפות בשיחות עם זיכרון.
  • היכולת לגלות, להוריד ולנסות מגוון של מודלים שעברו אופטימיזציה ל-LiteRT מהקהילה של Hugging Face LiteRT ומהגרסאות הרשמיות של Google (למשל, Gemma 3N).
  • נקודות השוואה לביצועים בזמן אמת במכשיר עבור דגמים שונים (הזמן עד לטוקן הראשון, מהירות הפענוח וכו').
  • איך מייבאים ובודקים מודלים מותאמים אישית של .litertlm או .task.

האפליקציה הזו היא משאב להבנת היישום המעשי של LLM Inference API והפוטנציאל של AI גנרטיבי במכשיר. אפשר לעיין בקוד המקור ולהוריד את האפליקציה ממאגר Google AI Edge Gallery GitHub.

אפשרויות הגדרה

כדי להגדיר אפליקציית Android, משתמשים באפשרויות ההגדרה הבאות:

שם האפשרות תיאור טווח ערכים ערך ברירת מחדל
modelPath הנתיב למיקום שבו המודל מאוחסן בספריית הפרויקט. נתיב לא רלוונטי
maxTokens מספר הטוקנים המקסימלי (טוקנים של קלט + טוקנים של פלט) שהמודל יכול לטפל בהם. מספר שלם 512
topK מספר הטוקנים שהמודל לוקח בחשבון בכל שלב של יצירת התוכן. התחזיות מוגבלות ל-k האסימונים בעלי ההסתברות הגבוהה ביותר. מספר שלם 40
temperature רמת הרנדומיזציה שהוכנסה במהלך היצירה. טמפרטורה גבוהה יותר מובילה ליצירתיות רבה יותר בטקסט שנוצר, ואילו טמפרטורה נמוכה יותר מובילה ליצירה צפויה יותר. מספר ממשי (float) 0.8
randomSeed הערך האקראי שמשמש במהלך יצירת הטקסט. מספר שלם 0
loraPath הנתיב המוחלט למודל LoRA באופן מקומי במכשיר. הערה: האפשרות הזו תואמת רק למודלים של GPU. נתיב לא רלוונטי
resultListener הגדרת מאזין התוצאות לקבלת התוצאות באופן אסינכרוני. האפשרות הזו רלוונטית רק כשמשתמשים בשיטת היצירה האסינכרונית. לא רלוונטי לא רלוונטי
errorListener הגדרת מאזין שגיאות אופציונלי. לא רלוונטי לא רלוונטי

הנחיות מרובות מצבים

ממשקי ה-API של LLM Inference ל-Android תומכים בהנחיות מולטי-מודאליות עם מודלים שמקבלים קלט של טקסט, תמונות ואודיו. כשמפעילים את התכונה 'מולטי-מודאליות', המשתמשים יכולים לכלול בהנחיות שלהם שילוב של תמונות וטקסט או אודיו וטקסט.ה-LLM מספק בתגובה טקסט.

כדי להתחיל, משתמשים בגרסה של Gemma 3n שתואמת ל-MediaPipe:

  • Gemma-3n E2B: מודל יעיל של 2B בסדרת Gemma-3n.
  • Gemma-3n E4B: מודל יעיל של 4B בסדרת Gemma-3n.

מידע נוסף זמין במסמכי התיעוד של Gemma-3n.

כדי להפעיל קלט של תמונות או אודיו ל-LLM Inference API, פועלים לפי השלבים הבאים.

קלט של תמונה

כדי לספק תמונות בהנחיה, צריך להמיר את תמונות הקלט או המסגרות לאובייקט com.google.mediapipe.framework.image.MPImage לפני שמעבירים אותו ל-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()

כדי להפעיל תמיכה בראייה ב-LLM Inference API, מגדירים את אפשרות ההגדרה EnableVisionModality לערך true באפשרויות הגרף:

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

אפשר להגדיר עד 10 תמונות לכל סשן.

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

הנה דוגמה להטמעה של LLM Inference API שהוגדר לטיפול בקלט של ראייה וטקסט:

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();
}

קלט אודיו

הפעלת תמיכה באודיו ב-LlmInferenceOptions

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

הפעלת תמיכה באודיו ב-sessionOptions

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

שליחת נתוני אודיו במהלך הסקת מסקנות. הערה: האודיו צריך להיות בערוץ מונו בפורמט ‎ .wav


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

הנה דוגמה להטמעה של LLM Inference API שהוגדר לטפל בקלט של אודיו וטקסט:

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

התאמה אישית של LoRA

‫LLM Inference API תומך בשיפור דיוק של מודלים באמצעות LoRA (Low-Rank Adaptation) בעזרת ספריית PEFT (Parameter-Efficient Fine-Tuning). התאמה באמצעות LoRA מאפשרת להתאים אישית את ההתנהגות של מודלים מסוג LLM באמצעות תהליך אימון חסכוני. התהליך הזה יוצר קבוצה קטנה של משקלים שאפשר לאמן על סמך נתוני אימון חדשים, במקום לאמן מחדש את כל המודל.

‫LLM Inference API תומך בהוספת משקלים של LoRA לשכבות של מנגנון תשומת הלב במודלים Gemma-2 2B, ‏ Gemma 2B ו-Phi-2. מורידים את המודל בפורמט safetensors.

כדי ליצור משקלים של LoRA, מודל הבסיס צריך להיות בפורמט safetensors. אחרי אימון LoRA, אפשר להמיר את המודלים לפורמט FlatBuffers כדי להריץ אותם ב-MediaPipe.

הכנת משקלים של LoRA

אפשר להשתמש במדריך LoRA Methods מ-PEFT כדי לאמן מודל LoRA מכוונן על מערך נתונים משלכם.

ה-API של LLM Inference תומך ב-LoRA רק בשכבות של מנגנון תשומת הלב, לכן צריך לציין רק את השכבות של מנגנון תשומת הלב ב-LoraConfig:

# 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"],
)

אחרי האימון על מערך הנתונים המוכן ושמירת המודל, המשקלים של מודל LoRA שעבר כוונון עדין זמינים ב-adapter_model.safetensors. קובץ safetensors הוא נקודת ביקורת (checkpoint) של LoRA שמשמשת במהלך המרת המודל.

המרות לפי מודל

משתמשים בחבילת MediaPipe Python כדי להמיר את משקלי המודל לפורמט Flatbuffer. התג ConversionConfig מציין את האפשרויות של מודל הבסיס יחד עם האפשרויות הנוספות של 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)

הכלי להמרה ייצור שני קובצי Flatbuffer, אחד למודל הבסיסי ואחד למודל LoRA.

היקש של מודל LoRA

מערכת Android תומכת ב-LoRA סטטי במהלך האתחול. כדי לטעון מודל LoRA, צריך לציין את הנתיב של מודל LoRA וגם את מודל שפה גדול (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)

כדי להריץ הסקה של LLM עם LoRA, משתמשים באותן שיטות generateResponse() או generateResponseAsync() כמו במודל הבסיסי.