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

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

המשימה הזו תומכת ב-Gemma 2B, שהיא חלק ממשפחה של מודלים פתוחים וקלים וחדשניים, שנבנו על סמך אותם מחקר וטכנולוגיה שמשמשים ליצירת המודלים של Gemini. הוא גם תומך במודלים החיצוניים הבאים: Phi-2, Falcon-RW-1B ו-StableLM-3B, יחד עם כל המודלים שיוצאו דרך AI Edge.

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

קוד לדוגמה

המדריך הזה מתייחס לדוגמה לאפליקציה בסיסית ליצירת טקסט ב-Android. תוכלו להשתמש באפליקציה כנקודת התחלה של אפליקציה משלכם ל-Android, או להתייחס אליה כשאתם משנים אפליקציה קיימת. הקוד לדוגמה מתארח ב-GitHub.

הורדת הקוד

בהוראות הבאות מוסבר איך ליצור עותק מקומי של הקוד לדוגמה באמצעות כלי שורת הפקודה git.

כדי להוריד את הקוד לדוגמה:

  1. משכפלים את מאגר ה-Git באמצעות הפקודה הבאה:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. לחלופין, אפשר להגדיר את מכונת ה-Git לשימוש בקופה עם נתונים ספורים, כדי שיהיו לכם רק את הקבצים של האפליקציה לדוגמה של LLM Inference API:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/llm_inference/android
    

אחרי שיוצרים גרסה מקומית של הקוד לדוגמה, אפשר לייבא את הפרויקט אל Android Studio ולהפעיל את האפליקציה. לקבלת הוראות, אפשר לעיין במדריך ההגדרה ל-Android.

הגדרה

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

יחסי תלות

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

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

דגם

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

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

הורדת מודל

לפני שמפעילים את LLM Inference API, צריך להוריד אחד מהמודלים הנתמכים ולאחסן את הקובץ בספריית הפרויקט:

  • Gemma 2B: חלק ממשפחה של מודלים פתוחים וקלים וחדשניים שנוצרו על סמך אותם מחקר וטכנולוגיה ששימשו ליצירת הדגמים של Gemini. מתאימה למגוון רחב של משימות של יצירת טקסט, כולל מענה על שאלות, תמצות והבנת תשובות.
  • Phi-2: מודל טרנספורמר של 2.7 מיליארד פרמטרים, המתאים ביותר לפורמט Question-Answer, צ'אט וקוד.
  • Falcon-RW-1B: מיליארד פרמטרים של מפענח סיבתי בלבד, מודל שאומן על 350 מיליארד אסימונים של RefinedWeb.
  • StableLM-3B: מודל שפה של 3 מיליארד פרמטרים בלבד, שעבר אימון על טריליון אסימונים ממגוון מערכי נתונים של אנגלית וקוד.

לחלופין, אפשר להשתמש במודלים שממופים ומייצאים דרך AI Edge Troch.

מומלץ להשתמש ב-Gemma 2B, שזמינה ב-Kaggle ומגיע בפורמט שכבר תואם ל-LLM Inference API. אם אתם משתמשים ב-LLM אחר, תצטרכו להמיר את המודל לפורמט ידידותי ל-MediaPipe. מידע נוסף על Gemma 2B זמין באתר של Gemma. למידע נוסף על מודלים זמינים אחרים, עיינו בסקירה הכללית על המשימות קטע על מודלים.

המרת המודל לפורמט MediaPipe

המרה למודל מקורי

אם אתם משתמשים ב-LLM חיצוני (Phi-2, Falcon או StableLM) או בגרסה שאינה של Gemma, השתמשו בסקריפטים של ההמרות כדי לעצב את המודל כך שיתאים ל-MediaPipe.

תהליך המרת המודל מחייב חבילת MediaPipe PyPI. סקריפט ההמרה זמין בכל חבילות MediaPipe אחרי 0.10.11.

מתקינים ומייבאים את יחסי התלות באמצעות הפעולות הבאות:

$ python3 -m pip install mediapipe

משתמשים בספרייה genai.converter כדי להמיר את המודל:

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

config = converter.ConversionConfig(
  input_ckpt=INPUT_CKPT,
  ckpt_format=CKPT_FORMAT,
  model_type=MODEL_TYPE,
  backend=BACKEND,
  output_dir=OUTPUT_DIR,
  combine_file_only=False,
  vocab_model_file=VOCAB_MODEL_FILE,
  output_tflite_file=OUTPUT_TFLITE_FILE,
)

