Android'de özel TensorFlow Lite modeli kullanma

Uygulamanızda özel TensorFlow Lite modelleri kullanılıyorsa modellerinizi dağıtmak için Firebase ML'yi kullanabilirsiniz. Modelleri Firebase ile dağıtarak uygulamanızın yeni sürümünü yayınlamadan uygulamanızın ilk indirme boyutunu küçültebilir ve uygulamanızın makine öğrenimi modellerini güncelleyebilirsiniz. Ayrıca Remote Config ve A/B Testi ile farklı kullanıcı gruplarına dinamik olarak farklı modeller sunabilirsiniz.

TensorFlow Lite modelleri

TensorFlow Lite modelleri, mobil cihazlarda çalışacak şekilde optimize edilmiş makine öğrenimi modelleridir. TensorFlow Lite modeli edinmek için:

Başlamadan önce

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

    Ayrıca, Firebase ML model indirme aracını kurmanın bir parçası olarak, uygulamanıza TensorFlow Lite SDK'sını eklemeniz gerekir.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:33.1.2"))
    
        // 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 kullanıldığında uygulamanız Firebase Android kitaplıklarının her zaman uyumlu sürümlerini kullanır.

    (Alternatif) BoM'u kullanmadan Firebase kitaplığı bağımlılıklarını ekleme

    Firebase BoM'yi kullanmamayı seçerseniz 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 BoM kullanmanızı önemle tavsiye ederiz. Böylece tüm sürümlerin uyumlu olması sağlanır.

    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.0")
    // Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0")
    }
    Kotlin'e özel bir kitaplık modülü mü arıyorsunuz? Ekim 2023'ten (Firebase BoM 32.5.0) itibaren, hem Kotlin hem de Java geliştiricileri ana kitaplık modülüne bağlı olabilir (ayrıntılar için Bu girişimle ilgili SSS bölümüne bakın).
  3. Uygulamanızın manifest dosyasında, İNTERNET izninin gerekli olduğunu beyan edin:
    <uses-permission android:name="android.permission.INTERNET" />

1. Modelinizi dağıtma

Özel TensorFlow modellerinizi Firebase konsolunu ya da Firebase Yönetici Python ve Node.js SDK'larını kullanarak dağıtın. Özel modelleri dağıtma ve yönetme bölümünü inceleyin.

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

2. Modeli cihaza indirin ve TensorFlow Lite çevirmenini başlatın

Uygulamanızda TensorFlow Lite modelinizi kullanmak için öncelikle Firebase ML SDK'sını kullanarak modelin en son sürümünü cihaza indirin. Ardından, bu modelle bir TensorFlow Lite yorumlayıcısını örneklendirin.

Model indirme işlemini başlatmak için modeli indirirken atadığınız adı, her zaman en son modeli indirmek isteyip istemediğinizi ve indirmeye izin vermek istediğiniz koşulları belirterek modeli indiren kullanıcının getModel() yöntemini çağırın.

Üç indirme davranışı arasından seçim yapabilirsiniz:

İndirme türü Açıklama
YEREL_MODEL Cihazdan yerel modeli alın. Kullanılabilir yerel model yoksa bu LATEST_MODEL gibi davranır. Model güncellemelerini kontrol etmek istemiyorsanız bu indirme türünü kullanın. Örneğin, model adlarını almak için Remote Config'i kullanırsınız ve modelleri her zaman yeni adlarla yüklersiniz (önerilir).
LOCAL_MODEL_UPDATE_IN_BACKGROUND Yerel modeli cihazdan alıp arka planda güncellemeye başlayın. Kullanılabilir yerel model yoksa bu LATEST_MODEL gibi davranır.
SON_MODEL En son modeli edinin. Yerel model en yeni sürümse yerel modeli döndürür. Aksi takdirde, en son modeli indirin. Bu davranış, en son sürüm indirilinceye kadar engeller (önerilmez). Bu davranışı yalnızca açıkça en yeni sürüme ihtiyaç duyduğunuz durumlarda kullanın.

Modelin indirildiğini onaylayana kadar modelle ilgili işlevleri (örneğin, kullanıcı arayüzünüzün devre dışı bırakılması veya bir kısmını gizleme) devre dışı bırakmanız gerekir.

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

Birçok uygulama, indirme görevini başlangıç kodlarında başlatır ancak modeli kullanmadan önce istediğiniz zaman bunu yapabilirsiniz.

3. Giriş verilerinde çıkarım yap

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

TensorFlow Lite model yorumlayıcısı giriş olarak alır ve çıkış olarak bir veya daha fazla çok boyutlu dizi oluşturur. Bu diziler byte, int, long veya float değerlerini içerir. Bir modele veri iletmeden 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ış biçimi belgelendiyse bu bilgilere 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. Örnek:

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 çıkış:

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

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

Çevirmeni çalıştırma

Modelinizin giriş ve çıkışının biçimini belirledikten sonra giriş verilerinizi alın ve modeliniz için doğru şekilde girdi almak için gereken verilerde gerekli tüm dönüşümleri gerçekleştirin.

Örneğin, giriş şeklinde [1 224 224 3] kayan nokta değerine sahip bir resim sınıflandırma modeliniz varsa aşağıdaki örnekte gösterildiği gibi bir Bitmap nesnesinden ByteBuffer girişi 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ği ile çıkış arabelleğini TensorFlow Lite yorumlayıcısının run() yöntemine iletin. Örneğin, [1 1000] kayan nokta değerinden oluşan bir çı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);

Sonucu 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 sonuç dizinlerini temsil ettikleri etiketlerle eşleyebilirsiniz:

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'nin kullanımına sunma şeklinizden bağımsız olarak Firebase ML, bunları yerel depolama alanındaki standart serileştirilmiş protokol biçiminde depolar.

Teoride bu, herkesin modelinizi kopyalayabileceği anlamına gelir. Ancak pratikte çoğu model o kadar uygulamaya özgüdür ki optimizasyonlar tarafından anlaşılmaz hale gelir. Bu durum, rakiplerinizin kodunuzu söküp yeniden kullanmasına neden olan riske benzer. Bununla birlikte, uygulamanızda özel bir model kullanmadan önce bu riskin farkında olmanız gerekir.

Android API düzey 21 (Lollipop) ve daha yeni sürümlerde model, otomatik yedeklemeden hariç tutulan bir dizine indirilir.

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