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

1. परिचय

MediaPipe क्या है?

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

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

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

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

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

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

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

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

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

यह कोडलैब, पहले से तैयार किए गए सैंपल से शुरू होगा. इसकी मदद से, स्क्रीन पर ड्रॉ किया जा सकता है. आपको वह शुरुआती ऐप्लिकेशन, MediaPipe के आधिकारिक सैंपल रेपो यहां मिलेगा. कोड > 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 नाम की एक फ़ाइल दिख सकती है. यह फ़ाइल, आपके ऐप्लिकेशन की ऐसेट डायरेक्ट्री में डाउनलोड और सेव हो जाती है. आसानी से समझने के लिए, हमने पहले से ही एक मशहूर मॉडल, MNIST का इस्तेमाल किया है. यह मॉडल अंकों की कैटगरी तय करता है. साथ ही, हमने प्रोजेक्ट में download_models.gradle स्क्रिप्ट का इस्तेमाल करके, इसे ऐप्लिकेशन में जोड़ा है. अगर आपको अपना कस्टम मॉडल ट्रेन करना है, जैसे कि हाथ से लिखे गए अक्षरों के लिए, तो आपको download_models.gradle फ़ाइल को हटाना होगा. साथ ही, ऐप्लिकेशन लेवल की build.gradle फ़ाइल में इसका रेफ़रंस मिटाना होगा. इसके बाद, कोड में मॉडल का नाम बदलना होगा. खास तौर पर, DigitClassifierHelper.kt फ़ाइल में.

build.gradle अपडेट करना

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

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

3. MediaPipe Tasks की मदद से, हाथ से लिखे गए अंकों की पहचान करने वाला हेल्पर बनाना

अगले चरण में, आपको एक क्लास भरनी होगी. यह क्लास, मशीन लर्निंग की मदद से डेटा को अलग-अलग कैटगरी में बांटने का काम करेगी. DigitClassifierHelper.kt खोलें और शुरू करें!

  1. क्लास में सबसे ऊपर मौजूद वह टिप्पणी ढूंढें जिसमें लिखा हो कि // दूसरा चरण: लिसनर बनाएं
  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. // तीसरा चरण: क्लासिफ़ायर तय करना वाली लाइन पर जाकर, ImageClassifier के लिए प्लेसहोल्डर बनाने के लिए यह लाइन जोड़ें. इसका इस्तेमाल इस ऐप्लिकेशन के लिए किया जाएगा:

// तीसरा चरण: क्लासिफ़ायर तय करना

private var digitClassifier: ImageClassifier? = null
  1. जहां आपको टिप्पणी // चौथा चरण: क्लासिफ़ायर सेट अप करना दिखती है वहां यह फ़ंक्शन जोड़ें:
// 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 के इस्तेमाल किए गए पैरामीटर तय किए जाएंगे. इसमें आपके ऐप्लिकेशन में सेव किया गया मॉडल (mnist.tflite) शामिल है, जो BaseOptions में मौजूद है. साथ ही, इसमें 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. इस फ़ाइल में सबसे नीचे, आपको एक टिप्पणी दिखेगी, जिसमें लिखा होगा कि // छठा चरण: लिसनर सेट अप करना. यहां आपको 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 क्लासिफ़ायर को शुरू करें. यहां आपको DigitClassifierHelper के लिए एलान करना होगा.
// STEP 7a Initialize classifier.
private lateinit var digitClassifierHelper: DigitClassifierHelper
  1. // STEP 7b क्लासिफ़ायर को शुरू करें पर जाकर,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 एम्युलेटर या किसी फ़िज़िकल Android डिवाइस पर डिप्लॉय करें.

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

7f37187f8f919638.gif

6. बधाई हो!

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

अगले चरण

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

हमें आपके बनाए गए शानदार शॉर्ट वीडियो देखने का इंतज़ार रहेगा!