converter.convert_checkpoint(config)

כדי להמיר את מודל LoRA, יש לציין ב-ConversionConfig את האפשרויות של המודל הבסיסי וכן אפשרויות נוספות של LoRA. שימו לב שה-API תומך רק בהסקה של LoRA עם GPU, ולכן הקצה העורפי צריך להיות מוגדר ל-'gpu'.

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_TFLITE_FILE,
)

converter.convert_checkpoint(config)

הממיר יפיק שני קובצי TFLite למאגר אחסון שטוח, אחד למודל הבסיסי והשני למודל LoRA.

פרמטר תיאור ערכים מותרים
input_ckpt הנתיב לקובץ model.safetensors או pytorch.bin. חשוב לשים לב שלפעמים הפורמט של פריטי ה-safetensors מחולקים למספר קבצים, למשל model-00001-of-00003.safetensors, model-00001-of-00003.safetensors. אפשר לציין תבנית של קובץ, כמו model*.safetensors. PATH
ckpt_format פורמט הקובץ של המודל. {"safetensors", "pytorch"}
model_type ה-LLM עובר המרה. {"PHI_2", "FALCON_RW_1B", "STABLELM_4E1T_3B", "GEMMA_2B"}
backend המעבד (הגישה) ששימש להפעלת המודל. {"cpu", "gpu"}
output_dir הנתיב לספריית הפלט שמארחת את קובצי המשקל לכל שכבה. PATH
output_tflite_file הנתיב לקובץ הפלט. לדוגמה, "model_cpu.bin" או "model_gpu.bin". הקובץ הזה תואם רק ל-LLM Inference API, ואי אפשר להשתמש בו כקובץ 'tflite' כללי. PATH
vocab_model_file הנתיב לספרייה שמאחסנת את הקבצים tokenizer.json ו-tokenizer_config.json. עבור Gemma, מצביעים על הקובץ tokenizer.model היחיד. PATH
lora_ckpt הנתיב לקובץ Safetensors של LoRA ששומר את משקל המתאם של LoRA. PATH
lora_rank מספר שלם שמייצג את הדירוג של LoRA ckpt. נדרש כדי להמיר את משקולות הלורה. אם לא מציינים את הפרמטר הזה, הממיר מניח שאין משקלי LoRA. הערה: רק הקצה העורפי של ה-GPU תומך ב-LoRA. מספר שלם
lora_output_tflite_file שם קובץ tflite של הפלט של המשקולות של LoRA. PATH

המרה של מודל AI Edge

אם אתם משתמשים ב-LLM שממופה למודל TFLite באמצעות AI Edge, תוכלו להשתמש בסקריפט הקיבוץ כדי ליצור חבילת משימות. תהליך הקיבוץ כולל את המודל הממופה עם מטא-נתונים נוספים (למשל, פרמטרים של אסימון) שנדרשים כדי להריץ הסקת מסקנות מקצה לקצה.

תהליך קיבוץ המודלים מחייב חבילת MediaPipe PyPI. סקריפט ההמרה זמין בכל חבילות MediaPipe אחרי 0.10.14.

מתקינים ומייבאים את יחסי התלות באמצעות הפעולות הבאות:

$ python3 -m pip install mediapipe

אפשר להשתמש בספרייה genai.bundler כדי לקבץ את המודל:

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

config = bundler.BundleConfig(
    tflite_model=TFLITE_MODEL,
    tokenizer_model=TOKENIZER_MODEL,
    start_token=START_TOKEN,
    stop_tokens=STOP_TOKENS,
    output_filename=OUTPUT_FILENAME,
    enable_bytes_to_unicode_mapping=ENABLE_BYTES_TO_UNICODE_MAPPING,
)
bundler.create_bundle(config)
פרמטר תיאור ערכים מותרים
tflite_model הנתיב למודל TFLite שיוצא באמצעות AI Edge. PATH
tokenizer_model הנתיב למודל האסימונים של SentencePiece. PATH
start_token אסימון התחלה ספציפי לדגם. אסימון ההתחלה חייב להיות קיים במודל ההמרה לאסימונים. מחרוזת
stop_tokens הדגמה של אסימוני עצירה ספציפיים. אסימוני העצירה חייבים להיות קיימים במודל ההמרה לאסימונים. רשימה[STRING]
output_filename שם קובץ חבילת משימות הפלט. PATH

