জিপিইউ

ওভারভিউ

MediaPipe GPU কম্পিউট এবং রেন্ডারিংয়ের জন্য ক্যালকুলেটর নোড সমর্থন করে এবং একাধিক GPU নোডকে একত্রিত করার পাশাপাশি CPU ভিত্তিক ক্যালকুলেটর নোডগুলির সাথে মিশ্রিত করার অনুমতি দেয়। মোবাইল প্ল্যাটফর্মে বেশ কিছু GPU API রয়েছে (যেমন, OpenGL ES, Metal এবং Vulkan)। MediaPipe একটি একক ক্রস-API GPU বিমূর্ততা অফার করার চেষ্টা করে না। পৃথক নোডগুলিকে বিভিন্ন API ব্যবহার করে লেখা যেতে পারে, প্রয়োজনে তাদের প্ল্যাটফর্ম নির্দিষ্ট বৈশিষ্ট্যগুলির সুবিধা নিতে দেয়।

মোবাইল প্ল্যাটফর্মে ভালো পারফরম্যান্সের জন্য, বিশেষ করে রিয়েল-টাইম ভিডিওর জন্য GPU সমর্থন অপরিহার্য। MediaPipe ডেভেলপারদের GPU সামঞ্জস্যপূর্ণ ক্যালকুলেটর লিখতে সক্ষম করে যা এর জন্য GPU ব্যবহার সমর্থন করে:

  • অন-ডিভাইস রিয়েল-টাইম প্রসেসিং, শুধু ব্যাচ প্রসেসিং নয়
  • ভিডিও রেন্ডারিং এবং প্রভাব, শুধু বিশ্লেষণ নয়

নীচে MediaPipe-এ GPU সমর্থনের জন্য ডিজাইন নীতিগুলি রয়েছে৷

  • GPU-ভিত্তিক ক্যালকুলেটরগুলি গ্রাফের যে কোনও জায়গায় ঘটতে সক্ষম হওয়া উচিত এবং অন-স্ক্রিন রেন্ডারিংয়ের জন্য অগত্যা ব্যবহার করা উচিত নয়।
  • একটি জিপিইউ-ভিত্তিক ক্যালকুলেটর থেকে অন্যটিতে ফ্রেম ডেটা স্থানান্তর দ্রুত হওয়া উচিত এবং ব্যয়বহুল কপি অপারেশন করা উচিত নয়।
  • সিপিইউ এবং জিপিইউ-এর মধ্যে ফ্রেম ডেটা স্থানান্তর প্ল্যাটফর্মের অনুমতি অনুযায়ী কার্যকর হওয়া উচিত।
  • যেহেতু বিভিন্ন প্ল্যাটফর্মের সেরা পারফরম্যান্সের জন্য বিভিন্ন কৌশলের প্রয়োজন হতে পারে, এপিআইকে পর্দার আড়ালে জিনিসগুলি বাস্তবায়িত করার উপায়ে নমনীয়তার অনুমতি দেওয়া উচিত।
  • একটি ক্যালকুলেটরকে তার ক্রিয়াকলাপের সমস্ত বা অংশের জন্য GPU ব্যবহারে সর্বাধিক নমনীয়তার অনুমতি দেওয়া উচিত, প্রয়োজনে এটিকে CPU-এর সাথে একত্রিত করা।

OpenGL ES সমর্থন

MediaPipe Android/Linux-এ OpenGL ES সংস্করণ 3.2 পর্যন্ত এবং iOS-এ ES 3.0 পর্যন্ত সমর্থন করে। উপরন্তু, MediaPipe iOS এ মেটাল সমর্থন করে।

মেশিন লার্নিং ইনফারেন্স ক্যালকুলেটর এবং গ্রাফ চালানোর জন্য OpenGL ES 3.1 বা তার বেশি প্রয়োজন (Android/Linux সিস্টেমে)।

MediaPipe একাধিক GL প্রসঙ্গে গ্রাফগুলিকে OpenGL চালানোর অনুমতি দেয়। উদাহরণস্বরূপ, এটি গ্রাফগুলিতে খুব কার্যকর হতে পারে যা একটি ধীর GPU অনুমান পথকে (যেমন, 10 FPS-এ) একটি দ্রুত GPU রেন্ডারিং পাথের সাথে (যেমন, 30 FPS এ) একত্রিত করে: যেহেতু একটি GL প্রসঙ্গ একটি অনুক্রমিক কমান্ড সারির সাথে মিলে যায়, ব্যবহার করে উভয় কাজের জন্য একই প্রেক্ষাপট রেন্ডারিং ফ্রেম রেট কমিয়ে দেবে।

