Android'de ML Kit ile çıkarım için TensorFlow Lite modeli kullanma

TensorFlow Lite modeliyle cihaz üzerinde çıkarım yapmak için ML Kit'i kullanabilirsiniz.

Bu API, Android SDK düzey 16 (Jelly Bean) veya daha yeni bir sürüm gerektirir.

Başlamadan önce

  1. Henüz yapmadıysanız Firebase'i Android projenize ekleyin.
  2. Modül (uygulama düzeyinde) Gradle dosyanıza (genellikle app/build.gradle) ML Kit Android kitaplıkları için bağımlılıkları ekleyin:
    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. Kullanmak istediğiniz TensorFlow modelini TensorFlow Lite biçimine dönüştürün. Bkz. TOCO: TensorFlow Lite Optimize Converter.

Modelinizi barındırın veya paketleyin

Uygulamanızda çıkarım için TensorFlow Lite modelini kullanabilmeniz için öncelikle bu modeli ML Kit'te kullanılabilir hale getirmeniz gerekir. ML Kit, Firebase ile uzaktan barındırılan, uygulama ikili programıyla paket halinde sunulan veya her ikisini birden kullanan TensorFlow Lite modellerini kullanabilir.

Firebase'de bir model barındırarak yeni uygulama sürümü yayınlamadan modeli güncelleyebilirsiniz. Ayrıca farklı kullanıcı gruplarına dinamik olarak farklı modeller sunmak için Remote Config ve A/B Testi'ni kullanabilirsiniz.

Modeli yalnızca Firebase'de barındırarak sağlamayı ve uygulamanızla paketlemeyi tercih ederseniz uygulamanızın ilk indirme boyutunu küçültebilirsiniz. Bununla birlikte, modelin uygulamanızla paket halinde olmaması durumunda uygulamanız modeli ilk kez indirene kadar modelle ilgili hiçbir işlevin kullanılamayacağını unutmayın.

Modelinizi uygulamanızla paket haline getirerek Firebase tarafından barındırılan model kullanılamadığında uygulamanızın makine öğrenimi özelliklerinin çalışmaya devam etmesini sağlayabilirsiniz.

Firebase'de modelleri barındırma

TensorFlow Lite modelinizi Firebase'de barındırmak için:

  1. Firebase konsolunun ML Kit bölümünde Custom sekmesini tıklayın.
  2. Özel model ekle (veya Başka bir model ekle) seçeneğini tıklayın.
  3. Firebase projenizde modelinizi tanımlamak için kullanılacak bir ad belirtin ve ardından TensorFlow Lite model dosyasını (genellikle .tflite veya .lite ile biter) yükleyin.
  4. Uygulamanızın manifest dosyasında, İNTERNET izninin gerekli olduğunu beyan edin:
    <uses-permission android:name="android.permission.INTERNET" />
    

Firebase projenize özel bir model ekledikten sonra, belirttiğiniz adı kullanarak uygulamalarınızda bu modele referans verebilirsiniz. İstediğiniz zaman yeni bir TensorFlow Lite modeli yükleyebilirsiniz. Uygulamanız yeni modeli indirir ve uygulama yeniden başlatıldığında bu modeli kullanmaya başlar. Uygulamanızın modeli güncellemeyi denemesi için gereken cihaz koşullarını tanımlayabilirsiniz (aşağıya bakın).

Modelleri uygulama ile paketleme

