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 जिराफ़ की मदद से लिखा गया था और इसकी जांच की गई थी).
  • ऐप्लिकेशन चलाने के लिए, Android डिवाइस या एम्युलेटर.
  • Android डेवलपमेंट की बुनियादी जानकारी (यह "Hey World" नहीं है, लेकिन ज़्यादा दूर नहीं है!).

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

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

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

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

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

a0b5b070b802e4ea.png

  1. उस जगह पर जाएं जहां आपने रिपॉज़िटरी को क्लोन किया है या डाउनलोड किया है. इसके बाद, codelabs/Digiclassifier/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. आपको उस ब्लॉक के नीचे एक ऐसी टिप्पणी दिखेगी जिसमें लिखा होगा // पहला चरण डिपेंडेंसी इंपोर्ट.
  3. उस लाइन को नीचे दिए गए तरीके से बदलें
implementation("com.google.mediapipe:tasks-vision:latest.release")
  1. इस डिपेंडेंसी को डाउनलोड करने के लिए, Android Studio में सबसे ऊपर मौजूद बैनर में अभी सिंक करें बटन पर क्लिक करें.

3. MediaPipe Tasks डिजिट क्लासीफ़ायर हेल्पर बनाएं

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

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

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

private var digitClassifier: ImageClassifier? = null
  1. नीचे दिया गया फ़ंक्शन जोड़ें जहां आपको यह टिप्पणी दिखाई देती है // चरण 4 सेट अप क्लासिफ़ायर:
// 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 के खासियतिंग मोड में सेव किया गया मॉडल शामिल है, जो इस मामले में IMAGE है, लेकिन VIDEO और LIVE_STREAM इसके अन्य विकल्प हैं. अन्य उपलब्ध पैरामीटर, Maxनतीजे हैं, जो मॉडल को ज़्यादा से ज़्यादा नतीजे दिखाने के लिए सीमित करते हैं और Scoreथ्रेशोल्ड, वह कम से कम भरोसेमंद सेट करता है, जो मॉडल को नतीजे दिखाने से पहले नतीजे में होना चाहिए.

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. आखिर में, नीचे की ओर स्क्रोल करके उस टिप्पणी पर जाएं जिसमें लिखा है कि // पांचवां चरण, कैटगरी तय करने वाला फ़ंक्शन बनाएं. इसके बाद, नीचे दिया गया कोड जोड़ें. यह फ़ंक्शन एक बिटमैप को स्वीकार करेगा, जो इस मामले में ड्रॉ किया गया अंक है. इसके बाद, उसे MediaPipe इमेज ऑब्जेक्ट (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 टास्क की मदद से अनुमान चलाएं

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

  1. इस फ़ाइल के सबसे नीचे आपको एक टिप्पणी दिखेगी. इसमें // छठा चरण, लिसनर सेट अप करें लिखा होगा. यहां आपको लिसनर से जुड़े onनतीजे() और 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())
    }
}

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

  1. ऊपर दिए गए चरण में किसी इंटरफ़ेस से नए फ़ंक्शन जोड़ने पर, आपको क्लास में सबसे ऊपर, लागू करने का एलान भी जोड़ना होगा.
class DigitCanvasFragment : Fragment(), DigitClassifierHelper.DigitClassifierListener
  1. क्लास में सबसे ऊपर आपको एक टिप्पणी दिखेगी जिसमें लिखा होगा // चरण 7a क्लासिफ़ायर शुरू करें. यहां आपको DigitClassifierHelper के लिए एलान करना होगा.
// STEP 7a Initialize classifier.
private lateinit var digitClassifierHelper: DigitClassifierHelper
  1. // STEP 7b क्लासिफ़ायर को शुरू करें पर जाकर,onViewcreated() फ़ंक्शन में DigiClassifierHelper को शुरू किया जा सकता है.
// 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*: लगाएं* टिप्पणी ढूंढें और नए फ़ंक्शन को कॉल करने के लिए यह कोड जोड़ें, जिसे कुछ ही समय में जोड़ा जाएगा. ऐप्लिकेशन में ड्रॉइंग की जगह से उंगली हटाने पर, यह कोड ब्लॉक क्लासिफ़िकेशन को ट्रिगर करेगा.
// STEP 8a: classify
classifyDrawing()
  1. आखिर में, नए क्लासिफ़िकेशनऐसा करने के लिए, // STEP 8b classify करें, टिप्पणी करें. यह कैनवस से बिट मैप एक्सट्रैक्ट करेगा, फिर उसे DigitClassifierHelper को पास कर देगा, ताकि onनतीजे() इंटरफ़ेस फ़ंक्शन में नतीजे पाने के लिए वर्गीकरण किया जा सके.
// 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 टास्क के बारे में जानें. इनमें फ़ेस लैंडमार्क की पहचान, जेस्चर की पहचान, और ऑडियो क्लासिफ़िकेशन शामिल है.

हम आपके द्वारा बनाई गई सभी शानदार चीज़ों की इंतज़ार कर रहे हैं!