GPU

खास जानकारी

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

मोबाइल प्लैटफ़ॉर्म पर अच्छी परफ़ॉर्मेंस के लिए जीपीयू के साथ काम करना ज़रूरी है, खास तौर पर रीयल-टाइम वीडियो के लिए. MediaPipe, डेवलपर को जीपीयू के साथ काम करने वाले कैलकुलेटर लिखने की सुविधा देता है. इनकी मदद से, जीपीयू का इस्तेमाल इन कामों के लिए किया जा सकता है:

  • बैच प्रोसेसिंग के साथ-साथ, डिवाइस पर रीयल-टाइम में प्रोसेसिंग
  • वीडियो रेंडरिंग और इफ़ेक्ट, न सिर्फ़ विश्लेषण

MediaPipe में जीपीयू से जुड़ी सहायता के लिए डिज़ाइन के सिद्धांत यहां दिए गए हैं

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

OpenGL ES सहायता

MediaPipe, Android/Linux पर 3.2 तक के वर्शन OpenGL ES और ES 3.0 तक के वर्शन के साथ काम करता है आज़माएं. इसके अलावा, MediaPipe, iOS पर Metal के साथ भी काम करता है.

चलाने के लिए OpenGL ES 3.1 या इससे नया वर्शन (Android/Linux सिस्टम पर) ज़रूरी है मशीन लर्निंग अनुमान कैलकुलेटर और ग्राफ़.

MediaPipe, ग्राफ़ को एक से ज़्यादा जीएल कॉन्टेक्स्ट में OpenGL चलाने की अनुमति देता है. उदाहरण के लिए, यह यह उन ग्राफ़ में बहुत काम का हो सकता है, जिनमें धीमी जीपीयू अनुमान पाथ को जोड़ा जाता है (उदाहरण के लिए, 10 पर) ज़्यादा तेज़ जीपीयू रेंडरिंग पाथ (जैसे, 30 FPS) पर: एक जीएल कॉन्टेक्स्ट के बाद एक क्रम में कमांड वाली सूची से मेल खाता है. दोनों के लिए समान संदर्भ का इस्तेमाल किया जाता है. टास्क से रेंडरिंग फ़्रेम रेट कम हो जाएगा.

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

OpenGL संदर्भ को एक साथ एक से ज़्यादा थ्रेड से ऐक्सेस नहीं किया जा सकता. इसके अलावा, एक ही थ्रेड पर चालू जीएल कॉन्टेक्स्ट को स्विच करने से, कुछ Android डिवाइस पर. इसलिए, हम एक खास थ्रेड पर काम करते हैं हर संदर्भ के लिए. हर थ्रेड, जीएल कमांड इस्तेमाल करता है और सीरियल कमांड क्यू बनाता है है, जो जीपीयू से एसिंक्रोनस तरीके से एक्ज़ीक्यूट होता है.

जीपीयू कैलकुलेटर की लाइफ़

इस सेक्शन में जीपीयू के प्रोसेस तरीके का बुनियादी स्ट्रक्चर बताया गया है बुनियादी क्लास GlआसानCalculator से लिया गया कैलकुलेटर. जीपीयू कैलकुलेटर LuminanceCalculator को उदाहरण के तौर पर दिखाया गया है. तरीका GlSimpleCalculator::Process से LuminanceCalculator::GlRender कॉल किया गया है.

// Converts RGB images into luminance images, still stored in RGB format.
// See GlSimpleCalculator for inputs, outputs and input side packets.
class LuminanceCalculator : public GlSimpleCalculator {
 public:
  absl::Status GlSetup() override;
  absl::Status GlRender(const GlTexture& src,
                        const GlTexture& dst) override;
  absl::Status GlTeardown() override;

 private:
  GLuint program_ = 0;
  GLint frame_;
};
REGISTER_CALCULATOR(LuminanceCalculator);

absl::Status LuminanceCalculator::GlRender(const GlTexture& src,
                                           const GlTexture& dst) {
  static const GLfloat square_vertices[] = {
      -1.0f, -1.0f,  // bottom left
      1.0f,  -1.0f,  // bottom right
      -1.0f, 1.0f,   // top left
      1.0f,  1.0f,   // top right
  };
  static const GLfloat texture_vertices[] = {
      0.0f, 0.0f,  // bottom left
      1.0f, 0.0f,  // bottom right
      0.0f, 1.0f,  // top left
      1.0f, 1.0f,  // top right
  };

  // program
  glUseProgram(program_);
  glUniform1i(frame_, 1);

  // vertex storage
  GLuint vbo[2];
  glGenBuffers(2, vbo);
  GLuint vao;
  glGenVertexArrays(1, &vao);
  glBindVertexArray(vao);

  // vbo 0
  glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
  glBufferData(GL_ARRAY_BUFFER, 4 * 2 * sizeof(GLfloat), square_vertices,
               GL_STATIC_DRAW);
  glEnableVertexAttribArray(ATTRIB_VERTEX);
  glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, nullptr);

  // vbo 1
  glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
  glBufferData(GL_ARRAY_BUFFER, 4 * 2 * sizeof(GLfloat), texture_vertices,
               GL_STATIC_DRAW);
  glEnableVertexAttribArray(ATTRIB_TEXTURE_POSITION);
  glVertexAttribPointer(ATTRIB_TEXTURE_POSITION, 2, GL_FLOAT, 0, 0, nullptr);

  // draw
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

  // cleanup
  glDisableVertexAttribArray(ATTRIB_VERTEX);
  glDisableVertexAttribArray(ATTRIB_TEXTURE_POSITION);
  glBindBuffer(GL_ARRAY_BUFFER, 0);
  glBindVertexArray(0);
  glDeleteVertexArrays(1, &vao);
  glDeleteBuffers(2, vbo);

  return absl::OkStatus();
}

