ใช้โมเดล TensorFlow Lite ที่กำหนดเองใน Android

หากแอปใช้แบบกำหนดเอง TensorFlow โมเดล Lite คุณสามารถใช้ Firebase ML เพื่อทำให้โมเดลใช้งานได้ โดย การทำให้โมเดลใช้งานได้กับ Firebase คุณสามารถลดขนาดการดาวน์โหลดเริ่มต้น และอัปเดตโมเดล ML ของแอปโดยไม่ต้องเผยแพร่เวอร์ชันใหม่ของ แอปของคุณ และด้วย Remote Config และ A/B Testing คุณจะสามารถปรับเปลี่ยน แสดงรูปแบบที่แตกต่างกันแก่ผู้ใช้กลุ่มต่างๆ

โมเดล TensorFlow Lite

โมเดล TensorFlow Lite เป็นโมเดล ML ที่ได้รับการเพิ่มประสิทธิภาพให้ทำงานบนอุปกรณ์เคลื่อนที่ อุปกรณ์ วิธีรับโมเดล TensorFlow Lite

ก่อนเริ่มต้น

  1. หากคุณยังไม่ได้ดำเนินการ เพิ่ม Firebase ลงในโปรเจ็กต์ Android
  2. ในไฟล์ Gradle ของโมดูล (ระดับแอป) (ปกติ <project>/<app-module>/build.gradle.kts หรือ <project>/<app-module>/build.gradle) เพิ่มทรัพยากร Dependency สำหรับไลบรารีโปรแกรมดาวน์โหลดโมเดล Firebase ML สำหรับ Android เราขอแนะนำให้ใช้ Firebase Android BoM เพื่อควบคุมการกำหนดเวอร์ชันไลบรารี

    นอกจากนี้ ในการตั้งค่าโปรแกรมดาวน์โหลดโมเดล Firebase ML คุณจะต้องเพิ่ม TensorFlow Lite SDK ลงในแอป

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:33.5.1"))
    
        // Add the dependency for the Firebase ML model downloader library
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-ml-modeldownloader")
    // Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0")
    }

    เมื่อใช้Firebase Android BoM แอปจะใช้ไลบรารี Firebase Android เวอร์ชันที่เข้ากันได้เสมอ

    (ทางเลือก) เพิ่มทรัพยากร Dependency ของไลบรารี Firebase โดยไม่ใช้ BoM

    หากเลือกไม่ใช้ Firebase BoM คุณต้องระบุเวอร์ชันไลบรารี Firebase แต่ละเวอร์ชัน ในบรรทัดทรัพยากร Dependency

    โปรดทราบว่าหากคุณใช้ไลบรารี Firebase หลายรายการในแอป เราขอแนะนำอย่างยิ่ง แนะนำให้ใช้ BoM ในการจัดการเวอร์ชันไลบรารี เพื่อให้มั่นใจว่าทุกเวอร์ชัน ที่เข้ากันได้

    dependencies {
        // Add the dependency for the Firebase ML model downloader library
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-ml-modeldownloader:25.0.1")
    // Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0")
    }
    หากกำลังมองหาโมดูลไลบรารีสำหรับ Kotlin โดยเฉพาะ จะเริ่มต้นใน ตุลาคม 2023 (Firebase BoM 32.5.0) ทั้งนักพัฒนา Kotlin และ Java สามารถ ขึ้นอยู่กับโมดูลไลบรารีหลัก (ดูรายละเอียดได้ที่ คําถามที่พบบ่อยเกี่ยวกับโครงการริเริ่มนี้)
  3. ให้ประกาศว่าต้องใช้สิทธิ์ INTERNET ในไฟล์ Manifest ของแอป ดังนี้
    <uses-permission android:name="android.permission.INTERNET" />

1. ทำให้โมเดลใช้งานได้

ทำให้โมเดล TensorFlow ที่กำหนดเองใช้งานได้โดยใช้คอนโซล Firebase หรือ SDK ของ Python และ Node.js ของผู้ดูแลระบบ Firebase โปรดดู จัดการและทำให้โมเดลที่กำหนดเองใช้งานได้

หลังจากเพิ่มรูปแบบที่กำหนดเองลงในโปรเจ็กต์ Firebase แล้ว คุณสามารถอ้างอิง ในแอปของคุณโดยใช้ชื่อที่คุณระบุ คุณสามารถติดตั้งใช้งานได้ตลอดเวลา โมเดล TensorFlow Lite ใหม่และดาวน์โหลดโมเดลใหม่ไปยังผู้ใช้ อุปกรณ์โดย กำลังโทรหา getModel() (ดูด้านล่าง)

