MediaPipe के साथ, Android पर डिवाइस पर इमेज जनरेट करना

1. परिचय

MediaPipe क्या है?

MediaPipe Solutions की मदद से, अपने ऐप्लिकेशन में मशीन लर्निंग (एमएल) सलूशन लागू किए जा सकते हैं. यह पहले से बनी प्रोसेसिंग पाइपलाइन को कॉन्फ़िगर करने के लिए एक फ़्रेमवर्क उपलब्ध कराता है. इससे उपयोगकर्ताओं को तुरंत, दिलचस्प, और काम का आउटपुट मिलता है. डिफ़ॉल्ट मॉडल को अपडेट करने के लिए, इनमें से कई समाधानों को MediaPipe Model Maker की मदद से अपनी पसंद के मुताबिक बनाया जा सकता है.

टेक्स्ट से इमेज जनरेट करने की सुविधा, एमएल से जुड़े कई टास्क में से एक है. MediaPipe Solutions, एमएल से जुड़े कई टास्क उपलब्ध कराता है.

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

आपको क्या सीखने को मिलेगा

  • MediaPipe Tasks की मदद से, Android ऐप्लिकेशन में टेक्स्ट से इमेज जनरेट करने की सुविधा को स्थानीय तौर पर कैसे लागू करें.

आपको किन चीज़ों की ज़रूरत होगी

  • Android Studio का इंस्टॉल किया गया वर्शन. इस कोडलैब को Android Studio Giraffe के साथ लिखा और टेस्ट किया गया है.
  • एक ऐसा Android डिवाइस जिसकी रैम कम से कम 8 जीबी हो.
  • Android डेवलपमेंट की बुनियादी जानकारी और पहले से लिखी गई Python स्क्रिप्ट को चलाने की सुविधा.

2. Android ऐप्लिकेशन में MediaPipe Tasks को जोड़ना

Android स्टार्टर ऐप्लिकेशन डाउनलोड करना

यह कोडलैब, पहले से बने सैंपल से शुरू होगा. इसमें ऐसा यूज़र इंटरफ़ेस (यूआई) होगा जिसका इस्तेमाल, इमेज जनरेट करने के बेसिक वर्शन के लिए किया जाएगा. आपको MediaPipe Samples की आधिकारिक repo में, शुरुआती ऐप्लिकेशन यहां मिल सकता है. कोड > ZIP फ़ाइल डाउनलोड करें पर क्लिक करके, रेपो को क्लोन करें या ZIP फ़ाइल डाउनलोड करें.

ऐप्लिकेशन को Android Studio में इंपोर्ट करना

  1. Android Studio खोलें.
  2. Android Studio में आपका स्वागत है स्क्रीन पर, सबसे ऊपर दाएं कोने में मौजूद खोलें को चुनें.

a0b5b070b802e4ea.png

  1. उस जगह पर जाएं जहां आपने रिपॉज़िटरी को क्लोन या डाउनलोड किया है. इसके बाद, codelabs/image_generation_basic/android/start डायरेक्ट्री खोलें.
  2. इस चरण में, ऐप्लिकेशन को कंपाइल नहीं किया जाना चाहिए, क्योंकि आपने अब तक MediaPipe Tasks की डिपेंडेंसी शामिल नहीं की है.

ऐप्लिकेशन को ठीक करने और उसे चलाने के लिए, build.gradle फ़ाइल में जाएं और नीचे की ओर स्क्रोल करके // Step 1 - Add dependency. पर जाएं. इसके बाद, यहां दी गई लाइन को शामिल करें. इसके बाद, Android Studio में सबसे ऊपर मौजूद बैनर में दिखने वाले अभी सिंक करें बटन पर क्लिक करें.

// Step 1 - Add dependency
implementation 'com.google.mediapipe:tasks-vision-image-generator:latest.release'

सिंक होने के बाद, पुष्टि करें कि सब कुछ सही तरीके से खुला और इंस्टॉल हुआ है. इसके लिए, Android Studio में सबसे ऊपर दाईं ओर मौजूद, हरे रंग के चलाएं ऐरो ( 7e15a9c9e1620fe7.png) पर क्लिक करें. आपको ऐप्लिकेशन, ऐसी स्क्रीन पर खुला हुआ दिखेगा जिस पर दो रेडियो बटन और INITIALIZE लेबल वाला बटन होगा. उस बटन पर क्लिक करने के बाद, आपको तुरंत एक अलग यूज़र इंटरफ़ेस (यूआई) पर ले जाया जाएगा. इसमें एक टेक्स्ट प्रॉम्प्ट और अन्य विकल्प मौजूद होंगे. साथ ही, जनरेट करें लेबल वाला एक बटन भी होगा.

83c31de8e8a320ee.png 78b8765e832024e3.png

