GPU

Genel Bakış

MediaPipe, GPU bilgi işlem ve oluşturma işlemleri için hesap makinesi düğümlerini destekler. Ayrıca, birden çok GPU düğümünün birleştirilmesinin yanı sıra, CPU tabanlı hesap makinesi düğümleriyle karıştırılmasına da olanak tanır. Mobil platformlarda çeşitli GPU API'leri (ör. OpenGL ES, Metal ve Vulkan) vardır. MediaPipe, tek bir API'ler arası GPU soyutlama sunmaya çalışmaz. Bağımsız düğümler farklı API'ler kullanılarak yazılabilir. Böylece, gerektiğinde platforma özgü özelliklerden yararlanabilirler.

GPU desteği, mobil platformlarda iyi performansın (özellikle gerçek zamanlı videoların) sağlanması için gereklidir. MediaPipe, geliştiricilerin aşağıdaki işlemlerde GPU kullanımını destekleyen GPU ile uyumlu hesaplayıcılar yazmasını sağlar:

  • Yalnızca toplu işlem değil, cihaz üzerinde gerçek zamanlı işleme
  • Yalnızca analiz değil, video oluşturma ve efektler

Aşağıda, MediaPipe'te GPU desteği için tasarım ilkeleri verilmiştir

  • GPU tabanlı hesap makineleri, grafiğin herhangi bir yerinde bulunabilmelidir ve ekranda oluşturma için kullanılmaları gerekmez.
  • Kare verilerinin GPU tabanlı bir hesap makinesinden diğerine aktarılması hızlı olmalı ve pahalı kopyalama işlemlerine neden olmamalıdır.
  • CPU ve GPU arasında kare verisi aktarımı, platformun izin verdiği kadar verimli olmalıdır.
  • Farklı platformlar en iyi performans için farklı teknikler gerektirebilir. Bu nedenle, API arka planda işlerin uygulanma şeklinde esneklik sağlamalıdır.
  • Hesap makinesinin, çalışmasının tamamı veya bir kısmı için GPU kullanımı konusunda maksimum esnekliğe izin verilmeli, gerektiğinde CPU ile birleştirilmelidir.

OpenGL ES Desteği

MediaPipe, Android/Linux üzerinde sürüm 3.2'ye ve ES 3.0'a kadar OpenGL ES'yi destekler iOS'te. MediaPipe ayrıca iOS'te Metal'i de destekler.

Aşağıdakilerin çalışması için OpenGL ES 3.1 veya sonraki sürümleri gerekir (Android/Linux sistemlerinde) makine öğrenimi çıkarım hesaplayıcıları ve grafikleri

MediaPipe, grafiklerin birden çok GL bağlamında OpenGL çalıştırmasına olanak tanır. Örneğin, daha yavaş bir GPU çıkarım yolunu birleştiren grafiklerde çok yararlı olabilir (ör. 10'da FPS) kullanarak (ör. 30 FPS'de): tek bir GL bağlamından itibaren bir sıralı komut kuyruğuna karşılık gelir ve her ikisi için de aynı bağlam kullanılır oluşturma kare hızını düşürür.

MediaPipe'in birden fazla bağlam kullanmasının çözümü, iletişime geçmelerini sağlar. Örnek bir senaryoda, hem oluşturma hem de çıkarım yollarına gönderilir ve oluşturma işleminin, çıkarımdan en son çıkışa erişir.

Bir OpenGL bağlamına aynı anda birden fazla iş parçacığı tarafından erişilemez. Ayrıca, aynı iş parçacığında etkin GL bağlamının değiştirilmesi bazı Android cihazlarda kullanabilirsiniz. Bu nedenle, yaklaşımımız herkesin ihtiyaçlarına görebilirsiniz. Her iş parçacığı, GL komutları yayınlayarak seri komut sırası oluşturur bu işlem, daha sonra GPU tarafından eşzamansız olarak yürütülür.

GPU Hesap Makinesinin Ömrü

Bu bölümde, GPU'ya ait Process yönteminin temel yapısı açıklanmaktadır. GlBasit Hesaplayıcı temel sınıftan türetilen hesap makinesi. GPU hesaplayıcı Örnek olarak LuminanceCalculator gösterilmektedir. Yöntem LuminanceCalculator::GlRender, GlSimpleCalculator::Process numarasından çağrılıyor.

