Android पर मशीन लर्निंग किट की मदद से, TensorFlow Lite मॉडल का इस्तेमाल करके अनुमान लगाना

TensorFlow Lite मॉडल के साथ डिवाइस पर अनुमान लगाने के लिए, ML Kit का इस्तेमाल किया जा सकता है.

इस एपीआई के लिए, Android SDK का लेवल 16 (Jelly Bean) या इसके बाद का होना ज़रूरी है.

शुरू करने से पहले

  1. अगर आपने पहले से ही A/B टेस्टिंग नहीं बनाई है, तो अपने Android प्रोजेक्ट में Firebase जोड़ें.
  2. अपनी मॉड्यूल (ऐप्लिकेशन-लेवल) Gradle फ़ाइल (आम तौर पर app/build.gradle) में, ML Kit Android लाइब्रेरी के लिए डिपेंडेंसी जोड़ें:
    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. TensorFlow के उस मॉडल को TensorFlow Lite फ़ॉर्मैट में बदलें जिसका आपको इस्तेमाल करना है. देखें TOCO: TensorFlow Lite Optimizing Converter.

अपने मॉडल को होस्ट या बंडल करना

अपने ऐप्लिकेशन में अनुमान लगाने के लिए, TensorFlow Lite मॉडल का इस्तेमाल करने से पहले, आपको एमएल किट के लिए मॉडल उपलब्ध कराना होगा. ML Kit, Firebase का इस्तेमाल करके रिमोट तरीके से होस्ट किए गए TensorFlow Lite मॉडल का इस्तेमाल कर सकता है. इसके अलावा, यह ऐप्लिकेशन बाइनरी के साथ बंडल किए गए मॉडल या दोनों का इस्तेमाल कर सकता है.

Firebase पर मॉडल को होस्ट करके, ऐप्लिकेशन का नया वर्शन रिलीज़ किए बिना मॉडल को अपडेट किया जा सकता है. साथ ही, Remote Config और A/B Testing का इस्तेमाल करके, उपयोगकर्ताओं के अलग-अलग ग्रुप को डाइनैमिक तरीके से अलग-अलग मॉडल दिखाए जा सकते हैं.

अगर आपको सिर्फ़ Firebase पर मॉडल होस्ट करके उपलब्ध कराना है और उसे अपने ऐप्लिकेशन के साथ बंडल नहीं करना है, तो ऐप्लिकेशन के शुरुआती डाउनलोड का साइज़ कम किया जा सकता है. हालांकि, ध्यान रखें कि अगर मॉडल को आपके ऐप्लिकेशन के साथ बंडल नहीं किया जाता है, तो मॉडल से जुड़ी कोई भी सुविधा तब तक उपलब्ध नहीं होगी, जब तक आपका ऐप्लिकेशन पहली बार मॉडल डाउनलोड नहीं कर लेता.

अपने मॉडल को ऐप्लिकेशन के साथ बंडल करके, यह पक्का किया जा सकता है कि Firebase पर होस्ट किया गया मॉडल उपलब्ध न होने पर भी, आपके ऐप्लिकेशन की एमएल सुविधाएं काम करती रहें.

Firebase पर मॉडल होस्ट करना

अपने TensorFlow Lite मॉडल को Firebase पर होस्ट करने के लिए:

  1. Firebase कंसोल के ML Kit सेक्शन में, कस्टम टैब पर क्लिक करें.
  2. कस्टम मॉडल जोड़ें या कोई दूसरा मॉडल जोड़ें पर क्लिक करें.
  3. कोई ऐसा नाम डालें जिसका इस्तेमाल, आपके Firebase प्रोजेक्ट में मॉडल की पहचान करने के लिए किया जाएगा. इसके बाद, TensorFlow Lite मॉडल फ़ाइल अपलोड करें. आम तौर पर, यह फ़ाइल .tflite या .lite पर खत्म होती है.
  4. अपने ऐप्लिकेशन के मेनिफ़ेस्ट में यह एलान करें कि INTERNET की अनुमति ज़रूरी है:
    <uses-permission android:name="android.permission.INTERNET" />