2. ดาวน์โหลดโมเดลลงในอุปกรณ์และเริ่มต้นอินเทอร์พรีเตอร์ของ TensorFlow Lite

หากต้องการใช้โมเดล TensorFlow Lite ในแอป ให้ใช้ Firebase ML SDK ก่อน เพื่อดาวน์โหลดโมเดลเวอร์ชันล่าสุดลงในอุปกรณ์ จากนั้น สร้างอินสแตนซ์ อินเทอร์พรีเตอร์ของ TensorFlow Lite กับโมเดล

หากต้องการเริ่มดาวน์โหลดโมเดล ให้เรียกเมธอด getModel() ของโปรแกรมดาวน์โหลดโมเดล ระบุชื่อที่คุณกำหนดให้กับโมเดลเมื่ออัปโหลด ไม่ว่าคุณจะ ต้องการดาวน์โหลดรุ่นล่าสุดเสมอ และเงื่อนไขที่คุณ ต้องการอนุญาตให้ดาวน์โหลด

คุณเลือกพฤติกรรมการดาวน์โหลดได้ 3 แบบดังนี้

ประเภทการดาวน์โหลด คำอธิบาย
โมเดล LOCAL_MODEL รับโมเดลในเครื่องจากอุปกรณ์ หากไม่มีโมเดลในเครื่อง ลักษณะการทำงานเหมือน LATEST_MODEL ใช้ร่างคำตอบนี้ ประเภทการดาวน์โหลดหากคุณไม่สนใจ กำลังตรวจหาการอัปเดตโมเดล ตัวอย่างเช่น คุณกำลังใช้การกำหนดค่าระยะไกลเพื่อดึงข้อมูล ชื่อโมเดลและคุณจะอัปโหลดโมเดลเสมอ ภายใต้ชื่อใหม่ (แนะนำ)
LOCAL_MODEL_UPDATE_IN_BACKGROUND รับโมเดลในเครื่องจากอุปกรณ์และ เริ่มอัปเดตโมเดลในเบื้องหลัง หากไม่มีโมเดลในเครื่อง ลักษณะการทำงานเหมือน LATEST_MODEL
โมเดล LATEST_ ดาวน์โหลดรุ่นล่าสุด หากโมเดลในเครื่องคือ เวอร์ชันล่าสุด จะแสดงผลลัพธ์เป็น โมเดล หรือไม่เช่นนั้น ให้ดาวน์โหลดแอปล่าสุด โมเดล ระบบจะบล็อกลักษณะการทำงานนี้จนกว่า มีการดาวน์โหลดเวอร์ชันล่าสุด (ไม่ใช่ แนะนำ) ใช้ลักษณะการทำงานนี้ใน ในกรณีที่คุณต้องการข้อมูลล่าสุด เวอร์ชัน

คุณควรปิดใช้ฟังก์ชันการทำงานที่เกี่ยวข้องกับโมเดล เช่น เป็นสีเทาหรือ ซ่อนบางส่วนของ UI จนกว่าคุณจะยืนยันว่าดาวน์โหลดโมเดลแล้ว

Kotlin+KTX

val conditions = CustomModelDownloadConditions.Builder()
        .requireWifi()  // Also possible: .requireCharging() and .requireDeviceIdle()
        .build()
FirebaseModelDownloader.getInstance()
        .getModel("your_model", DownloadType.LOCAL_MODEL_UPDATE_IN_BACKGROUND,
            conditions)
        .addOnSuccessListener { model: CustomModel? ->
            // Download complete. Depending on your app, you could enable the ML
            // feature, or switch from the local model to the remote model, etc.

            // The CustomModel object contains the local path of the model file,
            // which you can use to instantiate a TensorFlow Lite interpreter.
            val modelFile = model?.file
            if (modelFile != null) {
                interpreter = Interpreter(modelFile)
            }
        }

Java

CustomModelDownloadConditions conditions = new CustomModelDownloadConditions.Builder()
    .requireWifi()  // Also possible: .requireCharging() and .requireDeviceIdle()
    .build();
FirebaseModelDownloader.getInstance()
    .getModel("your_model", DownloadType.LOCAL_MODEL_UPDATE_IN_BACKGROUND, conditions)
    .addOnSuccessListener(new OnSuccessListener<CustomModel>() {
      @Override
      public void onSuccess(CustomModel model) {
        // Download complete. Depending on your app, you could enable the ML
        // feature, or switch from the local model to the remote model, etc.

        // The CustomModel object contains the local path of the model file,
        // which you can use to instantiate a TensorFlow Lite interpreter.
        File modelFile = model.getFile();
        if (modelFile != null) {
            interpreter = new Interpreter(modelFile);
        }
      }
    });

