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

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

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

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

  1. अगर आपने पहले से ऐसा नहीं किया है, तो अपने 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 ऑप्टिमाइज़िंग कन्वर्टर.

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

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

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

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

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

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

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

  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 ऑब्जेक्ट बनाकर, अपने ऐप्लिकेशन के मॉडल इंटरप्रेटर को कॉन्फ़िगर किया जा सकता है.

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

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

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 उन्हें स्टोरेज में स्टैंडर्ड सीरियलाइज़ किए गए protobuf फ़ॉर्मैट में सेव करता है.

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

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

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