Google cam kết thúc đẩy công bằng chủng tộc cho Cộng đồng người da đen. Xem cách thực hiện.

Sử dụng mô hình TensorFlow Lite để suy luận với ML Kit trên Android

Bạn có thể sử dụng ML Kit để thực hiện trên thiết bị kết luận với một TensorFlow Lite mô hình.

API này yêu cầu Android SDK cấp 16 (Jelly Bean) hoặc mới hơn.

Trước khi bắt đầu

  1. Nếu bạn chưa sẵn sàng, thêm căn cứ hỏa lực cho dự án Android của bạn .
  2. Thêm sự phụ thuộc cho các thư viện ML Kit Android để mô-đun của bạn (ứng dụng cấp) tập tin Gradle (thường là 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'
    }
    
  3. Chuyển đổi mô hình TensorFlow bạn muốn sử dụng sang định dạng TensorFlow Lite. Xem Toco: TensorFlow Lite Tối ưu hóa Chuyển đổi .

Lưu trữ hoặc nhóm mô hình của bạn

Trước khi có thể sử dụng mô hình TensorFlow Lite để suy luận trong ứng dụng của mình, bạn phải cung cấp mô hình đó cho ML Kit. ML Kit có thể sử dụng các mô hình TensorFlow Lite được lưu trữ từ xa bằng Firebase, đi kèm với tệp nhị phân ứng dụng hoặc cả hai.

Bằng cách lưu trữ mô hình trên Firebase, bạn có thể cập nhật mô hình mà không cần phát hành phiên bản ứng dụng mới và bạn có thể sử dụng Cấu hình từ xa và Thử nghiệm A / B để phân phối động các mô hình khác nhau cho các nhóm người dùng khác nhau.

Nếu bạn chọn chỉ cung cấp mô hình bằng cách lưu trữ nó với Firebase và không gói nó với ứng dụng của mình, bạn có thể giảm kích thước tải xuống ban đầu của ứng dụng. Tuy nhiên, hãy nhớ rằng nếu mô hình không được đi kèm với ứng dụng của bạn, thì mọi chức năng liên quan đến mô hình sẽ không khả dụng cho đến khi ứng dụng của bạn tải xuống mô hình lần đầu tiên.

Bằng cách kết hợp mô hình với ứng dụng của bạn, bạn có thể đảm bảo các tính năng ML của ứng dụng vẫn hoạt động khi mô hình được lưu trữ trên Firebase không khả dụng.

Lưu trữ các mô hình trên Firebase

Để lưu trữ mô hình TensorFlow Lite của bạn trên Firebase:

  1. Trong phần ML Kit của căn cứ hỏa lực console , nhấp vào tab Custom.
  2. Nhấn Add mô hình tùy chỉnh (hoặc Thêm một mô hình khác).
  3. Chỉ định tên sẽ được sử dụng để xác định mô hình của bạn trong dự án căn cứ hỏa lực của bạn, sau đó tải lên các mô hình tập tin TensorFlow Lite (thường kết thúc bằng .tflite hoặc .lite ).
  4. Trong manifest, tuyên bố rằng sự cho phép INTERNET được yêu cầu của ứng dụng của bạn:
    <uses-permission android:name="android.permission.INTERNET" />
    

Sau khi thêm mô hình tùy chỉnh vào dự án Firebase, bạn có thể tham chiếu mô hình trong ứng dụng của mình bằng tên bạn đã chỉ định. Bất kỳ lúc nào, bạn cũng có thể tải lên mô hình TensorFlow Lite mới và ứng dụng của bạn sẽ tải xuống mô hình mới và bắt đầu sử dụng khi ứng dụng khởi động lại lần sau. Bạn có thể xác định các điều kiện thiết bị cần thiết để ứng dụng của bạn cố gắng cập nhật mô hình (xem bên dưới).

Gói các mô hình với một ứng dụng

Để bó mô hình TensorFlow Lite của bạn với ứng dụng của bạn, sao chép các tập tin mô hình (thường kết thúc bằng .tflite hoặc .lite ) để ứng dụng của bạn assets/ thư mục. (Bạn có thể cần phải tạo thư mục đầu tiên bởi kích chuột phải vào app/ thư mục, sau đó nhấp vào New> Folder> Tài sản Folder.)