अपने Firebase प्रोजेक्ट में कस्टम मॉडल जोड़ने के बाद, उसे अपने ऐप्लिकेशन में इस्तेमाल किया जा सकता है. इसके लिए, आपको वही नाम इस्तेमाल करना होगा जो आपने मॉडल को दिया था. आपके पास किसी भी समय, नया TensorFlow Lite मॉडल अपलोड करने का विकल्प होता है. ऐसा करने पर, आपका ऐप्लिकेशन नया मॉडल डाउनलोड कर लेगा. इसके बाद, जब ऐप्लिकेशन अगली बार रीस्टार्ट होगा, तब वह नए मॉडल का इस्तेमाल करना शुरू कर देगा. अपने ऐप्लिकेशन के लिए, डिवाइस से जुड़ी ज़रूरी शर्तें तय की जा सकती हैं. इन शर्तों के पूरा होने पर ही, ऐप्लिकेशन मॉडल को अपडेट करने की कोशिश करेगा. इसके बारे में यहां बताया गया है.

किसी ऐप्लिकेशन के साथ बंडल मॉडल

अपने ऐप्लिकेशन के साथ TensorFlow Lite मॉडल को बंडल करने के लिए, मॉडल फ़ाइल (आम तौर पर .tflite या .lite पर खत्म होने वाली) को अपने ऐप्लिकेशन के assets/ फ़ोल्डर में कॉपी करें. (आपको app/ फ़ोल्डर पर राइट क्लिक करके, पहले फ़ोल्डर बनाना पड़ सकता है. इसके बाद, नया > फ़ोल्डर > ऐसेट फ़ोल्डर पर क्लिक करें.)

इसके बाद, अपने ऐप्लिकेशन की build.gradle फ़ाइल में यह कोड जोड़ें, ताकि ऐप्लिकेशन बनाते समय Gradle, मॉडल को कंप्रेस न करे:

