LiteRT בממשקי ה-API של Google Play services ל-C ול-C++

LiteRT בסביבת זמן הריצה של Google Play Services מאפשר להריץ מודלים של למידת מכונה (ML) בלי לארוז ספריות LiteRT באופן סטטי באפליקציה. במדריך הזה מוסבר איך להשתמש בממשקי ה-API של C או C++ ל-Google Play Services.

לפני שמתחילים לעבוד עם LiteRT ב-Google Play Services C API או ב-C++ API, צריך לוודא שכלי ה-build CMake מותקן.

עדכון הגדרת ה-build

(1) מוסיפים את יחסי התלות הבאים לקוד של פרויקט האפליקציה כדי לגשת ל-Play Services API עבור LiteRT:

implementation "com.google.android.gms:play-services-tflite-java:16.4.0"

חשוב לזכור שגם אם שם החבילה מסתיים ב--java, החבילה הזו מכילה גם את ממשקי ה-API של C ו-C++.

(2) לאחר מכן, מעדכנים את הבלוק android בקובץ build.gradle של המודול כדי להפעיל את התכונה Prefab ולאפשר גישה ל-C API מסקריפט CMake:

buildFeatures {
  prefab = true
}

(3) [C++ API בלבד] אם אתם משתמשים ב-C++ API, מעתיקים את הקובץ tflite-java-extract-cpp-sdk.gradle לפרויקט, בתיקייה app, ומוסיפים את הקטע הבא לתחילת סקריפט ה-Gradle של האפליקציה (למשל app/build.gradle):

apply from: 'tflite-java-extract-cpp-sdk.gradle'

הקובץ הזה מכיל קוד Gradle לפתיחה אוטומטית של ה-SDK ל-C++ מקובץ ה-AAR של play-services-tflite-java.

(4) [C++ API בלבד] אם אתם משתמשים ב-C++ API, עליכם למצוא את הספרייה שמכילה את קובץ התצורה של CMake של האפליקציה (בדרך כלל CMakeLists.txt). בדרך כלל, הספרייה הזו היא ספריית app/src/main/cpp. לאחר מכן מעתיקים את Findtflite_cc_api.cmake לפרויקט, בתיקיית משנה חדשה בשם Modules בספרייה הזו. הוא מכיל קוד שמאתר את ערכת ה-SDK של C++‏ שחילוץ על ידי סקריפט Gradle בשלב הקודם.

(5) בשלב האחרון, צריך להוסיף את החבילה tensorflowlite_jni_gms_client, ול-C++ API גם את החבילה tflite_cc_api, ששתיהן מיובאות מ-AAR, כיחסי תלות בסקריפט של CMake:

C

find_package(tensorflowlite_jni_gms_client REQUIRED CONFIG)

# Set up C/C++ compiler flags to enable use of TFLite in Play services
# (rather than regular TFLite bundled with the app).
add_compile_definitions(TFLITE_IN_GMSCORE)
add_compile_definitions(TFLITE_WITH_STABLE_ABI)

target_link_libraries(tflite-jni # your JNI lib target
        tensorflowlite_jni_gms_client::tensorflowlite_jni_gms_client
        android # other deps for your target
        log)
      

C++‎

# Set up TFLite in Play services C API (tensorflowlite_jni_gms_client) dependency.

find_package(tensorflowlite_jni_gms_client REQUIRED CONFIG)

# Set up TFLite in Play services C++ API (tflite_cc_api) dependency.

list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Modules")

find_package(tflite_cc_api REQUIRED MODULE)
include_directories(${tflite_cc_api_INCLUDE_DIR})
add_subdirectory(${tflite_cc_api_DIR} tflite_cc_api_build)

# Set up C/C++ compiler flags to enable use of TFLite in Play services
# (rather than regular TFLite bundled with the app).
add_compile_definitions(TFLITE_IN_GMSCORE)
add_compile_definitions(TFLITE_WITH_STABLE_ABI)

target_link_libraries(tflite-jni # your JNI lib target
        tflite_cc_api::tflite_cc_api
        tensorflowlite_jni_gms_client::tensorflowlite_jni_gms_client
        android # other deps for your target
        log)
      

איך מאתחלים את סביבת זמן הריצה של LiteRT

לפני שמפעילים את LiteRT C או C++ API, צריך לאתחל את סביבת זמן הריצה TfLiteNative בקוד Java או Kotlin.

Java

Task tfLiteInitializeTask = TfLiteNative.initialize(context);
      

Kotlin

val tfLiteInitializeTask: Task = TfLiteNative.initialize(context)
        

באמצעות Google Play Services Task API, TfLiteNative.initialize מפעיל באופן אסינכרוני את סביבת זמן הריצה של TFLite מ-Google Play Services בתהליך זמן הריצה של האפליקציה. משתמשים ב-addOnSuccessListener() כדי לוודא שהמשימה TfLite.initialize() תושלם לפני שמריצים קוד שמקבל גישה לממשקי LiteRT API. אחרי שהמשימה תושלם בהצלחה, תוכלו להפעיל את כל ממשקי ה-API המקוריים של TFLite.

הטמעת קוד Native

כדי להשתמש ב-LiteRT ב-Google Play Services עם הקוד שלכם ב-C/C++, תוכלו לבצע אחת מהפעולות הבאות (או את שתיהן):

  • להצהיר על פונקציות JNI חדשות כדי לקרוא לפונקציות C או C++ מקוד ה-Java
  • קוראים ל-LiteRT Native API מהקוד הקיים ב-C או ב-C++.

פונקציות JNI