মিডিয়াপাইপের একাধিক প্রসঙ্গের ব্যবহার একটি চ্যালেঞ্জ সমাধান করে তা হল তাদের মধ্যে যোগাযোগ করার ক্ষমতা। একটি উদাহরণ দৃশ্যকল্প হল একটি ইনপুট ভিডিও সহ যেটি রেন্ডারিং এবং ইনফারেন্স পাথ উভয়েই পাঠানো হয় এবং রেন্ডারিংকে অনুমান থেকে সর্বশেষ আউটপুটে অ্যাক্সেস থাকতে হবে।

একটি OpenGL প্রসঙ্গ একই সময়ে একাধিক থ্রেড দ্বারা অ্যাক্সেস করা যাবে না। তদ্ব্যতীত, একই থ্রেডে সক্রিয় GL প্রসঙ্গ স্যুইচ করা কিছু Android ডিভাইসে ধীর হতে পারে। অতএব, আমাদের পদ্ধতি হল প্রতি প্রসঙ্গে একটি উৎসর্গীকৃত থ্রেড। প্রতিটি থ্রেড GL কমান্ড ইস্যু করে, এর প্রসঙ্গে একটি সিরিয়াল কমান্ড সারি তৈরি করে, যা GPU দ্বারা অ্যাসিঙ্ক্রোনাসভাবে চালানো হয়।

একটি GPU ক্যালকুলেটরের জীবন

এই বিভাগটি বেস ক্লাস GlSimpleCalculator থেকে প্রাপ্ত একটি GPU ক্যালকুলেটরের প্রক্রিয়া পদ্ধতির মৌলিক কাঠামো উপস্থাপন করে। GPU ক্যালকুলেটর LuminanceCalculator একটি উদাহরণ হিসেবে দেখানো হয়েছে। LuminanceCalculator::GlRender পদ্ধতিটিকে GlSimpleCalculator::Process থেকে বলা হয়।

// 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 GPU সমর্থনের জন্য নিম্নলিখিত নকশা পছন্দ হয়েছে:

  • আমাদের কাছে একটি GPU ডেটা টাইপ আছে, যাকে বলা হয় GpuBuffer , চিত্র ডেটা উপস্থাপনের জন্য, GPU ব্যবহারের জন্য অপ্টিমাইজ করা হয়েছে৷ এই ডেটা টাইপের সঠিক বিষয়বস্তু অস্বচ্ছ এবং প্ল্যাটফর্ম-নির্দিষ্ট।
  • কম্পোজিশনের উপর ভিত্তি করে একটি নিম্ন-স্তরের API, যেখানে যে কোনো ক্যালকুলেটর GPU ব্যবহার করতে চায় GlCalculatorHelper ক্লাসের একটি উদাহরণ তৈরি করে এবং তার মালিক। এই ক্লাসটি OpenGL প্রসঙ্গ পরিচালনা, ইনপুট এবং আউটপুটগুলির জন্য টেক্সচার সেট আপ করার জন্য একটি প্ল্যাটফর্ম-অজ্ঞেয়বাদী API অফার করে।
  • সাবক্লাসিং-এর উপর ভিত্তি করে একটি উচ্চ-স্তরের API, যেখানে সাধারণ ক্যালকুলেটরগুলি GlSimpleCalculator থেকে ইমেজ ফিল্টার সাবক্লাস প্রয়োগ করে এবং শুধুমাত্র তাদের নির্দিষ্ট OpenGL কোড দিয়ে কয়েকটি ভার্চুয়াল পদ্ধতি ওভাররাইড করতে হবে, যখন সুপারক্লাস সমস্ত প্লাম্বিংয়ের যত্ন নেয়।
  • সমস্ত GPU-ভিত্তিক ক্যালকুলেটরগুলির মধ্যে যে ডেটা ভাগ করতে হবে তা একটি বাহ্যিক ইনপুট হিসাবে সরবরাহ করা হয় যা একটি গ্রাফ পরিষেবা হিসাবে প্রয়োগ করা হয় এবং GlCalculatorHelper ক্লাস দ্বারা পরিচালিত হয়৷
  • ক্যালকুলেটর-নির্দিষ্ট সহায়ক এবং একটি ভাগ করা গ্রাফ পরিষেবার সংমিশ্রণ আমাদের GPU সংস্থান পরিচালনার ক্ষেত্রে দুর্দান্ত নমনীয়তা দেয়: আমরা ক্যালকুলেটর প্রতি একটি পৃথক প্রসঙ্গ থাকতে পারি, একটি একক প্রসঙ্গ ভাগ করতে পারি, একটি লক বা অন্যান্য সিঙ্ক্রোনাইজেশন আদিম জিনিস ভাগ করতে পারি, ইত্যাদি -- এবং সমস্ত এটি সাহায্যকারী দ্বারা পরিচালিত হয় এবং পৃথক ক্যালকুলেটর থেকে লুকানো হয়।

