2018 年 10 月

第 33 卷 10

本文章是由機器翻譯。

GPU 程式設計-使用 Eigenfaces 演算法在 GPU 上的臉部偵測

藉由Kishore Mulchandani

電腦視覺是包含識別的電腦科學的區域或標記的映像中的區域。映像都可以平行操作的像素大型 2d 陣列。Gpu 非常適合用來加速演算法需要大量的資料平行處理原則,[平行處理原則中的資料集的不同部分的一種可以在相同的時間,在多重處理器上操作。因此,它應該是可套用到實作有效率的電腦視覺演算法的工作的 Gpu。在本文中,我將使用 GPU 來實作臉部偵測,電腦視覺中熱門問題。

臉部偵測,正如其名,會探索相片或映像中對應至人類的正面的區域。這是處理套用篩選,或編輯映像中的臉部的應用程式的一個重要的必要條件。自動模糊、 遮罩、 反白顯示和增強是需要知道應修改的像素為單位,以完成此作業的範例。

有數種演算法目前用來偵測的表面,但在本文中,我利用 eigenfaces 方法,其中一種最早發佈的臉部偵測方法。它也是耗用大量運算資源。我的目標是要示範如何使用 Gpu 來加速運算嚴苛的演算法,及在 GPU 上呈現的高階程式設計簡介。

本文假設疐裾類似 C 語言和線性代數和映像處理的一般概念。

Eigenfaces

從線性代數您知道,是否您有 n 維點的集合,您可以找到一些主要元件或特徵向量,這個集合。這些特徵向量也會形成的基礎,這些點的空間。最重要的 eigenvector 是具有最大 eigenvalue 多。任何屬於此集合的新點應該也擁有最重要的 eigenvector 較高的預測值。

Eigenfaces 方法會藉由將臉部的集合轉換成 n 維點繼續。這是將每個二維的映像轉換成一維的向量。整個集合被封裝成一個大型的矩陣,其中每個資料行是 1-D 向量。特徵向量和特徵值位於正方形矩陣乘以含有其調換這個矩陣的格式。探索的點集合的特徵向量也稱為主體元件分析,特徵向量稱為主要元件。

任何臉部偵測演算法的起點是良好的資料庫的臉部。有幾個可在網際網路上,但本文中我使用公開可用 」 標示為面臨在萬用 」 集合 (vis www.cs.umass.edu/lfw)。集合轉換為灰階的衍生項目可供下載conradsanderson.id.au/lfwcrop ,也提供本文所附的下載。這個集合所組成的臉部 13,233 64 x 64 灰階映像。[圖 1顯示映像子集。請注意,所有映像具有已裁剪成包含僅臉部。

前 100 個的映像,加上標籤的臉部百分之八十的資料集
[圖 1 加上標籤的臉部百分之八十的資料集內的前 100 個映像

封裝的矩陣,在矩陣中的每個資料行的資料集,1-D 臉部映像所示**[圖 2**。請注意沿著此映像的資料列符合高層級的濃度。

巨量的矩陣的 4,096 個資料列和 13,233 的資料行調整的表示法
[圖 2 調整巨量矩陣的 4,096 個資料列和 13,233 的資料行的表示法

找到的特徵向量和特徵值之後,最重要的 eigenvector 時機會為 2d 影像看起來像在模糊的臉部**[圖 3**。

巨量的矩陣的第一個 Eigenface
[圖 3 的巨量的矩陣的第一個 Eigenface

一旦計算出第一個 eigenface 之後下, 一步是搜尋測試影像的區域與 eigenface 投影當達到較大的值。這個大型的值,表示測試映像區域和 eigenface 彼此相近的臉部的 n 維空間中。搜尋區域將會開始測試映像的每個像素 64 x 64 像素區域。每個搜尋的搜尋其他開始的像素,意思高層級的資料平行處理原則無關。

如先前所述,Gpu excel 在加速平行計算。但這並不表示應該在 GPU 上實作每個演算法。系統架構仍然會有一個相對比較慢的連線,系統記憶體和 GPU 記憶體之間。需要要處理的資料必須通過 PCI Express 匯流排,甚至是 pci-e 在每個通道第 4 代可以只有最多 32GT/秒,相當多慢傳輸速度比 CPU 和系統記憶體之間傳輸。這表示不能容忍高延遲的應用程式無法在 GPU 上有效地執行。資料集的大小必須大到足以證明的系統記憶體的資料複製到 GPU 記憶體額外負荷,並返回。如果應用程式有相當龐大的工作負載,根據資料大小、 要執行的作業包括類似在本質上,而且執行工作所需的所有資料可以都容納在 GPU 記憶體,GPU 是適合的處理器,應用程式。我將說明,在使用臉部偵測的情況下,為 GPU 適合處理程序中。

臉部偵測演算法有兩個不同的階段。第一個階段包括建立集合的臉部 eigenface 矩陣。這個集合通常不會變更,因為 eigenface 矩陣計算的計算需要一次執行每個集合。第二個階段是投影階段中,在其中測試區域規劃於第一個 eigenface,以查看投影的大小。這個階段通常會很頻繁發生。比方說,在安全性相機應用程式,此階段可能會發生在 30 秒,產生大量的資料框架。影像的解析度也可能非常大,即使是最便宜的網路攝影機現今支援 HD 的解析度。此外,其他的圖形作業,例如模糊或反白顯示,通常執行臉部偵測程式和臉部偵測的結果會在 GPU 上的程式其他部分取用。

因此,第一階段是不適合做為 GPU 的實作,基於它需要用來執行,而兩個階段是極佳的比對 GPU 實作,因為它符合所有準則的低頻率。

下列各節中,我將示範如何執行階段兩個臉部偵測,但首先讓我探討如何程式設計 GPU 不同於在 CPU 上。

程式設計 GPU

程式設計的 GPU 是相當不同的 CPU。Os GPU,會顯示為裝置,並安裝的驅動程式管理的工作,此裝置上執行。為 OS 和 GPU 驅動程式一起運作,可協助完成工作。在最低層級中,一連串命令會傳送至 GPU 裝置透過其命令佇列。命令可能會將狀態設定,CPU 記憶體和 GPU 記憶體和執行程式碼之間複製資料。Gpu 都有自己的指令語言,與 CPU 語言相當不同。幸運的是,不是您需要知道,除非您正在開發 GPU 編譯器的項目。大部分的程式設計人員會使用一或多個 GPU 廠商實作中,請在其驅動程式,例如 Direct3D、 OpenCL 和 OpenGL 的 Api。這些 Api 會隱藏低層級的複雜性,同時提供跨不同廠商和系列的架構的可攜性和相容性。

本文中我選擇使用 OpenCL,支援所有主要的 CPU 和 GPU 供應商的標準。已 OpenCL 周圍自 2009 中,有數個版本,最新正在 2.2 版,並持續發展 (khronos.org/opencl)。注意有關 OpenCL 非常重要的事實是,它可以針對 GPU,不僅 CPU。這是非常大的 plus for OpenCL,因為這表示您可使用的系統上的所有計算資源。基於這個理由,OpenCL 稱為平行程式設計 API 適用於異質系統中。OpenCL 主機程式可以再決定要使用哪些探索的可用性和運算裝置的功能。

幸運的是,程式設計模型和抽象概念都很相似的各種 Api 之間。這表示您應該能夠對應在其他 api 不需要的困難 OpenCL 中學到的概念。現在來探討一下 OpenCL 實作適用於臉部偵測。

設定環境

以進行開發 OpenCL,除了執行階段支援,在 [驅動程式,您需要從適當的廠商 SDK。請參閱本文所附的數位下載中的文件。

因為 OpenCL 是一套開放標準,所以任何廠商可以提供自己針對其硬體最佳化的執行階段版本。

OpenCL 程式設計詞彙是由平台、 裝置和命令佇列所組成。平台相當於系統上可用的實作。裝置是指一種硬體的獨立排程從其他裝置。每部電腦都至少一個 CPU 的裝置。大部分的工作站或遊戲類別電腦會有不連續的 GPU 會列為額外的裝置。高階的工程工作站通常會有多個 Gpu,與其中一個連結至其他項目會保留供計算使用時顯示。每個裝置可以有多個程式將會插入命令的命令佇列。

每個 OpenCL 程式,在主機上,執行會開始探索它執行所在系統的功能。主應用程式會嘗試識別的系統上可用的平台,然後它會列舉裝置。程式可以特別要求的裝置類型,CPU 的裝置類型或 GPU 裝置類型的執行個體。一旦選擇裝置,您可以建立內容,並針對您想要使用每個裝置的命令佇列。以下是一些要執行上述作業 (適用於我已排除的呼叫所需的參數的清晰度) 進行的呼叫:

clGetPlatformIDs(...); // Gets the ids of the platforms available
clGetDeviceIDs(...); // Gets the devices with certain capabilities
clCreateContext(...); // Creates a context on the device
clCreateCommandQueueWithProperties(...); // Creates a command queue with
                                         // certain properties

命令佇列已設定完畢後,主應用程式會建立可以是唯讀、 唯寫或讀寫在裝置上的緩衝區。必須先使用系統記憶體中的資料初始化緩衝區,可用於執行任何有意義的動作:

clCreateBuffer(...);  // Creates a read only buffer on the device
clEnqueueWriteImage(...);  // Queues a buffer copy from the system to
                           // device memory

資料通常是大型緩衝區或整數和浮點值的陣列,而且通常會以非同步方式複製。同樣地建立的緩衝區中的計算結果會儲存在裝置上。OpenCL 具有特殊資料類型,稱為映像。許多密集的工作通常都是來自映像或 3d 的資料集的形式,這些特殊的資料型別很有用。這些類型都支援不同的取樣作業,例如最接近的範例,或平均。

核心的程式,因為它們會參考在 OpenCL 術語中,必須單獨編譯及連結及命令佇列中排入佇列。我稍後會詳述在這方面,如 CPU 程式設計人員可能會納悶為什麼核心會在執行階段編譯:

clCreateProgramWithSource(...); // Create a program from kernel source
clBuildProgram(...); // The program is compiled; errors from compilation
                     // are reported
clCreateKernel(...); // The kernel is created from the program

一旦建立核心,設定核心的引數,和核心然後排入佇列以便在命令佇列中執行:

clSetKernelArg(...); // Set the value of a particular argument
clEnqueueNDRangeKernel(...); // Queue the kernel

隨附的原始程式碼,其中一個進行規劃的 eigenface 上的區域中有兩個核心和其他可尋找本機尖峰投影的結果。投射作業是基本上向量內積。

大數值的內積表示映像中的區域和 eigenface 之間的多個相似之處。這些較大的值或尖峰,可以找到使用第二個核心。由於第二個核心才能使用它們,則第一個核心的結果必須是可用,OpenCL 事件用來同步處理。主應用程式可以使用下列 API 呼叫的一或多個事件上等候:

clWaitForEvents(...);

一旦這兩個核心已在裝置上執行,第二個核心的結果會在裝置緩衝區,然後複製回,它可以用於進一步的主機記憶體。

現在讓我們看看其中一個會在中啟動的核心**[圖 4**。此核心會呼叫每個像素中測試映像。它會開始該像素的區域會先尋找 4,096 維的向量 (64 x 64) 的總和,然後減去的區域的每個像素的總和。然後,它會計算這個區域會傳入做為引數,核心 eigenface 的內積。

[圖 4 OpenCL 核心中測試映像的區域上建立 Eigenface 投影

__kernel void eigenFaceSearch(
    __read_only image2d_t testImage,        // Input test image
    __write_only image2d_t projectionImage, // Output projection image
    int rows,                               // Number of rows in the test image
    int cols,                               // Number of columns in the test image
    __constant float* eigenFace,            // The first eigenface buffer
    sampler_t sampler                       // Sampler for reading the image data
    )
  {
    int myCol = get_global_id(0);           // Column index of test image pixel
    int myRow = get_global_id(1);           // Row index of test image pixel
    float4 dotp = {0.0f, 0.0f, 0.0f, 0.0f}; // Resulting dot project variable
    float4 pixel = {0.0f, 0.0f, 0.0f, 0.0f};// Variable for reading the pixel
    float sum = 0.f;                        // Sum of the pixels in the test region
    float meanVal=0.f;
    float patch[4096];                      // Local buffer to hold the mean
                                            // subtracted region
    int2 myCoords;                          // Local variable for holding current
                                            // pixels coords
    myCoords.x = myCol;                    
    myCoords.y = myRow;
    if (!(( myCol > cols-64) || (myRow > rows - 64))) { // Bounds check
      for (int i = 0; i < 64; i++) { // Loop over every pixel in test region
        int2 coords;
        coords.y = myRow + i;
        for (int j = 0; j < 64; j++) {
          coords.x = myCol + j;
          // Read the pixel at coords, from the test image using the sampler
          pixel = read_imagef(testImage, sampler, coords); 
          patch[i*64+j] = pixel.x;  // Take the first component as it is a single
                                    // float buffer
          sum += patch[i*64+j];     // Accumulate the sum
        } 
  }  
    meanVal = sum / 256.;           // An intensity factor proportional to sum.
    for (int i= 0; i < 4096; i++){  // Remove from each pixel
      patch[i] -= meanVal;          // Per component subtract of intensity factor
    }
    // Perform the dot product
    for (int i= 0; i < 4096; i++){
      dotp.x += patch[i] * eigenFace[i]; // Do the component-wise dot product
    }
    // Write back the dot product into the projection Image
    write_imagef(projectionImage, myCoords, dotp);
  }
}

編譯 OpenCL 核心

如先前所述,OpenCL 編譯器會叫用在執行階段主應用程式。編譯器會提供核心的整個原始程式做為字串。頻繁的核心是相當快速的編譯而不是很小程式碼片段,且除非您的應用程式很容易就能取得結果的每個額外毫秒,您可能不需要了解它。但複雜的應用程式與數百個核心,延遲可能是明顯。幸運的是,中繼語言 (IL) 選項存在,可減少整體的編譯時間。(IL 也有助於保護智慧財產的核心程式碼的內嵌的字串可能會提供專屬的資訊。) 執行階段編譯的核心的優點是,它對應用程式具有恢復功能的硬體中的變更。它是很普遍的 PC 使用者到其電腦的存留期間升級他們的 Gpu。新的 GPU 與新的架構可能會有全新的指令集,離開先行編譯二進位檔,從較舊的 GPU 無法運作。

它拼湊

Eigenface 映像會被預先計算,並提供當作二進位檔案,其中包含以列為主要順序中的單精確度浮點數資料。測試映像也會轉換成浮點數的灰階映像中。測試影像的格式如下:

Height: 4 byte unsigned integer   
  // The number of rows in the image
Width: 4 byte unsigned integer    
  // The number of columns in the image
Intensity Buffer:   Height * width single precision floating point buffer
  // Data buffer

使用這類簡單的格式,很容易產生測試的映像可供我的程式。計算的結果是也儲存為浮點數資料的緩衝區。  此外,會產生文字檔案,包含所面臨的所有矩形的左上角邊角的座標。這項資料可以匯入的任何程式。MATLAB 中儲存資料以供取用 (bit.ly/2isajNJ)。

程式可以輕鬆地修改以 CPU,而不是 GPU 上執行。

執行結果

數個測試映像上執行程式。因為程式碼目前搜尋的比對僅 64 x 64 區域,如果測試影像有更大或較小的臉部,我不能期望它尋找良好。不過,當測試映像沒有 eigenface,大約相同的大小,除非表面會循環,它應該執行良好。我在一個著名的映像上執行的結果所示**[圖 5**。臉部識別使用的第一個 eigenface 上區域的非正規化投影 eigenfaces; 方法。

在第五個 Solvay 會議拍攝採取保留在 1927
[圖 5] 第五個 Solvay 大會的照片拍攝保留在 1927

我收到很多誤判和誤否定。已錯過數個臉部,和許多非表面區域會反白顯示。其中有些是我用來偵測高的值 (尖峰) 投影映像中的本機行程最長搜尋方法的結果。我只會搜尋網路上的芳鄰的 97 x 97 像素數,請參閱 < 是否我就會發現任何較高的值。結果就是數個區域會反白顯示有沒有面但仍然會有較高的值超過其本機網路上的芳鄰。這個方法可以改善時,以減少誤判。 

請記住,結果的品質取決於 [範例映像,其中包括之類的影像解析度、 光源狀況和變化性的強度的品質。

在 [GPU vs OpenCL。CPU

有數個平行處理技術,在 CPU 方面,從 SIMD 的向量化,以明確進行多執行緒處理,以編譯器 pragma OpenMP 樣式平行處理的迴圈中。若要真正比較功能的速度,或具有較高的輸送量簡直是難上加難除非每個可能的技術組合已通過測試與廣泛最佳化實作。話雖如此,它會指定如何輕鬆從一種裝置類型切換到另一個程式碼中,我決定要試試看。

從兩個不同 「 平台。 」 這兩種裝置類型,CPU 和 gpu 方面,與執行程式 系統執行這是遊戲膝上型電腦使用 Intel Core i7-8750 H CPU @2.20 具有 16 GB RAM 與 NVIDIA GeForce GTX 1060 GPU GHz。我無法選擇 CPU 裝置上任何三個平台或上一個來自 NVIDIA GPU 裝置類型。請注意,GPU 廠商可能會提供 CPU 實作以及它 GPU 的實作,在此情況下就比較不容易進行最佳化。

GPU 執行棒的是,如預期般,花費 12 到 21 次,如中所示的 CPU 版本**[圖 6**。分析未包含任何 I/O,但未包含複製系統中的緩衝區,以在裝置記憶體的時間。所有時間都是以毫秒為單位。

GPU 和 CPU Eigenface 搜尋實作時間使用 OpenCL 的比較
[圖 6 比較 GPU 和 CPU Eigenface 搜尋實作時間使用 OpenCL

在核心所撰寫的意圖,以了解並不以取得最佳效能,因此採取這些比較持保留態度。事實上,核心的效能微調是複雜的程序,並在之前部署程式的重要步驟。管線緩衝區複本、 減少在核心中的暫存器的數目和保持一致的記憶體存取是採用最佳化的核心的一些技巧。

事實上,相同的 OpenCL 主機程式可以同時將工作排入佇列的所有系統上可用的不同裝置可讓您表示您可以採用所有這些裝置,以進一步提升輸送量。如果您影片的保全錄影畫面上,執行臉部偵測,比方說,您無法將每個畫面或 subframe 其輸送量按比例不同的裝置佇列之間。系統記憶體和系統匯流排仍共用,並可能會成為瓶頸,因此,不幸的是,您無法藉由新增更多裝置,無限期地調整效能。

特徵的任何項目

這篇文章著重於偵測人的臉部,但是沒有任何可避免這種方法套用至偵測其他的實體或物件。訣竅是收集好一些測試映像,執行某些前置處理,使其大小完全相同,註冊一些主要功能的位置,然後計算特徵向量。一旦已建立特徵向量,搜尋程式碼會維持不變。因此,如果您正在開發程式碼,以偵測應該要充分波蘭文視覺化應用程式的實際操作,可以讓資料庫的實際操作,產生 「 eigenhands",並在搜尋中可能的實際操作的映像。增加擴增的實境應用程式,這類應用程式很可能出現。

總結

對探究 GPU 開發,第一次程式設計師而言,可能會有陡峭的學習曲線,但是,不僅可以非常值得投資。Gpu 有大量的計算能力,可以使用程式設計語言,例如 OpenCL 統馭。這篇文章會介紹 GPU 程式設計,同時示範尋找映像使用 eigenfaces 方法中的臉部的熱門現實世界的問題。這種方法可以延伸到其他的圖形和物件中。


Kishore Mulchandani開發 3d 圖形應用程式,並在 Cpu 和 Gpu 上執行的平行程式碼中的效能改進。高效能運算、 基準測試開發圖形,3d 圖形從 [使用電腦視覺的 2d 影像資料的重新建構,且虛擬實境 edutainment 應用程式的一些他最新的興趣和工作領域能夠一路順風。他可以在觸達Kishore@vanishinglines.com

感謝下列 Microsoft 技術專家來檢閱這篇文章:James McCaffrey, Ravi Shankar Kolli


MSDN Magazine 論壇中的這篇文章的討論