แอปจำนวนมากเริ่มงานดาวน์โหลดในโค้ดเริ่มต้น แต่คุณทำได้ ก่อนที่คุณจะต้องใช้โมเดลดังกล่าว

3. ทำการอนุมานเกี่ยวกับข้อมูลอินพุต

รับรูปร่างอินพุตและเอาต์พุตของโมเดล

อินเทอร์พรีเตอร์โมเดล TensorFlow Lite รับเป็นอินพุตและสร้างเป็นเอาต์พุต อย่างน้อยหนึ่งอาร์เรย์หลายมิติ อาร์เรย์เหล่านี้มี byte int long หรือfloat คุณต้องทราบก่อนจึงจะส่งข้อมูลไปยังโมเดลหรือใช้ผลลัพธ์ได้ จำนวนและมิติข้อมูล ("รูปร่าง") ของอาร์เรย์ที่โมเดลของคุณใช้

หากคุณสร้างโมเดลด้วยตนเอง หรือหากรูปแบบอินพุตและเอาต์พุตของโมเดลคือ คุณอาจมีข้อมูลนี้อยู่แล้ว หากคุณไม่รู้จัก รูปร่างและประเภทข้อมูลของอินพุตและเอาต์พุตของโมเดล คุณสามารถใช้ อินเทอร์พรีเตอร์ของ TensorFlow Lite เพื่อตรวจสอบโมเดล เช่น

Python

import tensorflow as tf

interpreter = tf.lite.Interpreter(model_path="your_model.tflite")
interpreter.allocate_tensors()

# Print input shape and type
inputs = interpreter.get_input_details()
print('{} input(s):'.format(len(inputs)))
for i in range(0, len(inputs)):
    print('{} {}'.format(inputs[i]['shape'], inputs[i]['dtype']))

# Print output shape and type
outputs = interpreter.get_output_details()
print('\n{} output(s):'.format(len(outputs)))
for i in range(0, len(outputs)):
    print('{} {}'.format(outputs[i]['shape'], outputs[i]['dtype']))

ตัวอย่างเอาต์พุต:

1 input(s):
[  1 224 224   3] <class 'numpy.float32'>

1 output(s):
[1 1000] <class 'numpy.float32'>

เรียกใช้ล่าม

หลังจากที่คุณกำหนดรูปแบบอินพุตและเอาต์พุตของโมเดลแล้ว ให้ขอรับ ป้อนข้อมูลและดำเนินการเปลี่ยนรูปแบบข้อมูลที่จำเป็นต่อการได้รับ อินพุตของรูปร่างที่เหมาะสมสำหรับโมเดลของคุณ

ตัวอย่างเช่น หากคุณมีโมเดลการจัดประเภทรูปภาพที่มีรูปร่างอินพุตเป็น ค่าทศนิยม [1 224 224 3] ค่าซึ่งคุณอาจสร้างอินพุต ByteBuffer ได้ จากออบเจ็กต์ Bitmap ดังที่แสดงในตัวอย่างต่อไปนี้

Kotlin+KTX

val bitmap = Bitmap.createScaledBitmap(yourInputImage, 224, 224, true)
val input = ByteBuffer.allocateDirect(224*224*3*4).order(ByteOrder.nativeOrder())
for (y in 0 until 224) {
    for (x in 0 until 224) {
        val px = bitmap.getPixel(x, y)

        // Get channel values from the pixel value.
        val r = Color.red(px)
        val g = Color.green(px)
        val b = Color.blue(px)

        // Normalize channel values to [-1.0, 1.0]. This requirement depends on the model.
        // For example, some models might require values to be normalized to the range
        // [0.0, 1.0] instead.
        val rf = (r - 127) / 255f
        val gf = (g - 127) / 255f
        val bf = (b - 127) / 255f

        input.putFloat(rf)
        input.putFloat(gf)
        input.putFloat(bf)
    }
}

Java

Bitmap bitmap = Bitmap.createScaledBitmap(yourInputImage, 224, 224, true);
ByteBuffer input = ByteBuffer.allocateDirect(224 * 224 * 3 * 4).order(ByteOrder.nativeOrder());
for (int y = 0; y < 224; y++) {
    for (int x = 0; x < 224; x++) {
        int px = bitmap.getPixel(x, y);

        // Get channel values from the pixel value.
        int r = Color.red(px);
        int g = Color.green(px);
        int b = Color.blue(px);

        // Normalize channel values to [-1.0, 1.0]. This requirement depends
        // on the model. For example, some models might require values to be
        // normalized to the range [0.0, 1.0] instead.
        float rf = (r - 127) / 255.0f;
        float gf = (g - 127) / 255.0f;
        float bf = (b - 127) / 255.0f;

        input.putFloat(rf);
        input.putFloat(gf);
        input.putFloat(bf);
    }
}