ऊपर बताए गए डिज़ाइन सिद्धांतों के आधार पर, नीचे दिए गए डिज़ाइन तैयार किए गए हैं MediaPipe जीपीयू से जुड़ी सहायता के विकल्प:

  • हमारे पास जीपीयू डेटा टाइप है, जिसका नाम GpuBuffer है. इमेज डेटा को दिखाने के लिए, इसे जीपीयू के इस्तेमाल के लिए ऑप्टिमाइज़ किया जाता है. इस डेटा टाइप का सटीक कॉन्टेंट, ओपेक और प्लैटफ़ॉर्म के हिसाब से होता है.
  • कंपोज़िशन पर आधारित लो-लेवल एपीआई, जिसमें कोई भी ऐसा कैलकुलेटर जो जीपीयू का इस्तेमाल करना चाहता है, GlCalculatorHelper क्लास का इंस्टेंस बनाता है और उसका मालिक होता है. यह क्लास OpenGL कॉन्टेक्स्ट मैनेज करने, इनपुट और आउटपुट के लिए टेक्सचर सेट अप करने वगैरह के लिए, प्लैटफ़ॉर्म-एग्नॉस्टिक एपीआई ऑफ़र करती है.
  • सब-क्लासिंग पर आधारित एक हाई-लेवल एपीआई. इसमें सामान्य कैलकुलेटर, GlSimpleCalculator से इमेज फ़िल्टर सब-क्लास लागू करते हैं. साथ ही, उन्हें अपने खास OpenGL कोड से कुछ वर्चुअल तरीकों को ही बदलना पड़ता है, जबकि सुपर क्लास सभी प्लंबिंग का काम करती है.
  • जीपीयू पर आधारित सभी कैलकुलेटर के बीच जिस डेटा को शेयर करना होता है उसे बाहरी इनपुट के तौर पर उपलब्ध कराया जाता है. इसे ग्राफ़ सेवा के तौर पर लागू किया जाता है और इसे GlCalculatorHelper क्लास से मैनेज किया जाता है.
  • कैलकुलेटर-विशिष्ट हेल्पर और एक शेयर ग्राफ़ सेवा के संयोजन से हमें जीपीयू संसाधन प्रबंधित करने में बहुत मदद मिलती है: हम हर कैलकुलेटर के लिए एक अलग संदर्भ रख सकते हैं, एक संदर्भ शेयर कर सकते हैं, कोई लॉक या अन्य सिंक करने के तरीके शेयर कर सकते हैं, वगैरह. -- और ये सभी काम हेल्पर के ज़रिए प्रबंधित किए जाते हैं और अलग-अलग कैलकुलेटर से छिपा दिए जाते हैं.

GpuBuffer से ImageFrame कन्वर्टर

हम GpuBufferToImageFrameCalculator और ImageFrameToGpuBufferCalculator नाम के दो कैलकुलेटर उपलब्ध कराते हैं. ये कैलकुलेटर ImageFrame और GpuBuffer के बीच कन्वर्ट करते हैं. इससे जीपीयू और सीपीयू कैलकुलेटर को जोड़ने वाले ग्राफ़ बनाए जा सकते हैं. वे iOS और Android, दोनों पर काम करते हैं

जब भी मुमकिन हो, ये कैलकुलेटर बिना कॉपी किए सीपीयू और जीपीयू के बीच डेटा शेयर करने के लिए, प्लैटफ़ॉर्म के हिसाब से काम करते हैं.

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

जीपीयू कैलकुलेटर कैसे इंटरैक्ट करते हैं

कैमरे के वीडियो फ़्रेम, ग्राफ़ में GpuBuffer पैकेट के तौर पर डाले जाते हैं. कॉन्टेंट बनाने इनपुट स्ट्रीम को एक साथ दो कैलकुलेटर से ऐक्सेस किया जाता है. GpuBufferToImageFrameCalculator बफ़र को ImageFrame में बदलता है, जिसे ग्रेस्केल कन्वर्टर और कैनी फ़िल्टर से भेजा जाता है (दोनों और सीपीयू पर चल रहा होता है, तो उसका आउटपुट, GpuBuffer फिर से. एक से ज़्यादा इनपुट वाला जीपीयू कैलकुलेटर, GlOverlayCalculator, इस तरह लेता है ओरिजनल GpuBuffer और एज डिटेक्टर से आने वाले डिटेक्टर, दोनों को डालें, और शेडर का इस्तेमाल करके उन्हें ओवरले कर लें. इसके बाद आउटपुट को ऐप्लिकेशन, कॉलबैक कैलकुलेटर का इस्तेमाल करता है और ऐप्लिकेशन इमेज को रेंडर करता है स्क्रीन पर OpenGL का इस्तेमाल करके कनेक्ट करें.