คุณสามารถใช้ ML Kit เพื่อทำการอนุมานในอุปกรณ์ด้วย โมเดล TensorFlow Lite
API นี้ต้องใช้ Android SDK ระดับ 16 (Jelly Bean) ขึ้นไป
ก่อนเริ่มต้น
- หากคุณยังไม่ได้ดำเนินการ เพิ่ม Firebase ลงในโปรเจ็กต์ Android
- เพิ่มทรัพยากร Dependency สำหรับไลบรารี ML Kit Android ลงในโมดูล
ไฟล์ Gradle (ระดับแอป) (ปกติราคา
app/build.gradle
):apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' dependencies { // ... implementation 'com.google.firebase:firebase-ml-model-interpreter:22.0.3' }
- แปลงโมเดล TensorFlow ที่ต้องการใช้เป็นรูปแบบ TensorFlow Lite โปรดดู TOCO: TensorFlow Lite เพิ่มประสิทธิภาพตัวแปลง
โฮสต์หรือรวมกลุ่มโมเดลของคุณ
ก่อนที่คุณจะสามารถใช้โมเดล TensorFlow Lite สำหรับการอนุมานในแอป คุณต้อง ต้องทำให้โมเดลพร้อมใช้งานใน ML Kit ML Kit ใช้ TensorFlow Lite ได้ โมเดลที่โฮสต์จากระยะไกลโดยใช้ Firebase พ่วงกับไบนารีของแอป หรือทั้งสองอย่าง
เมื่อโฮสต์โมเดลใน Firebase คุณจะอัปเดตโมเดลได้โดยไม่ต้องเปิดตัว แอปเวอร์ชันใหม่ และคุณจะใช้ Remote Config และ A/B Testing เพื่อทำสิ่งต่อไปนี้ได้ แสดงรูปแบบต่างๆ แก่ผู้ใช้กลุ่มต่างๆ แบบไดนามิก
หากคุณเลือกที่จะระบุเฉพาะโมเดลโดยการโฮสต์ด้วย Firebase ไม่ใช่ รวมกลุ่มแอปไว้กับแอปของคุณ คุณจะลดขนาดการดาวน์โหลดเริ่มต้นของแอปได้ อย่างไรก็ตาม หากโมเดลไม่ได้รวมอยู่กับแอปของคุณ ฟังก์ชันการทำงานที่เกี่ยวข้องกับโมเดลจะยังไม่พร้อมใช้งานจนกว่าแอปของคุณจะดาวน์โหลด โมเดลของคุณเป็นครั้งแรก
การรวมโมเดลกับแอปจะทำให้คุณมั่นใจได้ว่าฟีเจอร์ ML ของแอป ยังคงใช้งานได้เมื่อรูปแบบที่โฮสต์ด้วย Firebase ไม่พร้อมใช้งาน
โมเดลโฮสต์บน Firebase
วิธีโฮสต์โมเดล TensorFlow Lite บน Firebase
- ในส่วน ML Kit ของคอนโซล Firebase ให้คลิก ในแท็บกําหนดเอง
- คลิกเพิ่มรูปแบบที่กำหนดเอง (หรือเพิ่มโมเดลอื่น)
- ระบุชื่อที่จะใช้ระบุโมเดลใน Firebase
แล้วอัปโหลดไฟล์โมเดล TensorFlow Lite (โดยปกติจะลงท้ายด้วย
.tflite
หรือ.lite
) - ให้ประกาศว่าต้องใช้สิทธิ์ INTERNET ในไฟล์ Manifest ของแอป โดยทำดังนี้
<uses-permission android:name="android.permission.INTERNET" />
หลังจากเพิ่มรูปแบบที่กำหนดเองลงในโปรเจ็กต์ Firebase แล้ว คุณสามารถอ้างอิง ในแอปของคุณโดยใช้ชื่อที่คุณระบุ คุณอัปโหลดได้ทุกเมื่อ โมเดล TensorFlow Lite ใหม่ แอปของคุณจะดาวน์โหลดโมเดลใหม่และ เริ่มใช้งานเมื่อแอปรีสตาร์ทครั้งถัดไป คุณสามารถกำหนดอุปกรณ์ เงื่อนไขที่จำเป็นเพื่อให้แอปพยายามอัปเดตโมเดล (ดูด้านล่าง)
รวมโมเดลเข้ากับแอป
หากต้องการรวมโมเดล TensorFlow Lite กับแอป ให้คัดลอกไฟล์โมเดล (โดยทั่วไป
ที่ลงท้ายด้วย .tflite
หรือ .lite
) ไปยังโฟลเดอร์ assets/
ของแอป (คุณอาจต้อง
หากต้องการสร้างโฟลเดอร์ก่อนโดยการคลิกขวาที่โฟลเดอร์ app/
จากนั้นคลิก
ใหม่ > โฟลเดอร์ > โฟลเดอร์ชิ้นงาน)
จากนั้นเพิ่มข้อมูลต่อไปนี้ลงในไฟล์ build.gradle
ของแอปเพื่อให้ Gradle
ไม่บีบอัดโมเดลเมื่อสร้างแอป:
android {
// ...
aaptOptions {
noCompress "tflite" // Your model's file extension: "tflite", "lite", etc.
}
}
ไฟล์โมเดลจะรวมอยู่ในแพ็กเกจแอปและพร้อมให้ ML Kit ใช้งาน เป็นเนื้อหาดิบ
โหลดโมเดล
หากต้องการใช้โมเดล TensorFlow Lite ในแอป ให้กำหนดค่า ML Kit ด้วย ตำแหน่งที่พร้อมใช้งานโมเดลของคุณ: จากระยะไกลโดยใช้ Firebase ที่จัดเก็บข้อมูลในเครื่อง หรือทั้ง 2 อย่าง หากคุณระบุทั้งโมเดลในเครื่องและระยะไกล คุณสามารถใช้โมเดลระยะไกลได้ (หากมี) และกลับไปใช้ โมเดลที่จัดเก็บไว้ในเครื่อง หากไม่มีโมเดลระยะไกลกำหนดค่าโมเดลที่โฮสต์ด้วย Firebase
หากคุณโฮสต์โมเดลไว้กับ Firebase ให้สร้าง FirebaseCustomRemoteModel
โดยระบุชื่อที่คุณกำหนดโมเดลเมื่ออัปโหลด:
Java
FirebaseCustomRemoteModel remoteModel =
new FirebaseCustomRemoteModel.Builder("your_model").build();
Kotlin+KTX
val remoteModel = FirebaseCustomRemoteModel.Builder("your_model").build()
จากนั้นจึงเริ่มงานดาวน์โหลดโมเดล โดยระบุเงื่อนไขที่คุณ ต้องการอนุญาตให้ดาวน์โหลด หากไม่มีรุ่นนี้อยู่ในอุปกรณ์ หรือรุ่นที่ใหม่กว่า ของโมเดลพร้อมใช้งาน งานจะดาวน์โหลด จาก Firebase ได้ดังนี้
Java
FirebaseModelDownloadConditions conditions = new FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build();
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
// Success.
}
});
Kotlin+KTX
val conditions = FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build()
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Success.
}
แอปจำนวนมากเริ่มงานดาวน์โหลดในโค้ดเริ่มต้น แต่คุณทำได้ ก่อนที่คุณจะต้องใช้โมเดลดังกล่าว
กำหนดค่าโมเดลในเครื่อง
หากคุณรวมกลุ่มโมเดลกับแอป ให้สร้าง FirebaseCustomLocalModel
ที่ระบุชื่อไฟล์ของโมเดล TensorFlow Lite
Java
FirebaseCustomLocalModel localModel = new FirebaseCustomLocalModel.Builder()
.setAssetFilePath("your_model.tflite")
.build();
Kotlin+KTX
val localModel = FirebaseCustomLocalModel.Builder()
.setAssetFilePath("your_model.tflite")
.build()
สร้างล่ามจากโมเดล
หลังจากที่กำหนดค่าแหล่งที่มาของโมเดลแล้ว ให้สร้าง FirebaseModelInterpreter
จากหนึ่งในนั้น
หากคุณมีเฉพาะโมเดลที่รวมภายในเครื่อง ให้สร้างล่ามจาก
ออบเจ็กต์ FirebaseCustomLocalModel
รายการ:
Java
FirebaseModelInterpreter interpreter;
try {
FirebaseModelInterpreterOptions options =
new FirebaseModelInterpreterOptions.Builder(localModel).build();
interpreter = FirebaseModelInterpreter.getInstance(options);
} catch (FirebaseMLException e) {
// ...
}
Kotlin+KTX
val options = FirebaseModelInterpreterOptions.Builder(localModel).build()
val interpreter = FirebaseModelInterpreter.getInstance(options)
หากคุณมีโมเดลที่โฮสต์จากระยะไกล คุณจะต้องตรวจสอบว่ามีการ
ซึ่งดาวน์โหลดมาก่อนที่จะเรียกใช้ คุณตรวจสอบสถานะการดาวน์โหลดโมเดลได้
โดยใช้เมธอด isModelDownloaded()
ของผู้จัดการโมเดล
แต่คุณต้องยืนยันเรื่องนี้ก่อนเรียกใช้ล่ามเท่านั้นหากคุณ มีทั้งโมเดลที่โฮสต์จากระยะไกลและโมเดลที่รวมอยู่ภายใน ในการตรวจสอบนี้เมื่อเริ่มต้นอินเทอร์พรีเตอร์ของโมเดล: สร้าง จากโมเดลระยะไกล หากดาวน์โหลดแล้ว และจากในเครื่อง หากไม่เป็นเช่นนั้น
Java
FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
.addOnSuccessListener(new OnSuccessListener<Boolean>() {
@Override
public void onSuccess(Boolean isDownloaded) {
FirebaseModelInterpreterOptions options;
if (isDownloaded) {
options = new FirebaseModelInterpreterOptions.Builder(remoteModel).build();
} else {
options = new FirebaseModelInterpreterOptions.Builder(localModel).build();
}
FirebaseModelInterpreter interpreter = FirebaseModelInterpreter.getInstance(options);
// ...
}
});
Kotlin+KTX
FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
.addOnSuccessListener { isDownloaded ->
val options =
if (isDownloaded) {
FirebaseModelInterpreterOptions.Builder(remoteModel).build()
} else {
FirebaseModelInterpreterOptions.Builder(localModel).build()
}
val interpreter = FirebaseModelInterpreter.getInstance(options)
}
หากคุณมีเฉพาะโมเดลที่โฮสต์จากระยะไกล คุณควรปิดใช้โมเดลที่เกี่ยวข้องกับ
เช่น เป็นสีเทาหรือซ่อนบางส่วนของ UI จนถึง
คุณยืนยันว่าดาวน์โหลดโมเดลแล้ว คุณสามารถทำได้โดยการแนบ Listener
ไปยังเมธอด download()
ของผู้จัดการโมเดล:
Java
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void v) {
// Download complete. Depending on your app, you could enable
// the ML feature, or switch from the local model to the remote
// model, etc.
}
});
Kotlin+KTX
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Download complete. Depending on your app, you could enable the ML
// feature, or switch from the local model to the remote model, etc.
}
ระบุอินพุตและเอาต์พุตของโมเดล
ถัดไป ให้กำหนดค่ารูปแบบอินพุตและเอาต์พุตของตัวแปลมโมเดล
โมเดล TensorFlow Lite รับเป็นอินพุตและสร้างเอาต์พุตอย่างน้อย 1 รายการ
อาร์เรย์หลายมิติ อาร์เรย์เหล่านี้มี byte
ค่า int
, long
หรือ float
คุณต้อง
กำหนดค่า ML Kit ด้วยจำนวนและขนาด ("รูปร่าง") ของอาร์เรย์
ของโมเดล
หากไม่ทราบรูปร่างและประเภทข้อมูลของอินพุตและเอาต์พุตของโมเดล คุณใช้อินเทอร์พรีเตอร์ Python ของ TensorFlow Lite เพื่อตรวจสอบโมเดลได้ สำหรับ ตัวอย่าง:
import tensorflow as tf interpreter = tf.lite.Interpreter(model_path="my_model.tflite") interpreter.allocate_tensors() # Print input shape and type print(interpreter.get_input_details()[0]['shape']) # Example: [1 224 224 3] print(interpreter.get_input_details()[0]['dtype']) # Example: <class 'numpy.float32'> # Print output shape and type print(interpreter.get_output_details()[0]['shape']) # Example: [1 1000] print(interpreter.get_output_details()[0]['dtype']) # Example: <class 'numpy.float32'>
หลังจากที่คุณกำหนดรูปแบบอินพุตและเอาต์พุตของโมเดลแล้ว คุณสามารถ
กำหนดค่าโมเดลล่ามของแอปโดยสร้าง
FirebaseModelInputOutputOptions
ตัวอย่างเช่น โมเดลการจัดประเภทรูปภาพจุดลอยตัวอาจใช้เป็นอินพุต
อาร์เรย์ Nx224x224x3 ของค่า float
ซึ่งแสดงกลุ่มของ
N รูปภาพ 3 ช่อง (RGB) ขนาด 224x224 และสร้างเป็นเอาต์พุตรายการ
ค่า float
1, 000 ค่า แต่ละค่าแสดงถึงความน่าจะเป็นที่รูปภาพจะเป็นสมาชิก
หนึ่งใน 1000 หมวดหมู่ที่โมเดลคาดการณ์ไว้
สำหรับโมเดลดังกล่าว คุณจะต้องกำหนดค่าอินพุตและเอาต์พุตของอินเทอร์พรีเตอร์ของโมเดล ดังที่แสดงด้านล่าง
Java
FirebaseModelInputOutputOptions inputOutputOptions = new FirebaseModelInputOutputOptions.Builder() .setInputFormat(0, FirebaseModelDataType.FLOAT32, new int[]{1, 224, 224, 3}) .setOutputFormat(0, FirebaseModelDataType.FLOAT32, new int[]{1, 5}) .build();
Kotlin+KTX
val inputOutputOptions = FirebaseModelInputOutputOptions.Builder() .setInputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, 224, 224, 3)) .setOutputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, 5)) .build()
ทำการอนุมานเกี่ยวกับข้อมูลอินพุต
สุดท้าย ในการอนุมานโดยใช้โมเดล ให้รับข้อมูลอินพุตและดำเนินการ การเปลี่ยนรูปแบบของข้อมูลที่จำเป็นต่อการได้รับอาร์เรย์อินพุตของ รูปร่างที่เหมาะสมสำหรับโมเดลของคุณตัวอย่างเช่น หากคุณมีโมเดลการจัดประเภทรูปภาพที่มีรูปร่างอินพุตเป็น
[1 224 224 3] ค่าจุดลอยตัว คุณสามารถสร้างอาร์เรย์อินพุตจาก
Bitmap
ตามที่แสดงในตัวอย่างต่อไปนี้
Java
Bitmap bitmap = getYourInputImage(); bitmap = Bitmap.createScaledBitmap(bitmap, 224, 224, true); int batchNum = 0; float[][][][] input = new float[1][224][224][3]; for (int x = 0; x < 224; x++) { for (int y = 0; y < 224; y++) { int pixel = bitmap.getPixel(x, y); // Normalize channel values to [-1.0, 1.0]. This requirement varies by // model. For example, some models might require values to be normalized // to the range [0.0, 1.0] instead. input[batchNum][x][y][0] = (Color.red(pixel) - 127) / 128.0f; input[batchNum][x][y][1] = (Color.green(pixel) - 127) / 128.0f; input[batchNum][x][y][2] = (Color.blue(pixel) - 127) / 128.0f; } }
Kotlin+KTX
val bitmap = Bitmap.createScaledBitmap(yourInputImage, 224, 224, true) val batchNum = 0 val input = Array(1) { Array(224) { Array(224) { FloatArray(3) } } } for (x in 0..223) { for (y in 0..223) { val pixel = bitmap.getPixel(x, y) // Normalize channel values to [-1.0, 1.0]. This requirement varies by // model. For example, some models might require values to be normalized // to the range [0.0, 1.0] instead. input[batchNum][x][y][0] = (Color.red(pixel) - 127) / 255.0f input[batchNum][x][y][1] = (Color.green(pixel) - 127) / 255.0f input[batchNum][x][y][2] = (Color.blue(pixel) - 127) / 255.0f } }
จากนั้นสร้างออบเจ็กต์ FirebaseModelInputs
โดยใช้
ป้อนข้อมูล และส่งต่อ รวมถึงข้อกำหนดอินพุตและเอาต์พุตของโมเดลไปยัง
เมธอด run
ของโมเดลล่าม:
Java
FirebaseModelInputs inputs = new FirebaseModelInputs.Builder() .add(input) // add() as many input arrays as your model requires .build(); firebaseInterpreter.run(inputs, inputOutputOptions) .addOnSuccessListener( new OnSuccessListener<FirebaseModelOutputs>() { @Override public void onSuccess(FirebaseModelOutputs result) { // ... } }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Kotlin+KTX
val inputs = FirebaseModelInputs.Builder() .add(input) // add() as many input arrays as your model requires .build() firebaseInterpreter.run(inputs, inputOutputOptions) .addOnSuccessListener { result -> // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
หากเรียกใช้สำเร็จ คุณจะรับเอาต์พุตได้โดยเรียกใช้เมธอด getOutput()
ของออบเจ็กต์ที่ส่งไปยังผู้ฟังที่ประสบความสำเร็จ เช่น
Java
float[][] output = result.getOutput(0); float[] probabilities = output[0];
Kotlin+KTX
val output = result.getOutput<Array<FloatArray>>(0) val probabilities = output[0]
วิธีที่คุณใช้เอาต์พุตจะขึ้นอยู่กับโมเดลที่คุณใช้
ตัวอย่างเช่น ถ้าคุณกำลังแยกประเภท ในขั้นตอนถัดไป คุณอาจ แมปดัชนีของผลลัพธ์กับป้ายกำกับที่แสดง:
Java
BufferedReader reader = new BufferedReader( new InputStreamReader(getAssets().open("retrained_labels.txt"))); for (int i = 0; i < probabilities.length; i++) { String label = reader.readLine(); Log.i("MLKit", String.format("%s: %1.4f", label, probabilities[i])); }
Kotlin+KTX
val reader = BufferedReader( InputStreamReader(assets.open("retrained_labels.txt"))) for (i in probabilities.indices) { val label = reader.readLine() Log.i("MLKit", String.format("%s: %1.4f", label, probabilities[i])) }
ภาคผนวก: ความปลอดภัยของโมเดล
ไม่ว่าคุณจะทำให้โมเดล TensorFlow Lite พร้อมใช้งานกับ ML Kit และ ML Kit จะจัดเก็บข้อมูลในรูปแบบ Protocolbuf แบบอนุกรมมาตรฐานใน พื้นที่เก็บข้อมูลในเครื่อง
ในทางทฤษฎี หมายความว่าทุกคนสามารถคัดลอกโมเดลของคุณได้ อย่างไรก็ตาม ในทางปฏิบัติ โมเดลส่วนใหญ่จะมีความเฉพาะเจาะจงกับแอปพลิเคชันโดยเฉพาะและทำให้ยากต่อการอ่าน (Obfuscate) ด้วย การเพิ่มประสิทธิภาพที่มีความเสี่ยงคล้ายกับการถอดแยกชิ้นส่วนของคู่แข่งและ การนำโค้ดของคุณมาใช้ซ้ำ อย่างไรก็ตาม คุณควรตระหนักถึงความเสี่ยงนี้ก่อนที่จะใช้ โมเดลที่กำหนดเองในแอปของคุณ
ใน Android API ระดับ 21 (Lollipop) ขึ้นไป โมเดลจะดาวน์โหลดไปยัง ไดเรกทอรีที่ ไม่รวมอยู่ในการสำรองข้อมูลอัตโนมัติ
ใน Android API ระดับ 20 และเก่ากว่า ระบบจะดาวน์โหลดโมเดลไปยังไดเรกทอรี
ตั้งชื่อว่า com.google.firebase.ml.custom.models
ในแอปส่วนตัว
ที่จัดเก็บข้อมูลภายใน หากคุณเปิดใช้การสำรองไฟล์โดยใช้ BackupAgent
คุณอาจเลือกที่จะยกเว้นไดเรกทอรีนี้