דחיפת המודל למכשיר

מעבירים את התוכן של התיקייה 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.bin

יצירת המשימה

כדי להגדיר את המשימה, ב-MediaPipe LLM Inference API נעשה שימוש בפונקציה createFromOptions(). הפונקציה createFromOptions() מקבלת ערכים לאפשרויות התצורה. מידע נוסף על אפשרויות ההגדרה זמין במאמר אפשרויות תצורה.

הקוד הבא מפעיל את המשימה באמצעות אפשרויות תצורה בסיסיות:

// Set the configuration options for the LLM Inference task
val options = LlmInferenceOptions.builder()
        .setModelPATH('/data/local/.../')
        .setMaxTokens(1000)
        .setTopK(40)
        .setTemperature(0.8)
        .setRandomSeed(101)
        .build()

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

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

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

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

הכנת הנתונים

ה-LLM Inference API מקבל את מקורות הקלט הבאים:

  • הנחיה (מחרוזת): שאלה או הנחיה.
val inputPrompt = "Compose an email to remind Brett of lunch plans at noon on Saturday."

מריצים את המשימה.

משתמשים בשיטה generateResponse() כדי ליצור תגובת טקסט לטקסט הקלט שהוזן בקטע הקודם (inputPrompt), וכך נוצרת תשובה אחת.

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)

טיפול בתוצאות והצגתן

ה-LLM Inference API מחזיר LlmInferenceResult, שכולל את טקסט התשובה שנוצר.

Here's a draft you can use:

Subject: Lunch on Saturday Reminder

Hi Brett,

Just a quick reminder about our lunch plans this Saturday at noon.
Let me know if that still works for you.

Looking forward to it!

Best,
[Your Name]

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

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

התמיכה של LoRA ב-LLM Inference API פועלת במודלים מסוג Gemma-2B ו-Pi-2 בקצה העורפי של ה-GPU, עם משקלי LoRA שרלוונטיים לשכבות תשומת לב בלבד. ההטמעה הראשונית הזו משמשת כ-API ניסיוני לפיתוחים עתידיים, עם תוכניות לתמוך במודלים נוספים ובסוגים שונים של שכבות בעדכונים הקרובים.

הכנת מודלים של LoRA

פועלים לפי ההוראות ב-HugingFace כדי לאמן מודל LoRA שעבר כוונון עדין במערך נתונים משלכם עם סוגי מודלים נתמכים, Gemma-2B או Phi-2. הדגמים Gemma-2B ו-Pi-2 זמינים ב-HugingFace בפורמט Safetensors. מכיוון ש-LLM Inference API תומך רק ב-LoRA בשכבות תשומת לב, צריך לציין רק שכבות תשומת לב כשיוצרים את LoraConfig באופן הבא:

# For Gemma-2B
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 שזמינים לציבור הרחב, שמותאמים ל-LLM Inference API, שזמינים ב-HugingFace. לדוגמה: monsterapi/gemma-2b-lora-maths-orca-200k עבור Gemma-2B, ו-lole25/phi-2-sft-ultrachat-lora עבור Phi-2.

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

בשלב הבא, צריך להמיר את משקלי המודל ל-TensorFlow Lite Flatbuffer באמצעות חבילת MediaPipe Python. השדה ConversionConfig צריך לציין את האפשרויות של הדגם הבסיסי וכן אפשרויות נוספות של LoRA. שימו לב: ה-API תומך רק בהסקה של LoRA עם GPU, ולכן הקצה העורפי צריך להיות מוגדר ל-'gpu'.

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_TFLITE_FILE,
)

converter.convert_checkpoint(config)

הממיר יפיק שני קובצי TFLite למאגר אחסון שטוח, אחד למודל הבסיסי והשני למודל LoRA.

הסקת מודל LoRA

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

Android תומך ב-LoRA סטטית במהלך האתחול. כדי לטעון מודל LoRA, המשתמשים מציינים את הנתיב של מודל LoRA וגם את ה-LLM הבסיסי.

// Set the configuration options for the LLM Inference task
val options = LlmInferenceOptions.builder()
        .setModelPath('<path to base model>')
        .setMaxTokens(1000)
        .setTopK(40)
        .setTemperature(0.8)
        .setRandomSeed(101)
        .setLoraPath('<path to LoRA model>')
        .build()

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

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