總覽
MediaPipe 支援 GPU 運算和算繪的計算機節點,可結合多個 GPU 節點,以及與以 CPU 為基礎的計算工具節點混用。行動平台有多種 GPU API (例如 OpenGL ES、 Metal 和 Vulkan)。MediaPipe 未嘗試提供單一跨 API GPU 抽象化機制。個別節點可以使用不同的 API 編寫,以便視需要運用平台專屬功能。
GPU 支援是行動平台效能的重要關鍵,特別是即時影片。MediaPipe 可讓開發人員編寫支援 GPU 的與 GPU 相容計算機,可用於:
- 裝置端即時處理,不只是批次處理
- 影片算繪和效果,不只是分析
以下是 MediaPipe 中 GPU 支援的設計原則
- 應該能運用 GPU 式計算機在圖表中的任何位置,不一定要用於在螢幕上轉譯。
- 將影格資料從某 GPU 式計算機轉移至另一個,應該很快就能轉移,而且不會產生高成本的複製作業。
- 在 CPU 和 GPU 之間傳輸影格資料的方式也應符合平台允許的效率。
- 由於不同平台可能需要採用不同技術才能達到最佳效能,因此這個 API 應讓幕後實作方式有彈性。
- 使用 GPU 進行所有或部分作業時,應允許以最大彈性的方式使用計算機,並在必要時將 GPU 與 CPU 合併使用。
OpenGL ES 支援
MediaPipe 支援 Android/Linux 至 3.2 以上版本的 OpenGL ES 和 ES 3.0 最高版本 。此外,MediaPipe 也支援 iOS 上的金屬。
需要 OpenGL ES 3.1 以上版本 (在 Android/Linux 系統上) 才能執行 機器學習推論計算機和圖形
MediaPipe 允許在多個 GL 環境中執行 OpenGL。舉例來說 這在結合較慢的 GPU 推論路徑 (例如 10 時) 的圖表中非常有用 每秒影格數 (FPS) 速度較快的 GPU 轉譯路徑 (例如每秒 30 個影格):自一次 GL 內容以來 對應一個連續命令佇列, 工作就會降低轉譯畫面更新率
MediaPipe 使用多種結構定義可解決這個問題的一個挑戰就是 仍可正常使用其中一個例子是內含影片 同時傳送給轉譯和推論路徑,而且轉譯時必須 存取推論的最新輸出內容
無法同時由多個執行緒存取 OpenGL 內容。 此外,在同一個執行緒上切換使用中的 GL 情境可能會速度過慢 部分 Android 裝置。因此,我們的做法 每個情境。每個執行緒都會發出 GL 指令,並建立序列指令佇列 而 GPU 會以非同步方式執行。
GPU 計算工具的生命週期
本節說明 GPU 的處理方法基本結構
基本類別 GlSimpleCalculator 產生的計算機。GPU 計算工具
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 GPU 支援的選項:
- 我們有 GPU 資料類型
GpuBuffer
,用於表示圖片資料,已針對 GPU 用量進行最佳化。這個資料類型的確切內容是不透明且平台專屬。 - 以組合為基礎的低階 API。任何要使用 GPU 的計算機都會建立並擁有
GlCalculatorHelper
類別的執行個體。這個類別提供跨平台通用的 API,可用於管理 OpenGL 環境、設定輸入和輸出的紋理等。 - 以子類別為基礎的高階 API,其中簡單的計算機會從
GlSimpleCalculator
實作圖片篩選器子類別,而且只需要用其特定的 OpenGL 程式碼覆寫幾個虛擬方法,父類別則負責處理所有水管作業。 - 所有 GPU 式計算機之間需要共用的資料,會以外部輸入的形式提供,並以圖表服務的形式實作,並由
GlCalculatorHelper
類別管理。 - 只要結合計算機專用輔助程式和共用圖形服務,我們就能靈活管理 GPU 資源:我們可以為每個計算器有個別的內容、共用單一背景資訊、共用鎖定或其他同步處理基元等。這些功能都是由輔助程式管理,而且不會顯示在個別計算機中。
從 GpuBuffer 到 ImageFrame 轉換器
我們提供兩個名為 GpuBufferToImageFrameCalculator
和 ImageFrameToGpuBufferCalculator
的計算機。這些計算機可在 ImageFrame
和 GpuBuffer
之間轉換,讓您建構結合 GPU 和 CPU 計算的圖形。iOS 和 Android 都支援這些額外資訊
在可能的情況下,這些計算機會使用平台專屬功能,在 CPU 和 GPU 之間共用資料,而無需複製。
下圖顯示行動應用程式中的資料流程。這個應用程式會擷取相機中的影片、透過 MediaPipe 圖表執行資料,並在螢幕上即時算繪輸出內容。虛線表示 MediaPipe 圖表中的哪些部分正確。這個應用程式會使用 OpenCV 在 CPU 上執行 Canny 邊緣偵測篩選器,並使用 GPU 覆蓋在原始影片上方。
攝影機的視訊畫面會以 GpuBuffer
封包的形式輸入至圖表中。
輸入串流是由兩個計算機同時存取。
GpuBufferToImageFrameCalculator
會將緩衝區轉換為 ImageFrame
。
然後透過灰階轉換器和 Canny 篩選器傳送
並在 CPU 上執行) 之後,其輸出內容會轉換成
GpuBuffer
。多輸入 GPU 計算機 GlOverlayCalculator
系統會同時輸入原始 GpuBuffer
和邊緣偵測工具以外的值
並使用著色器疊加這些元素接著,系統會將輸出內容傳回
自訂回呼功能,而應用程式則會
使用 OpenGL。