Nếu ứng dụng của bạn sử dụng mô hình TensorFlow Lite tuỳ chỉnh, bạn có thể sử dụng Firebase ML để triển khai mô hình. Bằng cách triển khai các mô hình bằng Firebase, bạn có thể giảm kích thước tải xuống ban đầu của ứng dụng và cập nhật các mô hình học máy của ứng dụng mà không cần phát hành phiên bản mới của ứng dụng. Ngoài ra, với Remote Config và A/B Testing, bạn có thể linh hoạt phân phát các mô hình khác nhau cho các nhóm người dùng khác nhau.
Mô hình TensorFlow Lite
Mô hình TensorFlow Lite là các mô hình học máy được tối ưu hoá để chạy trên thiết bị di động. Cách tải mô hình TensorFlow Lite:
- Sử dụng mô hình tạo sẵn, chẳng hạn như một trong các mô hình TensorFlow Lite chính thức.
- Chuyển đổi mô hình TensorFlow, mô hình Keras hoặc hàm cụ thể sang TensorFlow Lite.
Trước khi bắt đầu
- Nếu bạn chưa thực hiện, hãy thêm Firebase vào dự án Android.
-
Trong tệp Gradle (cấp ứng dụng) của mô-đun (thường là
<project>/<app-module>/build.gradle.kts
hoặc<project>/<app-module>/build.gradle
), hãy thêm phần phụ thuộc cho thư viện trình tải mô hình Firebase ML xuống cho Android. Bạn nên sử dụng Firebase Android BoM để kiểm soát việc tạo phiên bản thư viện.Ngoài ra, trong quá trình thiết lập trình tải mô hình Firebase ML, bạn cần thêm SDK TensorFlow Lite vào ứng dụng.
dependencies { // Import the BoM for the Firebase platform implementation(platform("com.google.firebase:firebase-bom:33.7.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") }Bằng cách sử dụng Firebase Android BoM, ứng dụng của bạn sẽ luôn sử dụng những phiên bản tương thích của thư viện Android trên Firebase.
(Phương án thay thế) Thêm phần phụ thuộc thư viện Firebase mà không sử dụng BoM
Nếu chọn không sử dụng Firebase BoM, bạn phải chỉ định từng phiên bản thư viện Firebase trong dòng phần phụ thuộc của thư viện đó.
Xin lưu ý rằng nếu bạn sử dụng nhiều thư viện Firebase trong ứng dụng, bạn nên sử dụng BoM để quản lý các phiên bản thư viện, nhằm đảm bảo rằng tất cả các phiên bản đều tương thích.
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") } - Trong tệp kê khai của ứng dụng, hãy khai báo rằng bạn cần có quyền truy cập INTERNET:
<uses-permission android:name="android.permission.INTERNET" />
1. Triển khai mô hình
Triển khai các mô hình TensorFlow tuỳ chỉnh bằng bảng điều khiển Firebase hoặc SDK Python và Node.js dành cho Quản trị viên Firebase. Xem phần Triển khai và quản lý mô hình tuỳ chỉnh.
Sau khi thêm mô hình tuỳ chỉnh vào dự án Firebase, bạn có thể tham chiếu mô hình đó trong ứng dụng bằng tên mà bạn đã chỉ định. Bất cứ lúc nào, bạn cũng có thể triển khai mô hình TensorFlow Lite mới và tải mô hình mới xuống thiết bị của người dùng bằng cách gọi getModel()
(xem bên dưới).
2. Tải mô hình xuống thiết bị và khởi chạy trình thông dịch TensorFlow Lite
Để sử dụng mô hình TensorFlow Lite trong ứng dụng, trước tiên, hãy sử dụng SDK Firebase ML để tải phiên bản mới nhất của mô hình xuống thiết bị. Sau đó, tạo bản sao của trình phiên dịch TensorFlow Lite bằng mô hình.Để bắt đầu tải mô hình xuống, hãy gọi phương thức getModel()
của trình tải mô hình xuống, chỉ định tên bạn đã chỉ định cho mô hình khi tải lên, liệu bạn có muốn luôn tải mô hình mới nhất xuống hay không và điều kiện mà bạn muốn cho phép tải xuống.
Bạn có thể chọn trong số 3 hành vi tải xuống sau:
Loại tệp tải xuống | Mô tả |
---|---|
LOCAL_MODEL | Lấy mô hình cục bộ từ thiết bị.
Nếu không có mô hình cục bộ nào, thì mô hình này sẽ hoạt động như LATEST_MODEL . Hãy sử dụng loại tải xuống này nếu bạn không quan tâm đến việc kiểm tra bản cập nhật mô hình. Ví dụ: bạn đang sử dụng Cấu hình từ xa để truy xuất tên mô hình và bạn luôn tải mô hình lên theo tên mới (nên dùng). |
LOCAL_MODEL_UPDATE_IN_BACKGROUND | Lấy mô hình cục bộ từ thiết bị và bắt đầu cập nhật mô hình ở chế độ nền.
Nếu không có mô hình cục bộ nào, thì mô hình này sẽ hoạt động như LATEST_MODEL . |
LATEST_MODEL | Tải mô hình mới nhất. Nếu mô hình cục bộ là phiên bản mới nhất, hãy trả về mô hình cục bộ. Nếu không, hãy tải mô hình mới nhất xuống. Hành vi này sẽ chặn cho đến khi bạn tải phiên bản mới nhất xuống (không nên thực hiện). Chỉ sử dụng hành vi này trong trường hợp bạn cần rõ ràng phiên bản mới nhất. |
Bạn nên tắt chức năng liên quan đến mô hình (ví dụ: làm mờ hoặc ẩn một phần giao diện người dùng) cho đến khi xác nhận rằng mô hình đã được tải xuống.
Kotlin
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);
}
}
});
Nhiều ứng dụng bắt đầu tác vụ tải xuống trong mã khởi chạy, nhưng bạn có thể làm như vậy bất cứ lúc nào trước khi cần sử dụng mô hình.
3. Thực hiện suy luận trên dữ liệu đầu vào
Nhận các hình dạng đầu vào và đầu ra của mô hình
Trình diễn giải mô hình TensorFlow Lite sẽ lấy một hoặc nhiều mảng nhiều chiều làm dữ liệu đầu vào và tạo ra dữ liệu đầu ra. Các mảng này chứa giá trị byte
, int
, long
hoặc float
. Trước khi có thể truyền dữ liệu đến một mô hình hoặc sử dụng kết quả của mô hình đó, bạn phải biết số lượng và kích thước ("hình dạng") của các mảng mà mô hình sử dụng.
Nếu tự tạo mô hình hoặc nếu định dạng đầu vào và đầu ra của mô hình được ghi lại, thì có thể bạn đã có thông tin này. Nếu không biết hình dạng và loại dữ liệu đầu vào và đầu ra của mô hình, bạn có thể sử dụng trình thông dịch TensorFlow Lite để kiểm tra mô hình. Ví dụ:
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']))
Kết quả mẫu:
1 input(s): [ 1 224 224 3] <class 'numpy.float32'> 1 output(s): [1 1000] <class 'numpy.float32'>
Chạy trình thông dịch
Sau khi xác định định dạng đầu vào và đầu ra của mô hình, hãy lấy dữ liệu đầu vào và thực hiện mọi phép biến đổi cần thiết trên dữ liệu để có được dữ liệu đầu vào có hình dạng phù hợp với mô hình.Ví dụ: nếu có một mô hình phân loại hình ảnh có hình dạng đầu vào là giá trị dấu phẩy động [1 224 224 3]
, bạn có thể tạo một ByteBuffer
đầu vào từ đối tượng Bitmap
như trong ví dụ sau:
Kotlin
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);
}
}
Sau đó, hãy phân bổ một ByteBuffer
đủ lớn để chứa đầu ra của mô hình và truyền bộ đệm đầu vào và bộ đệm đầu ra đến phương thức run()
của trình thông dịch TensorFlow Lite. Ví dụ: đối với hình dạng đầu ra là các giá trị dấu phẩy động [1 1000]
:
Kotlin
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);
Cách bạn sử dụng kết quả phụ thuộc vào mô hình bạn đang sử dụng.
Ví dụ: nếu đang thực hiện phân loại, ở bước tiếp theo, bạn có thể ánh xạ các chỉ mục của kết quả đến các nhãn mà chúng đại diện:
Kotlin
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?
}
Phụ lục: Bảo mật mô hình
Bất kể bạn cung cấp mô hình TensorFlow Lite cho Firebase ML theo cách nào, Firebase ML sẽ lưu trữ các mô hình đó ở định dạng protobuf chuyển đổi tuần tự chuẩn trong bộ nhớ cục bộ.
Về lý thuyết, điều này có nghĩa là bất kỳ ai cũng có thể sao chép mô hình của bạn. Tuy nhiên, trong thực tế, hầu hết các mô hình đều dành riêng cho ứng dụng và bị làm rối mã nguồn do các hoạt động tối ưu hoá, nên rủi ro cũng tương tự như khi đối thủ cạnh tranh tháo rời và sử dụng lại mã của bạn. Tuy nhiên, bạn nên lưu ý đến rủi ro này trước khi sử dụng mô hình tuỳ chỉnh trong ứng dụng.
Trên Android API cấp 21 (Lollipop) trở lên, mô hình được tải xuống một thư mục được loại trừ khỏi tính năng sao lưu tự động.
Trên Android API cấp 20 trở xuống, mô hình được tải xuống một thư mục có tên com.google.firebase.ml.custom.models
trong bộ nhớ trong riêng tư của ứng dụng. Nếu đã bật tính năng sao lưu tệp bằng BackupAgent
, bạn có thể chọn loại trừ thư mục này.