// 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();
}

Yukarıda belirtilen tasarım ilkeleri şu tasarımla sonuçlandı: seçenekleri sunar:

  • Resim verilerini temsil eden ve GPU kullanımı için optimize edilmiş GpuBuffer adlı bir GPU veri türümüz vardır. Bu veri türünün tam içerikleri opak ve platforma özgüdür.
  • GPU'dan yararlanmak isteyen her hesaplayıcının GlCalculatorHelper sınıfının bir örneğini oluşturup sahip olduğu, bileşime dayalı alt düzey bir API. Bu sınıf, OpenGL bağlamını yönetmek, giriş ve çıkışlar için dokular ayarlamak vb. işlemler için platformdan bağımsız bir API sunar.
  • Resim filtrelerini uygulayan basit hesap makinelerinin GlSimpleCalculator ve özel OpenGL kodlarıyla yalnızca birkaç sanal yöntemi geçersiz kılmasının gerektiği, alt sınıfa dayalı üst sınıf bir API. Tüm tesisat işleri ise üst sınıf tarafından halledilir.
  • Tüm GPU tabanlı hesap makineleri arasında paylaşılması gereken veriler, grafik hizmeti olarak uygulanmış ve GlCalculatorHelper sınıfı tarafından yönetilen harici bir giriş olarak sağlanır.
  • Hesap makinesine özgü yardımcıların ve paylaşılan bir grafik hizmetinin kombinasyonu, GPU kaynağını yönetme konusunda bize büyük esneklik sağlar: Her hesap makinesi için ayrı bir bağlama sahip olabilir, tek bir bağlamı paylaşabilir, bir kilit veya diğer temel senkronizasyon öğelerini paylaşabiliriz vb. bunların hepsi yardımcı tarafından yönetilir ve bağımsız hesaplayıcılardan gizlenebilir.

GpuBuffer - ImageFrame Dönüştürücüler

GpuBufferToImageFrameCalculator ve ImageFrameToGpuBufferCalculator adında iki hesap makinesi sunuyoruz. Bu hesap makineleri ImageFrame ile GpuBuffer arasında dönüştürme yaparak GPU ve CPU hesap makinelerini birleştiren grafiklerin oluşturulmasına olanak tanır. Bunlar hem iOS hem de Android'de desteklenir

Mümkün olduğunda bu hesaplayıcılar, kopyalama yapmadan CPU ile GPU arasında veri paylaşmak için platforma özel işlevler kullanır.

Aşağıdaki şemada, kameradan video kaydeden, bunu bir MediaPipe grafiğinde çalıştıran ve sonucu ekranda gerçek zamanlı olarak oluşturan bir mobil uygulamadaki veri akışı gösterilmektedir. Kesikli çizgi, MediaPipe grafiğinde hangi bölümlerin uygun olduğunu gösterir. Bu uygulama, OpenCV kullanarak CPU üzerinde bir Canny kenar algılama filtresi çalıştırır ve GPU'yu kullanarak bunu orijinal videonun üzerine yerleştirir.

GPU hesaplayıcıları nasıl etkileşime girer?

Kameradan alınan video kareleri, grafiğe GpuBuffer paketler halinde aktarılır. İlgili içeriği oluşturmak için kullanılan giriş akışına paralel olarak iki hesap makinesi tarafından erişilir. GpuBufferToImageFrameCalculator, tamponu bir ImageFrame biçimine dönüştürür. Bu daha sonra, gri tonlamalı bir dönüştürücü ve bir canny filtresi üzerinden (hem çalıştırıldığından) emin olun. Bu işlemin çıkışı daha sonra bir GpuBuffer tekrar. Çok girişli bir GPU hesaplayıcı olan GlOverlayCalculator Hem orijinal GpuBuffer hem de kenar dedektöründen çıkanı girin, ve gölgelendirici kullanarak üst üste bindirebilir. Çıkış, daha sonra geri arama hesaplayıcısı kullanan bir uygulamayla oluşturulan bir uygulamadır; uygulama, ekrana getirelim.