माफ़ करें, स्टार्टर ऐप्लिकेशन में इससे ज़्यादा कुछ नहीं है. इसलिए, अब आपको यह सीखना होगा कि इस ऐप्लिकेशन को कैसे पूरा किया जाए और अपने डिवाइस पर नई इमेज जनरेट करना कैसे शुरू किया जाए!

3. इमेज जनरेट करने की सुविधा सेट अप करना

इस उदाहरण के लिए, इमेज जनरेट करने से जुड़ा ज़्यादातर काम ImageGenerationHelper.kt फ़ाइल में होगा. इस फ़ाइल को खोलने पर, आपको क्लास के सबसे ऊपर एक वैरिएबल दिखेगा, जिसे imageGenerator कहा जाता है. यह Task ऑब्जेक्ट है. यह इमेज जनरेट करने वाले ऐप्लिकेशन में मुश्किल कामों को आसान बना देगा.

उस ऑब्जेक्ट के ठीक नीचे, आपको initializeImageGenerator() नाम का एक फ़ंक्शन दिखेगा. इसके साथ यह टिप्पणी होगी: // Step 2 - initialize the image generator. जैसा कि आपको पता होगा, ImageGenerator ऑब्जेक्ट को यहां शुरू किया जाएगा. इमेज जनरेट करने वाले मॉडल का पाथ सेट करने और ImageGenerator ऑब्जेक्ट को शुरू करने के लिए, फ़ंक्शन के मुख्य हिस्से की जगह यह कोड डालें:

// Step 2 - initialize the image generator
val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

imageGenerator = ImageGenerator.createFromOptions(context, options)

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

setInput() के मुख्य हिस्से में जाकर, इस लाइन को बदलें. आपको यहां टिप्पणी // Step 3 - accept inputs दिखेगी:

// Step 3 - accept inputs
imageGenerator.setInputs(prompt, iteration, seed)

अगले दो चरणों में, जवाब जनरेट किया जाता है. generate() फ़ंक्शन, setInput के जैसे ही इनपुट स्वीकार करता है. हालांकि, यह एक बार में ही इमेज जनरेट करता है. इसमें बीच के किसी भी चरण की इमेज नहीं दिखती. इस फ़ंक्शन के मुख्य हिस्से (जिसमें // Step 4 - generate without showing iterations वाली टिप्पणी शामिल है) की जगह यह कोड डालें:

// Step 4 - generate without showing iterations
val result = imageGenerator.generate(prompt, iteration, seed)
val bitmap = BitmapExtractor.extract(result?.generatedImage())
return bitmap

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

इस फ़ाइल में आपको आखिरी चरण के तौर पर, execute() फ़ंक्शन (पांचवें चरण के तौर पर लेबल किया गया) भरना होगा. यह एक ऐसा पैरामीटर स्वीकार करेगा जो यह बताएगा कि ImageGenerator execute() फ़ंक्शन के साथ किए जाने वाले जनरेशन के सिंगल स्टेप के लिए, इसे इंटरमीडिएट इमेज दिखानी चाहिए या नहीं. फ़ंक्शन के मुख्य हिस्से की जगह यह कोड डालें:

// Step 5 - generate with iterations
val result = imageGenerator.execute(showResult)

if (result == null || result.generatedImage() == null) {
    return Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888)
        .apply {
            val canvas = Canvas(this)
            val paint = Paint()
            paint.color = Color.WHITE
            canvas.drawPaint(paint)
        }
}

val bitmap =
    BitmapExtractor.extract(result.generatedImage())

return bitmap

और हेल्पर फ़ाइल के लिए बस इतना ही. अगले सेक्शन में, आपको ViewModel फ़ाइल भरनी होगी. यह फ़ाइल, इस उदाहरण के लिए लॉजिक को मैनेज करती है.

4. ऐप्लिकेशन को एक साथ लाना

MainViewModel फ़ाइल, इस उदाहरण ऐप्लिकेशन से जुड़ी यूज़र इंटरफ़ेस (यूआई) की स्थितियों और अन्य लॉजिक को मैनेज करेगी. इसे अभी खोलें.

फ़ाइल में सबसे ऊपर की ओर, आपको यह टिप्पणी दिखनी चाहिए: // Step 6 - set model path. यहां आपको अपने ऐप्लिकेशन को यह बताना होगा कि इमेज जनरेट करने के लिए ज़रूरी मॉडल फ़ाइलें कहां मिलेंगी. इस उदाहरण के लिए, वैल्यू को /data/local/tmp/image_generator/bins/ पर सेट करें.

// Step 6 - set model path
private val MODEL_PATH = "/data/local/tmp/image_generator/bins/"