android {

    // ...

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

मॉडल फ़ाइल को ऐप्लिकेशन पैकेज में शामिल किया जाएगा. साथ ही, यह ML Kit के लिए रॉ ऐसेट के तौर पर उपलब्ध होगी.

मॉडल लोड करना

अपने ऐप्लिकेशन में TensorFlow Lite मॉडल का इस्तेमाल करने के लिए, पहले ML Kit को उन जगहों के हिसाब से कॉन्फ़िगर करें जहां आपका मॉडल उपलब्ध है: Firebase का इस्तेमाल करके रिमोट तरीके से, लोकल स्टोरेज में या दोनों में. लोकल और रिमोट, दोनों मॉडल तय करने पर, रिमोट मॉडल उपलब्ध होने पर उसका इस्तेमाल किया जा सकता है. अगर रिमोट मॉडल उपलब्ध नहीं है, तो लोकल मॉडल का इस्तेमाल किया जा सकता है.

Firebase होस्ट किए गए मॉडल को कॉन्फ़िगर करना

अगर आपने Firebase पर अपना मॉडल होस्ट किया है, तो FirebaseCustomRemoteModel ऑब्जेक्ट बनाएं. इसमें वह नाम डालें जो आपने मॉडल को अपलोड करते समय दिया था:

Java

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

Kotlin

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

इसके बाद, मॉडल डाउनलोड करने का टास्क शुरू करें. इसमें उन शर्तों के बारे में बताएं जिनके तहत आपको डाउनलोड करने की अनुमति देनी है. अगर मॉडल डिवाइस पर नहीं है या मॉडल का नया वर्शन उपलब्ध है, तो टास्क, 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

val conditions = FirebaseModelDownloadConditions.Builder()
    .requireWifi()
    .build()
FirebaseModelManager.getInstance().download(remoteModel, conditions)
    .addOnCompleteListener {
        // Success.
    }

कई ऐप्लिकेशन, डाउनलोड करने का टास्क अपने इनिशियलाइज़ेशन कोड में शुरू करते हैं. हालांकि, मॉडल का इस्तेमाल करने से पहले, किसी भी समय ऐसा किया जा सकता है.

लोकल मॉडल को कॉन्फ़िगर करना

अगर आपने मॉडल को अपने ऐप्लिकेशन के साथ बंडल किया है, तो TensorFlow Lite मॉडल का फ़ाइल नाम तय करके, एक FirebaseCustomLocalModel ऑब्जेक्ट बनाएं:

Java

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

Kotlin

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

अपने मॉडल से इंटरप्रेटर बनाना

मॉडल सोर्स कॉन्फ़िगर करने के बाद, उनमें से किसी एक से FirebaseModelInterpreter ऑब्जेक्ट बनाएं.

अगर आपके पास सिर्फ़ स्थानीय तौर पर बंडल किया गया मॉडल है, तो अपने FirebaseCustomLocalModel ऑब्जेक्ट से एक इंटरप्रेटर बनाएं:

Java

FirebaseModelInterpreter interpreter;
try {
    FirebaseModelInterpreterOptions options =
            new FirebaseModelInterpreterOptions.Builder(localModel).build();
    interpreter = FirebaseModelInterpreter.getInstance(options);
} catch (FirebaseMLException e) {
    // ...
}

Kotlin

val options = FirebaseModelInterpreterOptions.Builder(localModel).build()
val interpreter = FirebaseModelInterpreter.getInstance(options)

अगर आपके पास रिमोटली होस्ट किया गया मॉडल है, तो आपको यह देखना होगा कि उसे चलाने से पहले डाउनलोड किया गया है या नहीं. मॉडल मैनेजर के isModelDownloaded() तरीके का इस्तेमाल करके, मॉडल डाउनलोड करने के टास्क की स्थिति देखी जा सकती है.

हालांकि, इंटरप्रेटर को चलाने से पहले ही इसकी पुष्टि करनी होती है. अगर आपके पास रिमोटली होस्ट किया गया मॉडल और स्थानीय तौर पर बंडल किया गया मॉडल, दोनों हैं, तो मॉडल इंटरप्रेटर को इंस्टैंटिएट करते समय इस जांच को पूरा करना सही हो सकता है: अगर रिमोट मॉडल डाउनलोड किया गया है, तो उससे इंटरप्रेटर बनाएं. अगर ऐसा नहीं है, तो स्थानीय मॉडल से इंटरप्रेटर बनाएं.

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

FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
    .addOnSuccessListener { isDownloaded -> 
    val options =
        if (isDownloaded) {
            FirebaseModelInterpreterOptions.Builder(remoteModel).build()
        } else {
            FirebaseModelInterpreterOptions.Builder(localModel).build()
        }
    val interpreter = FirebaseModelInterpreter.getInstance(options)
}

अगर आपके पास सिर्फ़ रिमोटली होस्ट किया गया मॉडल है, तो आपको मॉडल से जुड़ी सुविधा बंद करनी चाहिए. उदाहरण के लिए, जब तक मॉडल डाउनलोड नहीं हो जाता, तब तक अपने यूज़र इंटरफ़ेस (यूआई) के कुछ हिस्से को धूसर कर दें या छिपा दें. इसके लिए, मॉडल मैनेजर के download() तरीके में लिसनर अटैच करें:

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

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

मॉडल के इनपुट और आउटपुट के बारे में बताना

इसके बाद, मॉडल इंटरप्रेटर के इनपुट और आउटपुट फ़ॉर्मैट कॉन्फ़िगर करें.

TensorFlow Lite मॉडल, इनपुट के तौर पर एक या उससे ज़्यादा मल्टीडाइमेंशनल ऐरे लेता है और आउटपुट के तौर पर भी एक या उससे ज़्यादा मल्टीडाइमेंशनल ऐरे देता है. इन ऐरे में byte, int, long या float वैल्यू होती हैं. आपको ML Kit को, आपके मॉडल में इस्तेमाल होने वाली सरणियों की संख्या और डाइमेंशन ("शेप") के साथ कॉन्फ़िगर करना होगा.

अगर आपको अपने मॉडल के इनपुट और आउटपुट के शेप और डेटा टाइप के बारे में नहीं पता है, तो अपने मॉडल की जांच करने के लिए, TensorFlow Lite Python इंटरप्रेटर का इस्तेमाल करें. उदाहरण के लिए:

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

अपने मॉडल के इनपुट और आउटपुट का फ़ॉर्मैट तय करने के बाद, FirebaseModelInputOutputOptions ऑब्जेक्ट बनाकर, अपने ऐप्लिकेशन के मॉडल इंटरप्रेटर को कॉन्फ़िगर किया जा सकता है.

उदाहरण के लिए, फ़्लोटिंग-पॉइंट इमेज क्लासिफ़िकेशन मॉडल, N वैल्यू के Nx224x224x3 ऐरे को इनपुट के तौर पर ले सकता है. यह N 224x224 तीन-चैनल (आरजीबी) इमेज के बैच को दिखाता है. इसके बाद, यह 1,000 float वैल्यू की सूची को आउटपुट के तौर पर जनरेट करता है. इनमें से हर वैल्यू, इस बात की संभावना को दिखाती है कि इमेज, मॉडल की अनुमानित 1,000 कैटगरी में से किसी एक कैटगरी का हिस्सा है.float

ऐसे मॉडल के लिए, मॉडल इंटरप्रेटर के इनपुट और आउटपुट को इस तरह कॉन्फ़िगर किया जाएगा:

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

val inputOutputOptions = FirebaseModelInputOutputOptions.Builder()
        .setInputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, 224, 224, 3))
        .setOutputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, 5))
        .build()