כדי לאפשר לקוד Java/Kotlin לגשת לסביבת זמן הריצה של LiteRT שהוגדרה בקוד C/C++‎, אפשר להצהיר על פונקציות JNI חדשות באופן הבא:

Java

package com.google.samples.gms.tflite.c;

public class TfLiteJni {
  static {
    System.loadLibrary("tflite-jni");
  }
  public TfLiteJni() { /**/ };
  public native void loadModel(AssetManager assetManager, String assetName);
  public native float[] runInference(float[] input);  // For example.
}
      

Kotlin

package com.google.samples.gms.tflite.c

class TfLiteJni() {
  companion object {
    init {
      System.loadLibrary("tflite-jni")
    }
  }
  external fun loadModel(assetManager: AssetManager, assetName: String)
  external fun runInference(input: FloatArray): FloatArray  // For example.
}
        

התאמה לפונקציות loadModel ו-runInference הבאות ב-C או ב-C++‎:

#ifdef __cplusplus
extern "C" {
#endif

void Java_com_google_samples_gms_tflite_c_loadModel(
  JNIEnv *env, jobject tflite_jni, jobject asset_manager, jstring asset_name){
  //...
}

jfloatArray Java_com_google_samples_gms_tflite_c_TfLiteJni_runInference(
  JNIEnv* env, jobject tfliteJni, jfloatArray input) {
  //...
}

#ifdef __cplusplus
}  // extern "C".
#endif

לאחר מכן תוכלו להפעיל את הפונקציות של C/C++ מהקוד של Java/Kotlin:

Java

tfLiteHandleTask.onSuccessTask(unused -> {
    TfLiteJni jni = new TfLiteJni();
    jni.loadModel(getAssets(), "add.bin");
    //...
});
    

Kotlin

tfLiteHandleTask.onSuccessTask {
    val jni = TfLiteJni()
    jni.loadModel(assets, "add.bin")
    // ...
}
      

LiteRT בקוד Native

צריך לכלול את קובץ הכותרת המתאים של ה-API כדי לכלול את LiteRT עם Google Play Services API:

C

#include "tensorflow/lite/c/c_api.h"
      

C++‎

#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/model_builder.h"
      

לאחר מכן תוכלו להשתמש ב-LiteRT C API או ב-LiteRT C++ API הרגיל:

C

TfLiteModel* model = TfLiteModelCreate(model_asset, model_asset_length);
// ...
TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate();
// ...
TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options);
      

C++‎

  // Load the model.
  auto model = tflite::FlatBufferModel::VerifyAndBuildFromBuffer(
      model_asset, model_asset_length);
  ...
  // Initialize the interpreter.
  BuiltinOpResolver op_resolver;
  InterpreterBuilder interpreter_builder(*model, op_resolver);
  interpreter_builder(&interpreter);
  std::unique_ptr<Interpreter>` interpreter;
  interpreter_builder(&interpreter);
      

ממשקי API נתמכים

C

הכותרות של LiteRT עם Google Play Services C API מספקות את אותו API כמו LiteRT C API הרגיל, לא כולל תכונות שהוצאו משימוש או תכונות ניסיוניות. בשלב הזה, הפונקציות והסוגים מהכותרות הבאות זמינים.

ממשקי API של TensorFlow Lite לטעינה ולהרצה של מודלים:

tensorflow/lite/c/c_api.h
tensorflow/lite/c/c_api_types.h
      

ממשקי API של תוספים ל-TensorFlow Lite להגדרת אופרטורים וסוכני העברה בהתאמה אישית (למשל, להאצת חומרה):

tensorflow/lite/c/c_api_opaque.h
tensorflow/lite/c/common.h
tensorflow/lite/c/builtin_op_data.h
tensorflow/lite/builtin_ops.h
      

הענקת גישה לממשקי API של יישומי פלאגין לשימוש בחשבונות משתמשים קיימים:

tensorflow/lite/acceleration/configuration/c/gpu_plugin.h
tensorflow/lite/acceleration/configuration/c/xnnpack_plugin.h
      

לתשומת ליבכם, אין תמיכה בפונקציות מהכותרת c_api_experimental.h.

כדי להשתמש בפונקציות ספציפיות ל-LiteRT עם Google Play Services, צריך לכלול את הכותרת הבאה:

tensorflow/lite/abi/tflite.h
.

C++‎

הכותרות של LiteRT עם Google Play Services C++ API מספקות את אותו ממשק API כמו LiteRT C++ API הרגיל, לא כולל תכונות שהוצאו משימוש או תכונות ניסיוניות, ועם כמה חריגים קטנים שצוינו בהמשך הקטע הזה. הפונקציונליות מהכותרות הבאות זמינה:

tensorflow/lite/model_builder.h
tensorflow/lite/interpreter_builder.h
tensorflow/lite/interpreter.h
tensorflow/lite/signature_runner.h
tensorflow/lite/acceleration/configuration/delegate_registry.h
tensorflow/lite/kernels/builtin_op_kernels.h
tensorflow/lite/kernels/register.h
tensorflow/lite/tools/verifier.h
      

ב-tensorflow/lite/interpreter.h, ה-API הנתמך עם שירותי Play לא כולל כמה חברים ב-tflite::Interpreter של LiteRT לא מציע ABI יציב:

Interpreter::variables()
Interpreter::nodes_size()
Interpreter::node_and_registration(int node_index)
Interpreter::kTensorsReservedCapacity
Interpreter::kTensorsCapacityHeadroom
Interpreter::OpProfilingString(const TfLiteRegistration&, const TfLiteNode*)
Interpreter::SetExternalContext(TfLiteExternalContextType type, TfLiteExternalContext* ctx)