GpuBuffer থেকে ImageFrame কনভার্টার

আমরা GpuBufferToImageFrameCalculator এবং ImageFrameToGpuBufferCalculator নামে দুটি ক্যালকুলেটর প্রদান করি। এই ক্যালকুলেটরগুলি ImageFrame এবং GpuBuffer এর মধ্যে রূপান্তরিত হয়, যা GPU এবং CPU ক্যালকুলেটরকে একত্রিত করে এমন গ্রাফ নির্মাণের অনুমতি দেয়। এগুলি iOS এবং Android উভয় ক্ষেত্রেই সমর্থিত

যখন সম্ভব, এই ক্যালকুলেটরগুলি অনুলিপি ছাড়াই CPU এবং GPU-এর মধ্যে ডেটা ভাগ করতে প্ল্যাটফর্ম-নির্দিষ্ট কার্যকারিতা ব্যবহার করে।

নীচের চিত্রটি একটি মোবাইল অ্যাপ্লিকেশনে ডেটা প্রবাহ দেখায় যা ক্যামেরা থেকে ভিডিও ক্যাপচার করে, মিডিয়াপাইপ গ্রাফের মাধ্যমে চালায় এবং রিয়েল টাইমে স্ক্রিনে আউটপুট রেন্ডার করে। ড্যাশড লাইন নির্দেশ করে যে মিডিয়াপাইপ গ্রাফের ভিতরে কোন অংশগুলি সঠিক। এই অ্যাপ্লিকেশনটি OpenCV ব্যবহার করে CPU-তে ক্যানি এজ-ডিটেকশন ফিল্টার চালায় এবং GPU ব্যবহার করে এটিকে মূল ভিডিওর উপরে ওভারলে করে।

কিভাবে GPU ক্যালকুলেটর ইন্টারঅ্যাক্ট করে

ক্যামেরা থেকে ভিডিও ফ্রেমগুলি GpuBuffer প্যাকেট হিসাবে গ্রাফে দেওয়া হয়৷ ইনপুট স্ট্রীম দুটি ক্যালকুলেটর দ্বারা সমান্তরালভাবে অ্যাক্সেস করা হয়। GpuBufferToImageFrameCalculator বাফারটিকে একটি ImageFrame এ রূপান্তর করে, যা পরে একটি গ্রেস্কেল রূপান্তরকারী এবং একটি ক্যানি ফিল্টার (উভয়ই OpenCV-এর উপর ভিত্তি করে এবং CPU-তে চলমান) মাধ্যমে পাঠানো হয়, যার আউটপুট আবার GpuBuffer এ রূপান্তরিত হয়। একটি মাল্টি-ইনপুট GPU ক্যালকুলেটর, GlOverlayCalculator, মূল GpuBuffer এবং এজ ডিটেক্টর থেকে বেরিয়ে আসা উভয়ই ইনপুট হিসাবে নেয় এবং একটি শেডার ব্যবহার করে সেগুলিকে ওভারলে করে। আউটপুট তারপরে একটি কলব্যাক ক্যালকুলেটর ব্যবহার করে অ্যাপ্লিকেশনে ফেরত পাঠানো হয়, এবং অ্যাপ্লিকেশনটি OpenGL ব্যবহার করে চিত্রটিকে পর্দায় রেন্ডার করে।