इनपुट डेटा पर अनुमान लगाना

आखिर में, मॉडल का इस्तेमाल करके अनुमान लगाने के लिए, अपना इनपुट डेटा पाएं. साथ ही, डेटा में ऐसे सभी ज़रूरी बदलाव करें जिनसे आपके मॉडल के लिए सही शेप का इनपुट ऐरे मिल सके.

उदाहरण के लिए, अगर आपके पास [1 224 224 3] फ़्लोटिंग-पॉइंट वैल्यू वाला इमेज क्लासिफ़िकेशन मॉडल है, तो Bitmap ऑब्जेक्ट से इनपुट ऐरे जनरेट किया जा सकता है. इसका उदाहरण यहां दिया गया है:

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

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

इसके बाद, अपने इनपुट डेटा के साथ एक FirebaseModelInputs ऑब्जेक्ट बनाएं. साथ ही, इसे और मॉडल के इनपुट और आउटपुट स्पेसिफ़िकेशन को मॉडल इंटरप्रेटर के run तरीके पर पास करें:

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

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

अगर कॉल पूरा हो जाता है, तो आपको आउटपुट मिल सकता है. इसके लिए, आपको उस ऑब्जेक्ट के getOutput() तरीके को कॉल करना होगा जिसे सफलता के बारे में बताने वाले लिसनर को पास किया गया है. उदाहरण के लिए:

Java

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

Kotlin

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

आउटपुट का इस्तेमाल कैसे किया जाए, यह इस्तेमाल किए जा रहे मॉडल पर निर्भर करता है.

उदाहरण के लिए, अगर आपको क्लासिफ़िकेशन करना है, तो अगले चरण के तौर पर, आपको नतीजे के इंडेक्स को उन लेबल पर मैप करना होगा जो उन्हें दिखाते हैं:

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

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

अपेंडिक्स: मॉडल की सुरक्षा

TensorFlow Lite मॉडल को ML Kit के लिए उपलब्ध कराने का तरीका चाहे जो भी हो, ML Kit उन्हें लोकल स्टोरेज में स्टैंडर्ड सीरियलाइज़्ड प्रोटोबफ़ फ़ॉर्मैट में सेव करता है.

सैद्धांतिक तौर पर, इसका मतलब है कि कोई भी आपके मॉडल को कॉपी कर सकता है. हालांकि, व्यवहार में ज़्यादातर मॉडल, ऐप्लिकेशन के हिसाब से बनाए जाते हैं और ऑप्टिमाइज़ेशन की वजह से उन्हें समझना मुश्किल होता है. इसलिए, जोखिम उतना ही होता है जितना कि प्रतिस्पर्धियों के आपके कोड को अलग-अलग हिस्सों में बांटकर फिर से इस्तेमाल करने से होता है. हालांकि, आपको अपने ऐप्लिकेशन में कस्टम मॉडल का इस्तेमाल करने से पहले, इस जोखिम के बारे में पता होना चाहिए.

Android के एपीआई लेवल 21 (Lollipop) और इसके बाद के वर्शन पर, मॉडल को ऐसी डायरेक्ट्री में डाउनलोड किया जाता है जिसे अपने-आप होने वाले बैकअप से बाहर रखा जाता है.

Android के एपीआई लेवल 20 और इससे पुराने वर्शन पर, मॉडल को com.google.firebase.ml.custom.models नाम की डायरेक्ट्री में डाउनलोड किया जाता है. यह डायरेक्ट्री, ऐप्लिकेशन के प्राइवेट इंटरनल स्टोरेज में होती है. अगर आपने BackupAgent का इस्तेमाल करके फ़ाइल बैकअप लेने की सुविधा चालू की है, तो आपके पास इस डायरेक्ट्री को शामिल न करने का विकल्प होता है.