หากแอปของคุณใช้โมเดล TensorFlow Lite ที่กำหนดเอง คุณสามารถใช้ Firebase ML เพื่อปรับใช้โมเดลของคุณได้ เมื่อปรับใช้โมเดลกับ Firebase คุณจะลดขนาดการดาวน์โหลดเริ่มต้นของแอปและอัปเดตโมเดล ML ของแอปได้โดยไม่ต้องเปิดตัวแอปเวอร์ชันใหม่ และด้วยการกำหนดค่าระยะไกลและการทดสอบ A/B คุณสามารถให้บริการโมเดลต่างๆ แก่ผู้ใช้กลุ่มต่างๆ แบบไดนามิกได้
รุ่น TensorFlow Lite
รุ่น TensorFlow Lite คือรุ่น ML ที่ได้รับการปรับแต่งให้ทำงานบนอุปกรณ์เคลื่อนที่ วิธีรับโมเดล TensorFlow Lite:
- ใช้โมเดลที่สร้างไว้ล่วงหน้า เช่น หนึ่งใน โมเดล TensorFlow Lite อย่างเป็นทางการ
- แปลงโมเดล TensorFlow, โมเดล Keras หรือฟังก์ชันที่เป็นรูปธรรมเป็น TensorFlow Lite
ก่อนที่คุณจะเริ่ม
- หากคุณยังไม่ได้ เพิ่ม Firebase ในโครงการ Android ของคุณ
- ใน ไฟล์ Gradle ของโมดูล (ระดับแอป) (โดยปกติคือ
<project>/<app-module>/build.gradle.kts
หรือ<project>/<app-module>/build.gradle
) ให้เพิ่มการพึ่งพาสำหรับ 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:32.8.0")) // 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 เวอร์ชันที่เข้ากันได้เสมอ
กำลังมองหาโมดูลไลบรารีเฉพาะของ Kotlin อยู่ใช่ไหม? เริ่มตั้งแต่ เดือนตุลาคม 2023 (Firebase BoM 32.5.0) ทั้งนักพัฒนา Kotlin และ Java สามารถพึ่งพาโมดูลไลบรารีหลักได้ (สำหรับรายละเอียด โปรดดู คำถามที่พบบ่อยเกี่ยวกับโครงการริเริ่มนี้ )(ทางเลือก) เพิ่มการพึ่งพาไลบรารี Firebase โดยไม่ ใช้ BoM
หากคุณเลือกที่จะไม่ใช้ Firebase BoM คุณต้องระบุเวอร์ชันไลบรารี Firebase แต่ละเวอร์ชันในบรรทัดการขึ้นต่อกัน
โปรดทราบว่าหากคุณใช้ไลบรารี 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:24.2.3")
// Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0") } - ในรายการแอปของคุณ ให้ประกาศว่าต้องได้รับอนุญาตจากอินเทอร์เน็ต:
<uses-permission android:name="android.permission.INTERNET" />
1. ปรับใช้โมเดลของคุณ
ปรับใช้โมเดล TensorFlow ที่กำหนดเองของคุณโดยใช้คอนโซล Firebase หรือ Firebase Admin Python และ Node.js SDK ดู ปรับใช้และจัดการโมเดลแบบกำหนดเอง
หลังจากที่คุณเพิ่มโมเดลที่กำหนดเองลงในโปรเจ็กต์ Firebase แล้ว คุณจะอ้างอิงโมเดลในแอปได้โดยใช้ชื่อที่คุณระบุ คุณสามารถปรับใช้โมเดล TensorFlow Lite ใหม่และดาวน์โหลดโมเดลใหม่ลงในอุปกรณ์ของผู้ใช้ได้ทุกเมื่อโดยเรียก getModel()
(ดูด้านล่าง)
2. ดาวน์โหลดโมเดลลงในอุปกรณ์และเริ่มต้นล่าม TensorFlow Lite
หากต้องการใช้โมเดล TensorFlow Lite ในแอป ขั้นแรกให้ใช้ Firebase ML SDK เพื่อดาวน์โหลดเวอร์ชันล่าสุดของโมเดลลงในอุปกรณ์ จากนั้น สร้างอินสแตนซ์ของล่าม TensorFlow Lite ด้วยโมเดล หากต้องการเริ่มการดาวน์โหลดโมเดล ให้เรียกใช้เมธอด getModel()
ของผู้ดาวน์โหลดโมเดล โดยระบุชื่อที่คุณกำหนดให้กับโมเดลเมื่อคุณอัปโหลด ไม่ว่าคุณต้องการดาวน์โหลดโมเดลล่าสุดเสมอหรือไม่ และเงื่อนไขที่คุณต้องการอนุญาตให้ดาวน์โหลด
คุณสามารถเลือกลักษณะการดาวน์โหลดได้สามแบบ:
ประเภทการดาวน์โหลด | คำอธิบาย |
---|---|
LOCAL_MODEL | รับโมเดลท้องถิ่นจากอุปกรณ์ หากไม่มีรุ่นท้องถิ่น สิ่งนี้จะทำงานเหมือน LATEST_MODEL ใช้ประเภทการดาวน์โหลดนี้หากคุณไม่สนใจที่จะตรวจสอบการอัพเดตโมเดล ตัวอย่างเช่น คุณกำลังใช้การกำหนดค่าระยะไกลเพื่อเรียกชื่อโมเดล และคุณจะอัปโหลดโมเดลภายใต้ชื่อใหม่เสมอ (แนะนำ) |
LOCAL_MODEL_UPDATE_IN_BACKGROUND | รับโมเดลในเครื่องจากอุปกรณ์ และเริ่มอัปเดตโมเดลในเบื้องหลัง หากไม่มีรุ่นท้องถิ่น สิ่งนี้จะทำงานเหมือน LATEST_MODEL |
ล่าสุด_MODEL | รับรุ่นใหม่ล่าสุด หากโมเดลโลคัลเป็นเวอร์ชันล่าสุด ให้ส่งคืนโมเดลโลคัล มิฉะนั้น ให้ดาวน์โหลดเวอร์ชันล่าสุด ลักษณะการทำงานนี้จะบล็อกจนกว่าจะดาวน์โหลดเวอร์ชันล่าสุด (ไม่แนะนำ) ใช้ลักษณะการทำงานนี้เฉพาะในกรณีที่คุณต้องการเวอร์ชันล่าสุดอย่างชัดเจน |
คุณควรปิดการใช้งานฟังก์ชันที่เกี่ยวข้องกับโมเดล เช่น ทำให้เป็นสีเทาหรือซ่อนบางส่วนของ 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 เพื่อตรวจสอบโมเดลของคุณได้ ตัวอย่างเช่น:
หลาม
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
ที่มีขนาดใหญ่พอที่จะบรรจุเอาต์พุตของโมเดล และส่งบัฟเฟอร์อินพุตและบัฟเฟอร์เอาต์พุตไปยังเมธอด run()
ของล่าม TensorFlow Lite ตัวอย่างเช่น สำหรับรูปร่างเอาต์พุตของค่าจุดลอยตัว [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 จะจัดเก็บโมเดลเหล่านั้นในรูปแบบ protobuf ที่เป็นอนุกรมมาตรฐานในพื้นที่จัดเก็บในเครื่อง
ตามทฤษฎีแล้ว นี่หมายความว่าใครๆ ก็สามารถคัดลอกโมเดลของคุณได้ อย่างไรก็ตาม ในทางปฏิบัติ โมเดลส่วนใหญ่จะมีความเฉพาะเจาะจงกับแอปพลิเคชันมากและถูกทำให้สับสนด้วยการปรับให้เหมาะสมให้เหมาะสม ซึ่งมีความเสี่ยงใกล้เคียงกับความเสี่ยงที่คู่แข่งจะแยกส่วนและนำโค้ดของคุณกลับมาใช้ใหม่ อย่างไรก็ตาม คุณควรตระหนักถึงความเสี่ยงนี้ก่อนที่จะใช้โมเดลที่กำหนดเองในแอปของคุณ
บน Android API ระดับ 21 (Lollipop) และใหม่กว่า โมเดลจะถูกดาวน์โหลดไปยังไดเร็กทอรีที่ ไม่รวมอยู่ในการสำรองข้อมูลอัตโนมัติ
บน Android API ระดับ 20 และเก่ากว่า โมเดลจะถูกดาวน์โหลดไปยังไดเร็กทอรีชื่อ com.google.firebase.ml.custom.models
ในที่จัดเก็บข้อมูลภายในส่วนตัวของแอป หากคุณเปิดใช้งานการสำรองข้อมูลไฟล์โดยใช้ BackupAgent
คุณอาจเลือกที่จะยกเว้นไดเร็กทอรีนี้