Sau đó, thêm dòng sau vào ứng dụng của bạn build.gradle tập tin để đảm bảo Gradle không nén các mô hình khi xây dựng các ứng dụng:

android {

    // ...

    aaptOptions {
        noCompress "tflite"  // Your model's file extension: "tflite", "lite", etc.
    }
}

Tệp mô hình sẽ được bao gồm trong gói ứng dụng và có sẵn cho ML Kit dưới dạng nội dung thô.

Tải mô hình

Để sử dụng mô hình TensorFlow Lite trong ứng dụng của bạn, trước tiên hãy định cấu hình ML Kit với các vị trí mà mô hình của bạn có sẵn: từ xa bằng Firebase, trong bộ nhớ cục bộ hoặc cả hai. Nếu bạn chỉ định cả mô hình cục bộ và từ xa, bạn có thể sử dụng mô hình từ xa nếu nó có sẵn và quay lại mô hình được lưu trữ cục bộ nếu mô hình từ xa không khả dụng.

Định cấu hình mô hình được lưu trữ trên Firebase

Nếu bạn tổ chức mô hình của bạn với căn cứ hỏa lực, tạo ra một FirebaseCustomRemoteModel đối tượng, ghi tên bạn đã gán mô hình khi bạn đã tải lên nó:

Java

FirebaseCustomRemoteModel remoteModel =
        new FirebaseCustomRemoteModel.Builder("your_model").build();

Kotlin + KTX

val remoteModel = FirebaseCustomRemoteModel.Builder("your_model").build()

Sau đó, bắt đầu tác vụ tải xuống mô hình, chỉ định các điều kiện mà bạn muốn cho phép tải xuống. Nếu mô hình không có trên thiết bị hoặc nếu có phiên bản mới hơn của mô hình, tác vụ sẽ tải xuống mô hình một cách không đồng bộ từ 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.
    }

Nhiều ứng dụng bắt đầu tác vụ tải xuống trong mã khởi tạo của chúng, nhưng bạn có thể làm như vậy bất kỳ lúc nào trước khi cần sử dụng mô hình.

Định cấu hình một mô hình cục bộ

Nếu bạn đóng gói các mô hình với ứng dụng của bạn, tạo ra một FirebaseCustomLocalModel đối tượng, xác định tên tập tin của mô hình TensorFlow Lite:

Java

FirebaseCustomLocalModel localModel = new FirebaseCustomLocalModel.Builder()
        .setAssetFilePath("your_model.tflite")
        .build();

Kotlin + KTX

val localModel = FirebaseCustomLocalModel.Builder()
    .setAssetFilePath("your_model.tflite")
    .build()

Tạo trình thông dịch từ mô hình của bạn

Sau khi bạn cấu hình nguồn mô hình của bạn, tạo ra một FirebaseModelInterpreter đối tượng từ một trong số họ.

Nếu bạn chỉ có một mô hình địa phương kèm, chỉ cần tạo một thông dịch viên từ bạn FirebaseCustomLocalModel đối tượng:

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)

Nếu bạn có một mô hình được lưu trữ từ xa, bạn sẽ phải kiểm tra xem nó đã được tải xuống chưa trước khi chạy nó. Bạn có thể kiểm tra tình trạng của công việc mô hình tải bằng trình quản lý mô hình của isModelDownloaded() phương pháp.

Mặc dù bạn chỉ phải xác nhận điều này trước khi chạy trình thông dịch, nhưng nếu bạn có cả mô hình được lưu trữ từ xa và mô hình được gói cục bộ, bạn có thể thực hiện kiểm tra này khi khởi tạo trình thông dịch mô hình: tạo trình thông dịch từ mô hình từ xa nếu nó đã được tải xuống và từ mô hình cục bộ nếu không.

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)
}

Nếu bạn chỉ có một mô hình được lưu trữ từ xa, bạn nên tắt chức năng liên quan đến mô hình — ví dụ: chuyển sang màu xám hoặc ẩn một phần của giao diện người dùng — cho đến khi bạn xác nhận rằng mô hình đã được tải xuống. Bạn có thể làm như vậy bằng cách gắn một người biết lắng nghe để người quản lý mô hình của download() phương pháp:

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.
    }

Chỉ định đầu vào và đầu ra của mô hình