TensorFlow Lite modelinizi uygulamanızla paket halinde sunmak için model dosyasını (genellikle .tflite veya .lite ile biter) uygulamanızın assets/ klasörüne kopyalayın. (Önce app/ klasörünü sağ tıklayıp Yeni > Klasör > Öğeler Klasörü'nü tıklayarak klasörü oluşturmanız gerekebilir.)

Ardından, Gradle'ın uygulamayı oluştururken modelleri sıkıştırmadığından emin olmak için uygulamanızın build.gradle dosyasına aşağıdakini ekleyin:

android {

    // ...

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

Model dosyası uygulama paketine dahil edilir ve ham öğe olarak ML Kit tarafından kullanılabilir.

Modeli yükleme

TensorFlow Lite modelinizi uygulamanızda kullanmak için öncelikle ML Kit'i modelinizin kullanılabildiği yerlerle yapılandırın: Firebase'i uzaktan kullanma, yerel depolama alanı veya her ikisi. Hem yerel hem de uzak model belirtirseniz kullanılabiliyorsa uzak modeli kullanabilir ve uzak model mevcut değilse yerel olarak depolanan modele geri dönebilirsiniz.

Firebase tarafından barındırılan bir modeli yapılandırma

Modelinizi Firebase'de barındırıyorsanız modeli yüklerken atadığınız adı belirterek bir FirebaseCustomRemoteModel nesnesi oluşturun:

Java

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

Kotlin+KTX

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

Ardından, indirmeye izin vermek istediğiniz koşulları belirterek model indirme görevini başlatın. Model cihazda yoksa veya modelin daha yeni bir sürümü varsa görev, modeli Firebase'den eşzamansız olarak indirir:

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

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

Yerel model yapılandırma

Modeli uygulamanızla paket haline getirdiyseniz TensorFlow Lite modelinin dosya adını belirterek bir FirebaseCustomLocalModel nesnesi oluşturun:

Java

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

Kotlin+KTX

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

Modelinizden çevirmen oluşturma

Model kaynaklarınızı yapılandırdıktan sonra, bu kaynakların birinden FirebaseModelInterpreter nesnesi oluşturun.

Yalnızca yerel olarak paketlenmiş bir modeliniz varsa FirebaseCustomLocalModel nesnenizden bir çevirmen oluşturmanız yeterlidir:

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)

Uzaktan barındırılan bir modeliniz varsa çalıştırmadan önce modelin indirilip indirilmediğini kontrol etmeniz gerekir. Model indirme görevinin durumunu, model yöneticisinin isModelDownloaded() yöntemini kullanarak kontrol edebilirsiniz.

Çevirmeni çalıştırmadan önce bunu onaylamanız yeterlidir. Hem uzaktan barındırılan hem de yerel olarak paketlenmiş bir modeliniz varsa model yorumlayıcısını örneklendirirken şu kontrolü gerçekleştirmek mantıklı olabilir: İndirildiyse uzak modelden, aksi takdirde yerel modelden yorumlayıcı oluşturun.

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

Yalnızca uzaktan barındırılan bir modeliniz varsa modelin indirildiğini onaylayana kadar modelle ilgili işlevleri (ör. kullanıcı arayüzünün bir kısmını devre dışı bırakma veya gizleme) devre dışı bırakmanız gerekir. Bunu, model yöneticisinin download() yöntemine bir işleyici ekleyerek yapabilirsiniz:

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

Modelin giriş ve çıkışını belirtin

Ardından, model yorumlayıcının giriş ve çıkış biçimlerini yapılandırın.

TensorFlow Lite modeli girdi olarak alır ve bir veya daha fazla çok boyutlu dizi çıktısı olarak üretir. Bu diziler byte, int, long veya float değerlerini içerir. ML Kit'i, modelinizin kullandığı dizilerin sayısı ve boyutlarıyla ("şekli") yapılandırmanız gerekir.

Modelinizin giriş ve çıkışının şeklini ve veri türünü bilmiyorsanız modelinizi incelemek için TensorFlow Lite Python yorumlayıcısını kullanabilirsiniz. Örneğin:

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

Modelinizin giriş ve çıkışının biçimini belirledikten sonra FirebaseModelInputOutputOptions nesnesi oluşturarak uygulamanızın model yorumlayıcısını yapılandırabilirsiniz.

Örneğin, bir kayan nokta görüntü sınıflandırma modeli, bir N 224x224 üç kanallı (RGB) görüntü grubunu temsil eden Nx224x224x3 float değer dizisini girdi olarak alabilir ve her biri görüntünün modelin tahmin ettiği 1.000 kategoriden birinin üyesi olma olasılığını temsil eden 1.000 float değerinden oluşan bir liste çıktısı olarak üretilebilir.

Böyle bir model için model çevirmeninin giriş ve çıkışını aşağıda gösterildiği gibi yapılandırırsınız:

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

Giriş verilerinde çıkarım yap

Son olarak, modeli kullanarak çıkarım yapmak için giriş verilerinizi alın ve modeliniz için doğru şekilde bir giriş dizisi elde etmek amacıyla verilerde gerekli tüm dönüşümleri gerçekleştirin.

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

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

Ardından, giriş verilerinizle bir FirebaseModelInputs nesnesi oluşturun ve bu nesne ile birlikte modelin giriş ve çıkış özelliklerini model yorumlayıcının run yöntemine iletin:

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

Çağrı başarılı olursa başarılı işleyiciye iletilen nesnenin getOutput() yöntemini çağırarak sonucu alabilirsiniz. Örnek:

Java

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

Kotlin+KTX

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

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:

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

Ek: Model güvenliği

TensorFlow Lite modellerinizi ML Kit için nasıl kullanılabilir hale getirirseniz sunun, ML Kit 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.