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

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

TensorFlow Lite मॉडल

TensorFlow Lite मॉडल, एमएल मॉडल होते हैं. इन्हें मोबाइल डिवाइसों पर चलाने के लिए ऑप्टिमाइज़ किया जाता है. TensorFlow Lite मॉडल पाने के लिए:

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

  1. अगर आपने पहले से ऐसा नहीं किया है, तो अपने Android प्रोजेक्ट में Firebase जोड़ें.
  2. अपनी मॉड्यूल (ऐप्लिकेशन-लेवल) Gradle फ़ाइल (आम तौर पर <project>/<app-module>/build.gradle.kts या <project>/<app-module>/build.gradle) में, Android के लिए Firebase ML मॉडल डाउनलोडर लाइब्रेरी की डिपेंडेंसी जोड़ें. हमारा सुझाव है कि लाइब्रेरी के वर्शन को कंट्रोल करने के लिए, Firebase Android BoM का इस्तेमाल करें.

    साथ ही, Firebase ML मॉडल डाउनलोडर को सेट अप करने के लिए, आपको अपने ऐप्लिकेशन में TensorFlow Lite SDK टूल जोड़ना होगा.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:33.7.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 का इस्तेमाल करने पर, आपका ऐप्लिकेशन हमेशा Firebase Android लाइब्रेरी के काम करने वाले वर्शन का इस्तेमाल करेगा.

    (विकल्प)  BoM का इस्तेमाल किए बिना Firebase लाइब्रेरी की डिपेंडेंसी जोड़ें

    अगर Firebase BoM का इस्तेमाल नहीं किया जाता है, तो आपको हर Firebase लाइब्रेरी के वर्शन की जानकारी, उसकी डिपेंडेंसी लाइन में देनी होगी.

    ध्यान दें कि अगर आपके ऐप्लिकेशन में एक से ज़्यादा Firebase लाइब्रेरी का इस्तेमाल किया जाता है, तो हमारा सुझाव है कि आप लाइब्रेरी के वर्शन मैनेज करने के लिए BoM का इस्तेमाल करें. इससे यह पक्का होता है कि सभी वर्शन काम करते हों.

    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.1")
    // Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0")
    }
    क्या आपको Kotlin के लिए कोई लाइब्रेरी मॉड्यूल चाहिए? अक्टूबर 2023 (Firebase BoM 32.5.0) से, Kotlin और Java, दोनों डेवलपर मुख्य लाइब्रेरी मॉड्यूल का इस्तेमाल कर सकते हैं. ज़्यादा जानकारी के लिए, इस पहल के बारे में अक्सर पूछे जाने वाले सवाल देखें.
  3. अपने ऐप्लिकेशन के मेनिफ़ेस्ट में, यह एलान करें कि INTERNET की अनुमति ज़रूरी है:
    <uses-permission android:name="android.permission.INTERNET" />

1. अपना मॉडल डिप्लॉय करना

Firebase कंसोल या Firebase Admin Python और Node.js SDK टूल का इस्तेमाल करके, अपने कस्टम TensorFlow मॉडल डिप्लॉय करें. कस्टम मॉडल डिप्लॉय और मैनेज करना देखें.

अपने Firebase प्रोजेक्ट में कस्टम मॉडल जोड़ने के बाद, आपके पास अपने ऐप्लिकेशन में, तय किए गए नाम का इस्तेमाल करके मॉडल का रेफ़रंस देने का विकल्प होता है. किसी भी समय, getModel() को कॉल करके, नया TensorFlow Lite मॉडल डिप्लॉय किया जा सकता है और उपयोगकर्ताओं के डिवाइसों पर नया मॉडल डाउनलोड किया जा सकता है (नीचे देखें).

2. मॉडल को डिवाइस पर डाउनलोड करना और TensorFlow Lite इंटरप्रेटर को शुरू करना

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

मॉडल डाउनलोड करने के लिए, मॉडल डाउनलोडर के getModel() तरीके को कॉल करें. साथ ही, मॉडल अपलोड करते समय असाइन किया गया नाम बताएं. साथ ही, यह भी बताएं कि आपको हमेशा नया मॉडल डाउनलोड करना है या नहीं. साथ ही, यह भी बताएं कि आपको किन स्थितियों में डाउनलोड करने की अनुमति देनी है.

डाउनलोड करने के तीन तरीके चुने जा सकते हैं:

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

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

Kotlin

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

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

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

अपने मॉडल के इनपुट और आउटपुट शेप पाना

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

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

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

आउटपुट का उदाहरण:

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

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

अनुवादक को चलाना

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

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

Kotlin

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

इसके बाद, मॉडल के आउटपुट को शामिल करने के लिए, ByteBuffer को इतना बड़ा तय करें और इनपुट बफ़र और आउटपुट बफ़र को TensorFlow Lite इंटरप्रेटर के run() तरीके पर पास करें. उदाहरण के लिए, [1 1000] फ़्लोटिंग-पॉइंट वैल्यू के आउटपुट शेप के लिए:

Kotlin

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

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

उदाहरण के लिए, अगर डेटा को अलग-अलग कैटगरी में बांटा जा रहा है, तो अगले चरण में, नतीजों के इंडेक्स को उन लेबल से मैप किया जा सकता है जिनका वे प्रतिनिधित्व करते हैं:

Kotlin

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

परिशिष्ट: मॉडल की सुरक्षा

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

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

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

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