จากนั้นจัดสรร ByteBuffer ให้ใหญ่พอที่จะมีเอาต์พุตของโมเดลและ ส่งผ่านบัฟเฟอร์อินพุตและบัฟเฟอร์เอาต์พุตไปยังอินเทอร์พรีเตอร์ของ TensorFlow Lite run() วิธี ตัวอย่างเช่น สำหรับรูปร่างเอาต์พุตของ [1 1000] จุดลอยตัว มีดังนี้

Kotlin+KTX

val bufferSize = 1000 * java.lang.Float.SIZE / java.lang.Byte.SIZE
val modelOutput = ByteBuffer.allocateDirect(bufferSize).order(ByteOrder.nativeOrder())
interpreter?.run(input, modelOutput)

Java

int bufferSize = 1000 * java.lang.Float.SIZE / java.lang.Byte.SIZE;
ByteBuffer modelOutput = ByteBuffer.allocateDirect(bufferSize).order(ByteOrder.nativeOrder());
interpreter.run(input, modelOutput);

วิธีที่คุณใช้เอาต์พุตจะขึ้นอยู่กับโมเดลที่คุณใช้

ตัวอย่างเช่น ถ้าคุณกำลังแยกประเภท ในขั้นตอนถัดไป คุณอาจ แมปดัชนีของผลลัพธ์กับป้ายกำกับที่แสดง:

Kotlin+KTX

modelOutput.rewind()
val probabilities = modelOutput.asFloatBuffer()
try {
    val reader = BufferedReader(
            InputStreamReader(assets.open("custom_labels.txt")))
    for (i in probabilities.capacity()) {
        val label: String = reader.readLine()
        val probability = probabilities.get(i)
        println("$label: $probability")
    }
} catch (e: IOException) {
    // File not found?
}

Java

modelOutput.rewind();
FloatBuffer probabilities = modelOutput.asFloatBuffer();
try {
    BufferedReader reader = new BufferedReader(
            new InputStreamReader(getAssets().open("custom_labels.txt")));
    for (int i = 0; i < probabilities.capacity(); i++) {
        String label = reader.readLine();
        float probability = probabilities.get(i);
        Log.i(TAG, String.format("%s: %1.4f", label, probability));
    }
} catch (IOException e) {
    // File not found?
}

ภาคผนวก: ความปลอดภัยของโมเดล

ไม่ว่าคุณจะทำให้โมเดล TensorFlow Lite พร้อมใช้งานกับ Firebase ML, Firebase ML จัดเก็บไว้ในรูปแบบ Protocol Buf มาตรฐานแบบอนุกรมใน ที่จัดเก็บข้อมูลในตัวเครื่อง

ในทางทฤษฎี หมายความว่าทุกคนสามารถคัดลอกโมเดลของคุณได้ อย่างไรก็ตาม ในทางปฏิบัติ โมเดลส่วนใหญ่จะมีความเฉพาะเจาะจงกับแอปพลิเคชันโดยเฉพาะและทำให้ยากต่อการอ่าน (Obfuscate) ด้วย การเพิ่มประสิทธิภาพที่มีความเสี่ยงคล้ายกับการถอดแยกชิ้นส่วนของคู่แข่งและ การนำโค้ดของคุณมาใช้ซ้ำ อย่างไรก็ตาม คุณควรตระหนักถึงความเสี่ยงนี้ก่อนที่จะใช้ โมเดลที่กำหนดเองในแอปของคุณ

ใน Android API ระดับ 21 (Lollipop) ขึ้นไป โมเดลจะดาวน์โหลดไปยัง ไดเรกทอรีที่ ไม่รวมอยู่ในการสำรองข้อมูลอัตโนมัติ

ใน Android API ระดับ 20 และเก่ากว่า ระบบจะดาวน์โหลดโมเดลไปยังไดเรกทอรี ตั้งชื่อว่า com.google.firebase.ml.custom.models ในแอปส่วนตัว ที่จัดเก็บข้อมูลภายใน หากคุณเปิดใช้การสำรองไฟล์โดยใช้ BackupAgent คุณอาจเลือกที่จะยกเว้นไดเรกทอรีนี้