[英]Method to do final sum with reduction
我接受了在這個鏈接上解釋的第一個問題的延續。
我提醒你,我想應用一種能夠用OpenCL進行多次減少的方法(我的GPU設備只支持OpenCL 1.2)。 我需要計算一個數組的總和減少來檢查主循環的每次迭代的收斂標准,
目前,我只做了一次減少(即一次迭代)的版本。 在這個版本中,為簡單起見,我使用了一個順序CPU循環來計算每個部分和的總和並得到sum的最終值。
根據我在先例中的建議,我的問題是我不知道如何通過再次調用NDRangeKernel
函數(即第二次執行內核代碼)來執行最終總和。
實際上,通過第二次調用,我總是會遇到同樣的問題,即獲得部分和的總和(本身是從第一次調用NDRangeKernel
計算出來的):它似乎是一個遞歸問題。
讓我們從上圖中舉例說明:如果輸入數組大小為10240000
且WorkGroup size
為16
,則得到10000*2^10/2^4 = 10000*2^6 = 640000 WorkGroups
。
所以在第一次調用之后,我獲得了640000 partial sums
:如何處理所有這些部分總和的最終結果? 如果我再次調用內核代碼,例如WorkGroup size = 16
和global size = 640000
,我將得到nWorkGroups = 640000/16 = 40000 partial sums
,所以我必須再次調用內核代碼並重復此過程直到nWorkGroups < WorkGroup size
。
也許我不太了解第二階段,大部分內核代碼來自“兩階段縮減”( 在此鏈接上,我認為這是搜索輸入數組的最小值的情況 )
__kernel
void reduce(__global float* buffer,
__local float* scratch,
__const int length,
__global float* result) {
int global_index = get_global_id(0);
float accumulator = INFINITY;
// Loop sequentially over chunks of input vector
while (global_index < length) {
float element = buffer[global_index];
accumulator = (accumulator < element) ? accumulator : element;
global_index += get_global_size(0);
}
// Perform parallel reduction
...
如果有人能夠解釋上面代碼片段內核代碼的作用。
是否與第二階段的減少有關系,即最終的結果?
如果您不了解我的問題,請隨時向我詢問更多詳細信息。
謝謝
如評論中所述:聲明
如果輸入數組大小為10240000且WorkGroup大小為16,則得到10000 * 2 ^ 10/2 ^ 4 = 10000 * 2 ^ 6 = 640000個工作組。
是不正確的。 您可以選擇“任意”工作組大小和“任意”數量的工作組。 這里選擇的數字可以針對目標設備定制。 例如,設備可能具有某種本地存儲器大小。 可以使用clDeviceGetInfo
查詢:
cl_ulong localMemSize = 0;
clDeviceGetInfo(device, CL_DEVICE_LOCAL_MEM_SIZE,
sizeof(cl_ulong), &localMemSize, nullptr);
考慮到每個工作組將需要的事實,這可用於計算本地工作組的大小
sizeof(cl_float) * workGroupSize
本地內存的字節數。
類似地,工作組的數量可以從其他設備特定參數導出。
關於減少本身的關鍵點是工作組大小不限制可以處理的數組的大小 。 我對整個算法的理解也有些困難,所以我試着在這里解釋一下,希望一些圖像可能勝過千言萬語:
如您所見,工作組的數量和工作組大小是固定的,與輸入數組長度無關:即使我在示例中使用了3個大小為8的工作組(全局大小為24) ,可以處理長度為64的數組。 這主要是由於第一個循環,它只是遍歷輸入數組,其“步長”等於全局工作大小(此處為24)。 其結果將是對於每個24個線程之一累計值。 然后這些並行減小。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.