MediaPipe Tasks की मदद से, हाथ से लिखा हुआ डिजिट क्लासिफ़ायर ऐप्लिकेशन बनाएं

1. परिचय

MediaPipe क्या है?

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

इमेज की कैटगरी तय करना, एमएल विज़न टास्क में से एक है. MediaPipe Solutions, इस तरह के कई टास्क उपलब्ध कराता है. MediaPipe Tasks, Android, iOS, Python (इसमें Raspberry Pi भी शामिल है!) और वेब के लिए उपलब्ध है.

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

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

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

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

  • Android Studio का इंस्टॉल किया गया वर्शन. इस कोडलैब को Android Studio Giraffe के साथ लिखा और टेस्ट किया गया है.
  • ऐप्लिकेशन चलाने के लिए, Android डिवाइस या एम्युलेटर.
  • Android डेवलपमेंट की बुनियादी जानकारी (यह "Hello World" नहीं है, लेकिन इससे ज़्यादा अलग भी नहीं है!).

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

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

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

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

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

a0b5b070b802e4ea.png

  1. उस जगह पर जाएं जहां आपने रिपॉज़िटरी को क्लोन या डाउनलोड किया है. इसके बाद, codelabs/digitclassifier/android/start डायरेक्ट्री खोलें.
  2. पुष्टि करें कि सब कुछ सही तरीके से खुला है. इसके लिए, Android Studio में सबसे ऊपर दाईं ओर मौजूद, हरे रंग के रन ऐरो ( 7e15a9c9e1620fe7.png) पर क्लिक करें
  3. आपको ऐप्लिकेशन, काली स्क्रीन के साथ खुला हुआ दिखेगा. इस स्क्रीन पर ड्रॉइंग की जा सकती है. साथ ही, स्क्रीन को रीसेट करने के लिए मिटाएं बटन भी दिखेगा. इस स्क्रीन पर ड्रॉइंग की जा सकती है. हालांकि, इसमें और कुछ नहीं किया जा सकता. इसलिए, हम इसे ठीक करने की प्रोसेस शुरू करेंगे.

11a0f6fe021fdc92.jpeg

मॉडल

पहली बार ऐप्लिकेशन चलाने पर, आपको दिख सकता है कि mnist.tflite नाम की फ़ाइल डाउनलोड हो गई है और आपके ऐप्लिकेशन की assets डायरेक्ट्री में सेव हो गई है. आसानी से समझने के लिए, हमने पहले से ही एक जाने-माने मॉडल, MNIST को लिया है. यह मॉडल अंकों को कैटगरी में बांटता है. हमने इसे प्रोजेक्ट में download_models.gradle स्क्रिप्ट का इस्तेमाल करके, ऐप्लिकेशन में जोड़ा है. अगर आपको अपने कस्टम मॉडल को ट्रेन करना है, जैसे कि हाथ से लिखे गए अक्षरों के लिए, तो आपको download_models.gradle फ़ाइल को हटाना होगा. साथ ही, ऐप्लिकेशन लेवल की build.gradle फ़ाइल में मौजूद इसके रेफ़रंस को मिटाना होगा. इसके बाद, कोड में मॉडल का नाम बदलना होगा. खास तौर पर, DigitClassifierHelper.kt फ़ाइल में.

build.gradle फ़ाइल अपडेट करना

MediaPipe Tasks का इस्तेमाल करने से पहले, आपको लाइब्रेरी इंपोर्ट करनी होगी.

  1. अपने ऐप्लिकेशन मॉड्यूल में मौजूद build.gradle फ़ाइल खोलें. इसके बाद, नीचे की ओर स्क्रोल करके dependencies ब्लॉक पर जाएं.
  2. आपको उस ब्लॉक के सबसे नीचे एक टिप्पणी दिखेगी, जिसमें लिखा होगा // STEP 1 Dependency Import.
  3. उस लाइन की जगह, यहां दिया गया कोड डालें