Tiếp theo, cấu hình các định dạng đầu vào và đầu ra của trình thông dịch mô hình.

Mô hình TensorFlow Lite nhận làm đầu vào và tạo ra dưới dạng đầu ra một hoặc nhiều mảng đa chiều. Những mảng chứa một trong hai byte , int , long , hoặc float giá trị. Bạn phải định cấu hình ML Kit với số lượng và kích thước ("hình dạng") của các mảng mà mô hình của bạn sử dụng.

Nếu bạn không biết hình dạng và kiểu dữ liệu của đầu vào và đầu ra của mô hình, bạn có thể sử dụng trình thông dịch Python TensorFlow Lite để kiểm tra mô hình của mình. Ví dụ:

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'>

Sau khi bạn đã xác định định dạng của đầu vào và đầu ra của mô hình của bạn, bạn có thể cấu hình mô hình phiên dịch của ứng dụng của bạn bằng cách tạo ra một FirebaseModelInputOutputOptions đối tượng.

Ví dụ, một mô hình phân loại hình ảnh dấu chấm động có thể mất như là đầu vào một N mảng x224x224x3 của float giá trị, đại diện cho một loạt N 224x224 ba kênh (RGB) hình ảnh, và các sản phẩm như đầu ra một danh sách 1000 float giá trị, mỗi đại diện cho xác suất hình ảnh là thành viên của một trong 1000 danh mục mà mô hình dự đoán.

Đối với một mô hình như vậy, bạn sẽ định cấu hình đầu vào và đầu ra của trình thông dịch mô hình như hình dưới đây:

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()

Thực hiện suy luận trên dữ liệu đầu vào

Cuối cùng, để thực hiện suy luận bằng cách sử dụng mô hình, hãy lấy dữ liệu đầu vào của bạn và thực hiện bất kỳ phép biến đổi nào trên dữ liệu cần thiết để có được mảng đầu vào có hình dạng phù hợp với mô hình của bạn.

Ví dụ, nếu bạn có một mô hình phân loại hình ảnh với một hình dạng đầu vào của [1 224 224 3] giá trị dấu chấm động, bạn có thể tạo một mảng đầu vào từ một Bitmap đối tượng như trong ví dụ sau:

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
    }
}

Sau đó, tạo một FirebaseModelInputs đối tượng với dữ liệu đầu vào của bạn, và vượt qua nó và của mô hình đầu vào và đầu ra đặc điểm kỹ thuật cho thông dịch viên người mẫu 's run phương pháp:

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
            // ...
        }

Nếu cuộc gọi thành công, bạn có thể nhận được đầu ra bằng cách gọi getOutput() phương pháp của đối tượng đó được truyền cho người nghe thành công. Ví dụ:

Java

float[][] output = result.getOutput(0);
float[] probabilities = output[0];

Kotlin + KTX

val output = result.getOutput<Array<FloatArray>>(0)
val probabilities = output[0]

Cách bạn sử dụng đầu ra phụ thuộc vào kiểu máy bạn đang sử dụng.

Ví dụ: nếu bạn đang thực hiện phân loại, trong bước tiếp theo, bạn có thể ánh xạ các chỉ mục của kết quả với các nhãn mà chúng đại diện:

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]))
}

Phụ lục: Bảo mật mô hình

Bất kể bạn làm thế nào để cung cấp các mô hình TensorFlow Lite của mình cho ML Kit, ML Kit lưu trữ chúng ở định dạng protobuf tuần tự tiêu 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, trên thực tế, hầu hết các mô hình đều dành riêng cho ứng dụng và bị xáo trộn bởi các tối ưu hóa đến mức rủi ro tương tự như rủi ro khi đối thủ cạnh tranh tháo gỡ và sử dụng lại mã của bạn. Tuy nhiên, bạn nên biết rủi ro này trước khi sử dụng mô hình tùy chỉnh trong ứng dụng của mình.

Trên Android API mức 21 (Lollipop) và mới hơn, mô hình sẽ được tải về vào một thư mục được loại trừ từ bản sao lưu tự động .

Trên Android API level 20 trở lên, mô hình được tải về vào một thư mục có tên com.google.firebase.ml.custom.models ở bộ nhớ trong app-private. Nếu bạn kích hoạt tập tin sao lưu sử dụng BackupAgent , bạn có thể chọn để loại trừ thư mục này.