इसके बाद, नीचे की ओर स्क्रोल करके generateImage() फ़ंक्शन पर जाएं. इस फ़ंक्शन के सबसे नीचे, आपको सातवां और आठवां चरण दिखेगा. इनका इस्तेमाल, इमेज जनरेट करने के लिए किया जाएगा. सातवें चरण में, इमेज के कुछ वर्शन दिखाए जाएंगे, जबकि आठवें चरण में कोई वर्शन नहीं दिखाया जाएगा. ये दोनों कार्रवाइयां सिंक्रोनस तरीके से होती हैं. इसलिए, आपको दिखेगा कि इन्हें एक को-रूटीन में रैप किया गया है. इस कोड ब्लॉक का इस्तेमाल करके, // Step 7 - Generate without showing iterations को बदला जा सकता है. इससे ImageGenerationHelper फ़ाइल से generate() को कॉल किया जा सकेगा. इसके बाद, यूज़र इंटरफ़ेस (यूआई) की स्थिति को अपडेट किया जा सकेगा.

// Step 7 - Generate without showing iterations
val result = helper?.generate(prompt, iteration, seed)
_uiState.update {
    it.copy(outputBitmap = result)
}

आठवां चरण थोड़ा मुश्किल है. execute() फ़ंक्शन, इमेज जनरेट करने के लिए सभी चरणों के बजाय सिर्फ़ एक चरण पूरा करता है. इसलिए, आपको लूप के ज़रिए हर चरण को अलग-अलग कॉल करना होगा. आपको यह भी तय करना होगा कि मौजूदा चरण को उपयोगकर्ता के लिए दिखाया जाना चाहिए या नहीं. आखिर में, अगर मौजूदा इटरेशन को दिखाना है, तो यूज़र इंटरफ़ेस (यूआई) की स्थिति अपडेट करें. अब ये सभी काम किए जा सकते हैं.

// Step 8 - Generate with showing iterations
helper?.setInput(prompt, iteration, seed)
for (step in 0 until iteration) {
    isDisplayStep =
        (displayIteration > 0 && ((step + 1) % displayIteration == 0))
    val result = helper?.execute(isDisplayStep)

    if (isDisplayStep) {
        _uiState.update {
            it.copy(
                outputBitmap = result,
                generatingMessage = "Generating... (${step + 1}/$iteration)",
            )
        }
    }
}

इस समय, आपके पास अपना ऐप्लिकेशन इंस्टॉल करने, इमेज जनरेटर को शुरू करने, और फिर टेक्स्ट प्रॉम्प्ट के आधार पर नई इमेज बनाने का विकल्प होना चाहिए

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

फ़ाइलों को सीधे अपने डेवलपमेंट डिवाइस पर कॉपी करने के साथ-साथ, Firebase Storage को भी सेट अप किया जा सकता है. इससे ज़रूरी फ़ाइलें, रन टाइम पर सीधे उपयोगकर्ता के डिवाइस पर डाउनलोड हो जाती हैं.

5. ऐप्लिकेशन को डिप्लॉय और टेस्ट करना

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

  1. ऐप्लिकेशन चलाने के लिए, Android Studio टूलबार में मौजूद 'चलाएं' ( 7e15a9c9e1620fe7.png) पर क्लिक करें.
  2. जनरेशन के चरणों का टाइप चुनें (फ़ाइनल या इटरेशन के साथ). इसके बाद, शुरू करें बटन दबाएं.
  3. अगली स्क्रीन पर, अपनी पसंद की कोई भी प्रॉपर्टी सेट करें. इसके बाद, टूल से मिले सुझाव देखने के लिए, जनरेट करें बटन पर क्लिक करें.

e46cfaeb9d3fc235.gif

6. बधाई हो!

आपने कर दिखाया! इस कोडलैब में, आपने किसी Android ऐप्लिकेशन में डिवाइस पर टेक्स्ट से इमेज जनरेट करने की सुविधा जोड़ने का तरीका सीखा.

अगले चरण

इमेज जनरेट करने के टास्क के लिए, कई और काम किए जा सकते हैं. जैसे,

  • प्लगिन की मदद से जनरेट की गई इमेज को स्ट्रक्चर करने के लिए, किसी बेस इमेज का इस्तेमाल करना या Vertex AI की मदद से, अपने अतिरिक्त LoRA वेट को ट्रेन करना.
  • ADB टूल का इस्तेमाल किए बिना, अपने डिवाइस पर मॉडल फ़ाइलें वापस पाने के लिए Firebase Storage का इस्तेमाल करें.

हमें इस एक्सपेरिमेंटल टास्क के ज़रिए, आपके बनाए गए सभी शानदार कॉन्टेंट को देखने का इंतज़ार रहेगा. साथ ही, MediaPipe टीम के ज़्यादा कोडलैब और कॉन्टेंट पर नज़र रखें!