implementation("com.google.mediapipe:tasks-vision:latest.release")
  1. इस डिपेंडेंसी को डाउनलोड करने के लिए, Android Studio में सबसे ऊपर मौजूद बैनर में दिखने वाले अभी सिंक करें बटन पर क्लिक करें.

3. MediaPipe Tasks की मदद से, डिजिट की पहचान करने वाला हेल्पर बनाएं

अगले चरण में, आपको एक ऐसी क्लास भरनी होगी जो मशीन लर्निंग क्लासिफ़िकेशन के लिए मुश्किल काम करेगी. DigitClassifierHelper.kt खोलें और शुरू करें!

  1. क्लास में सबसे ऊपर मौजूद, // STEP 2 Create listener वाली टिप्पणी ढूंढें
  2. उस लाइन की जगह यह कोड डालें. इससे एक लिसनर तैयार होगा. इसका इस्तेमाल, DigitClassifierHelper क्लास से मिले नतीजों को उस जगह पर वापस भेजने के लिए किया जाएगा जहां इन नतीजों को सुना जा रहा है. इस मामले में, यह आपकी DigitCanvasFragment क्लास होगी. हालांकि, हम जल्द ही वहां पहुंचेंगे
// STEP 2 Create listener

interface DigitClassifierListener {
    fun onError(error: String)
    fun onResults(
        results: ImageClassifierResult,
        inferenceTime: Long
    )
}
  1. आपको क्लास के लिए, DigitClassifierListener को एक वैकल्पिक पैरामीटर के तौर पर भी स्वीकार करना होगा:
class DigitClassifierHelper(
    val context: Context,
    val digitClassifierListener: DigitClassifierListener?
) {
  1. // STEP 3 define classifier वाली लाइन के नीचे, यह लाइन जोड़ें. इससे ImageClassifier के लिए एक प्लेसहोल्डर बन जाएगा, जिसका इस्तेमाल इस ऐप्लिकेशन के लिए किया जाएगा:

// STEP 3 define classifier

private var digitClassifier: ImageClassifier? = null
  1. जहां आपको टिप्पणी // STEP 4 set up classifier दिख रही है वहां यह फ़ंक्शन जोड़ें:
// STEP 4 set up classifier
private fun setupDigitClassifier() {

    val baseOptionsBuilder = BaseOptions.builder()
        .setModelAssetPath("mnist.tflite")

    // Describe additional options
    val optionsBuilder = ImageClassifierOptions.builder()
        .setRunningMode(RunningMode.IMAGE)
        .setBaseOptions(baseOptionsBuilder.build())

    try {
        digitClassifier =
            ImageClassifier.createFromOptions(
                context,
                optionsBuilder.build()
            )
    } catch (e: IllegalStateException) {
        digitClassifierListener?.onError(
            "Image classifier failed to initialize. See error logs for " +
                    "details"
        )
        Log.e(TAG, "MediaPipe failed to load model with error: " + e.message)
    }
}

ऊपर दिए गए सेक्शन में कुछ चीज़ें हो रही हैं. इसलिए, आइए छोटे-छोटे हिस्सों को देखकर समझते हैं कि असल में क्या हो रहा है.

val baseOptionsBuilder = BaseOptions.builder()
    .setModelAssetPath("mnist.tflite")

// Describe additional options
val optionsBuilder = ImageClassifierOptions.builder()
    .setRunningMode(RunningMode.IMAGE)
    .setBaseOptions(baseOptionsBuilder.build())

इस ब्लॉक में, ImageClassifier के इस्तेमाल किए गए पैरामीटर तय किए जाएंगे. इसमें BaseOptions में मौजूद, आपके ऐप्लिकेशन में सेव किया गया मॉडल (mnist.tflite) और ImageClassifierOptions में मौजूद RunningMode शामिल है. इस मामले में, यह IMAGE है. हालांकि, VIDEO और LIVE_STREAM भी उपलब्ध विकल्प हैं. अन्य उपलब्ध पैरामीटर में MaxResults शामिल है. यह मॉडल को ज़्यादा से ज़्यादा नतीजे दिखाने के लिए सीमित करता है. साथ ही, ScoreThreshold, मॉडल को किसी नतीजे को दिखाने से पहले, उसमें कम से कम कॉन्फ़िडेंस सेट करता है.

try {
    digitClassifier =
        ImageClassifier.createFromOptions(
            context,
            optionsBuilder.build()
        )
} catch (e: IllegalStateException) {
    digitClassifierListener?.onError(
        "Image classifier failed to initialize. See error logs for " +
                "details"
    )
    Log.e(TAG, "MediaPipe failed to load model with error: " + e.message)
}

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

  1. हम ImageClassifier को इस्तेमाल करने से पहले शुरू करना चाहेंगे. इसलिए, setupDigitClassifier() को कॉल करने के लिए, init ब्लॉक जोड़ा जा सकता है.
init {
    setupDigitClassifier()
}
  1. आखिर में, नीचे की ओर स्क्रोल करके उस टिप्पणी पर जाएं जिसमें लिखा है कि // STEP 5 create classify function और यह कोड जोड़ें. यह फ़ंक्शन, Bitmap को स्वीकार करेगा. इस मामले में, यह खींचा गया अंक है. यह इसे MediaPipe Image ऑब्जेक्ट (MPImage) में बदल देगा. इसके बाद, ImageClassifier का इस्तेमाल करके उस इमेज की कैटगरी तय करेगा. साथ ही, यह भी रिकॉर्ड करेगा कि अनुमान लगाने में कितना समय लगता है. इसके बाद, DigitClassifierListener के ज़रिए उन नतीजों को वापस भेज देगा.
// STEP 5 create classify function
fun classify(image: Bitmap) {
    if (digitClassifier == null) {
        setupDigitClassifier()
    }

    // Convert the input Bitmap object to an MPImage object to run inference.
    // Rotating shouldn't be necessary because the text is being extracted from
    // a view that should always be correctly positioned.
    val mpImage = BitmapImageBuilder(image).build()

    // Inference time is the difference between the system time at the start and finish of the
    // process
    val startTime = SystemClock.uptimeMillis()

    // Run image classification using MediaPipe Image Classifier API
    digitClassifier?.classify(mpImage)?.also { classificationResults ->
        val inferenceTimeMs = SystemClock.uptimeMillis() - startTime
        digitClassifierListener?.onResults(classificationResults, inferenceTimeMs)
    }
}

बस, हेल्पर फ़ाइल के लिए इतना ही! अगले सेक्शन में, आपको चुने गए नंबरों को कैटगरी में बांटने के लिए, आखिरी चरण पूरे करने होंगे.

4. MediaPipe Tasks की मदद से अनुमान लगाना

इस सेक्शन को शुरू करने के लिए, Android Studio में DigitCanvasFragment क्लास खोलें. यहीं पर सारा काम होगा.

  1. इस फ़ाइल में सबसे नीचे, आपको एक टिप्पणी दिखेगी. इसमें लिखा होगा // STEP 6 Set up listener. यहां लिसनर से जुड़े onResults() और onError() फ़ंक्शन जोड़े जाएंगे.
// STEP 6 Set up listener
override fun onError(error: String) {
    activity?.runOnUiThread {
        Toast.makeText(requireActivity(), error, Toast.LENGTH_SHORT).show()
        fragmentDigitCanvasBinding.tvResults.text = ""
    }
}

override fun onResults(
    results: ImageClassifierResult,
    inferenceTime: Long
) {
    activity?.runOnUiThread {
        fragmentDigitCanvasBinding.tvResults.text = results
            .classificationResult()
            .classifications().get(0)
            .categories().get(0)
            .categoryName()

        fragmentDigitCanvasBinding.tvInferenceTime.text = requireActivity()
            .getString(R.string.inference_time, inferenceTime.toString())
    }
}

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

  1. ऊपर दिए गए चरण में, इंटरफ़ेस से नए फ़ंक्शन जोड़े जा रहे हैं. इसलिए, आपको क्लास के सबसे ऊपर, लागू करने की जानकारी भी जोड़नी होगी.
class DigitCanvasFragment : Fragment(), DigitClassifierHelper.DigitClassifierListener
  1. क्लास के सबसे ऊपर आपको एक टिप्पणी दिखेगी, जिसमें लिखा होगा // STEP 7a Initialize classifier. आपको DigitClassifierHelper के लिए एलान यहां करना होगा.
// STEP 7a Initialize classifier.
private lateinit var digitClassifierHelper: DigitClassifierHelper
  1. // STEP 7b Initialize classifier, पर जाकर, onViewCreated() फ़ंक्शन में digitClassifierHelper को इनिशियलाइज़ किया जा सकता है.
// STEP 7b Initialize classifier
// Initialize the digit classifier helper, which does all of the
// ML work. This uses the default values for the classifier.
digitClassifierHelper = DigitClassifierHelper(
    context = requireContext(), digitClassifierListener = this
)
  1. आखिरी चरणों के लिए, // STEP 8a*: classify* टिप्पणी ढूंढें. इसके बाद, एक नया फ़ंक्शन कॉल करने के लिए यह कोड जोड़ें. इस फ़ंक्शन को आपको अभी जोड़ना है. जब ऐप्लिकेशन में ड्राइंग एरिया से उंगली हटाई जाएगी, तब यह कोड ब्लॉक, क्लासिफ़िकेशन को ट्रिगर करेगा.
// STEP 8a: classify
classifyDrawing()
  1. आखिर में, नया classifyDrawing() फ़ंक्शन जोड़ने के लिए, // STEP 8b classify टिप्पणी ढूंढें. इससे कैनवस से बिटमैप निकाला जाएगा. इसके बाद, इसे DigitClassifierHelper को पास किया जाएगा, ताकि क्लासिफ़िकेशन किया जा सके. इससे onResults() इंटरफ़ेस फ़ंक्शन में नतीजे मिलेंगे.
// STEP 8b classify
private fun classifyDrawing() {
    val bitmap = fragmentDigitCanvasBinding.digitCanvas.getBitmap()
    digitClassifierHelper.classify(bitmap)
}

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

इन सभी चरणों को पूरा करने के बाद, आपके पास एक ऐसा ऐप्लिकेशन होगा जो स्क्रीन पर बनाए गए अंकों को पहचान सकता है! ऐप्लिकेशन को टेस्ट करने के लिए, उसे Android Emulator या किसी फ़िज़िकल Android डिवाइस पर डिप्लॉय करें.

  1. ऐप्लिकेशन चलाने के लिए, Android Studio टूलबार में मौजूद 'चलाएं' ( 7e15a9c9e1620fe7.png) पर क्लिक करें.
  2. ड्राइंग पैड पर कोई भी अंक बनाएं और देखें कि ऐप्लिकेशन उसे पहचान पाता है या नहीं. इसमें, मॉडल के हिसाब से बनाई गई संख्या और उस संख्या का अनुमान लगाने में लगा समय, दोनों दिखना चाहिए.

7f37187f8f919638.gif

6. बधाई हो!

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

अगले चरण

  • अब जब आपके पास अंकों को क्लासिफ़ाई करने की सुविधा है, तो आपके पास अपने मॉडल को ट्रेनिंग देने का विकल्प है. इससे, लिखे गए अक्षरों, जानवरों या अन्य चीज़ों को क्लासिफ़ाई किया जा सकता है. MediaPipe Model Maker की मदद से, इमेज की कैटगरी तय करने वाले नए मॉडल को ट्रेन करने से जुड़ा दस्तावेज़, developers.google.com/mediapipe पेज पर देखा जा सकता है.
  • Android के लिए उपलब्ध अन्य MediaPipe Tasks के बारे में जानें. इनमें चेहरे की पहचान, हाथ के जेस्चर की पहचान, और ऑडियो की कैटगरी तय करने की सुविधा शामिल है.

हमें आपके बनाए गए बेहतरीन कॉन्टेंट का इंतज़ार रहेगा!