Android'de özel bir TensorFlow Lite modeli kullanma

Uygulamanız özel TensorFlow Lite modelleri kullanıyorsa modellerinizi dağıtmak için Firebase ML'yi kullanabilirsiniz. Modelleri Firebase ile dağıtarak uygulamanızın ilk indirme boyutunu azaltabilir ve uygulamanızın yeni bir sürümünü yayınlamadan uygulamanızın makine öğrenimi modellerini güncelleyebilirsiniz. Uzaktan Yapılandırma ve A/B Testi ile farklı modelleri farklı kullanıcı gruplarına dinamik olarak sunabilirsiniz.

TensorFlow Lite modelleri

TensorFlow Lite modelleri, mobil cihazlarda çalışacak şekilde optimize edilmiş ML modelleridir. TensorFlow Lite modelini edinmek için:

Sen başlamadan önce

  1. Henüz yapmadıysanız Android projenize Firebase'i ekleyin .
  2. Modülünüzde (uygulama düzeyinde) Gradle dosyanızda (genellikle <project>/<app-module>/build.gradle.kts veya <project>/<app-module>/build.gradle ), Firebase ML'nin bağımlılığını ekleyin Android için model indirici kütüphanesi. Kitaplık sürümlerini kontrol etmek için Firebase Android BoM'yi kullanmanızı öneririz.

    Ayrıca Firebase ML model indiricisini kurmanın bir parçası olarak uygulamanıza TensorFlow Lite SDK'yı eklemeniz gerekir.

    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'yi kullandığınızda uygulamanız her zaman Firebase Android kitaplıklarının uyumlu sürümlerini kullanır.

    (Alternatif) BoM'yi kullanmadan Firebase kitaplığı bağımlılıklarını ekleyin

    Firebase BoM'yi kullanmamayı tercih ederseniz her Firebase kitaplığı sürümünü bağımlılık satırında belirtmeniz gerekir.

    Uygulamanızda birden fazla Firebase kitaplığı kullanıyorsanız kitaplık sürümlerini yönetmek için tüm sürümlerin uyumlu olmasını sağlayan BoM'yi kullanmanızı önemle tavsiye ettiğimizi unutmayın.

    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")
    }
    Kotlin'e özgü bir kütüphane modülü mü arıyorsunuz? Ekim 2023'ten itibaren (Firebase BoM 32.5.0) hem Kotlin hem de Java geliştiricileri ana kütüphane modülüne güvenebilecekler (ayrıntılar için bu girişimle ilgili SSS'ye bakın).
  3. Uygulamanızın manifest dosyasında İNTERNET izninin gerekli olduğunu belirtin:
    <uses-permission android:name="android.permission.INTERNET" />

1. Modelinizi dağıtın

Firebase konsolunu veya Firebase Admin Python ve Node.js SDK'larını kullanarak özel TensorFlow modellerinizi dağıtın. Bkz. Özel modelleri dağıtma ve yönetme .

Firebase projenize özel bir model ekledikten sonra, belirttiğiniz adı kullanarak uygulamalarınızda modele referans verebilirsiniz. İstediğiniz zaman yeni bir TensorFlow Lite modelini dağıtabilir ve getModel() öğesini çağırarak yeni modeli kullanıcıların cihazlarına indirebilirsiniz (aşağıya bakın).

2. Modeli cihaza indirin ve TensorFlow Lite yorumlayıcısını başlatın

TensorFlow Lite modelinizi uygulamanızda kullanmak için öncelikle Firebase ML SDK'yı kullanarak modelin en son sürümünü cihaza indirin. Ardından modelle bir TensorFlow Lite yorumlayıcısını başlatın.

Model indirmeyi başlatmak için, modeli yüklediğinizde modele atadığınız adı, her zaman en son modeli indirmek isteyip istemediğinizi ve hangi koşullar altında indirmeye izin vermek istediğinizi belirterek, model indiricisinin getModel() yöntemini çağırın.

Üç indirme davranışından birini seçebilirsiniz:

İndirme türü Tanım
LOCAL_MODEL Yerel modeli cihazdan alın. Yerel model mevcut değilse, bu LATEST_MODEL gibi davranır. Model güncellemelerini kontrol etmekle ilgilenmiyorsanız bu indirme türünü kullanın. Örneğin, model adlarını almak için Remote Config'i kullanıyorsunuz ve modelleri her zaman yeni adlar altında yüklüyorsunuz (önerilen).
LOCAL_MODEL_UPDATE_IN_BACKGROUND Yerel modeli cihazdan alın ve modeli arka planda güncellemeye başlayın. Yerel model mevcut değilse, bu LATEST_MODEL gibi davranır.
SON MODEL En son modeli alın. Yerel model en son sürümse yerel modeli döndürür. Aksi takdirde en son modeli indirin. Bu davranış, en son sürüm indirilene kadar engellenecektir (önerilmez). Bu davranışı yalnızca en son sürüme açıkça ihtiyaç duyduğunuz durumlarda kullanın.

Modelin indirildiğini onaylayana kadar modelle ilgili işlevleri (örneğin kullanıcı arayüzünüzün grileştirilmesi veya bir kısmının gizlenmesi) devre dışı bırakmalısınız.

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

Çoğu uygulama, indirme görevini kendi başlatma kodunda başlatır, ancak bunu, modeli kullanmanız gerekmeden önce herhangi bir noktada yapabilirsiniz.

3. Giriş verileri üzerinde çıkarım yapın

Modelinizin giriş ve çıkış şekillerini alın

TensorFlow Lite model yorumlayıcısı girdi olarak alır ve çıktı olarak bir veya daha fazla çok boyutlu dizi üretir. Bu diziler byte , int , long veya float değerlerini içerir. Bir modele veri aktarmadan veya sonucunu kullanmadan önce, modelinizin kullandığı dizilerin sayısını ve boyutlarını ("şekli") bilmeniz gerekir.

Modeli kendiniz oluşturduysanız veya modelin giriş ve çıkış formatı belgelenmişse bu bilgiye zaten sahip olabilirsiniz. Modelinizin giriş ve çıkışının şeklini ve veri türünü bilmiyorsanız modelinizi incelemek için TensorFlow Lite yorumlayıcısını kullanabilirsiniz. Örneğin:

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

Örnek çıktı:

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

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

Tercümanı çalıştırın

Modelinizin giriş ve çıkış formatını belirledikten sonra giriş verilerinizi alın ve modeliniz için doğru şekle sahip bir giriş elde etmek için veriler üzerinde gerekli tüm dönüşümleri gerçekleştirin.

Örneğin, [1 224 224 3] kayan nokta değerlerinin giriş şekline sahip bir görüntü sınıflandırma modeliniz varsa, aşağıdaki örnekte gösterildiği gibi bir Bitmap nesnesinden bir giriş ByteBuffer oluşturabilirsiniz:

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

Ardından, modelin çıkışını içerecek kadar büyük bir ByteBuffer ayırın ve giriş arabelleğini ve çıkış arabelleğini TensorFlow Lite yorumlayıcısının run() yöntemine aktarın. Örneğin, [1 1000] kayan nokta değerlerinin çıktı şekli için:

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

Çıktıyı nasıl kullanacağınız kullandığınız modele bağlıdır.

Örneğin, sınıflandırma yapıyorsanız bir sonraki adım olarak sonucun indekslerini temsil ettikleri etiketlerle eşleştirebilirsiniz:

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

Ek: Model güvenliği

TensorFlow Lite modellerinizi Firebase ML'de nasıl kullanılabilir hale getirdiğinizden bağımsız olarak, Firebase ML bunları yerel depolamada standart serileştirilmiş protobuf formatında saklar.

Teorik olarak bu, herkesin modelinizi kopyalayabileceği anlamına gelir. Ancak uygulamada çoğu model, uygulamaya o kadar özeldir ve optimizasyonlar nedeniyle karartılmıştır ki, risk, rakiplerinizin kodunuzu parçalara ayırıp yeniden kullanması ile benzerdir. Ancak uygulamanızda özel bir model kullanmadan önce bu riskin farkında olmalısınız.

Android API düzeyi 21 (Lollipop) ve daha yeni sürümlerde model, otomatik yedeklemenin dışında bırakılan bir dizine indirilir.

Android API düzeyi 20 ve daha eski sürümlerde model, uygulamaya özel dahili depolama alanındaki com.google.firebase.ml.custom.models adlı dizine indirilir. BackupAgent kullanarak dosya yedeklemeyi etkinleştirdiyseniz bu dizini hariç tutmayı seçebilirsiniz.