我在理解批量加载方面遇到一些困难,如引用的评论中所述。为了计算像素中的卷积,大小为5的掩模必须以该特定像素为中心。图像被分为图块。应用卷积蒙版后的这些图块是最终输出图块,其大小为TILE_WIDTH*TILE_WIDTH
。对于属于输出图块边框的像素,当此图块属于图像的边框时,图像必须从相邻图块借用一些像素。否则,这些借来的值被赋值为零。
if (srcY >= 0 && srcY < height && srcX >= 0 && srcX < width)
N_ds[destY][destX] = I[src];
else
N_ds[destY][destX] = 0;
因此,共享内存阵列的每一侧都有TILE_WIDTH + Mask_width - 1
个维度。我不清楚代码的以下部分。
destY
和destX
索引。
将输出索引除以输入切片宽度意味着什么? srcY
添加srcX
索引。
为什么destY
和destX
索引参与srcY
添加srcX
索引?
srcY = blockIdx.y * TILE_WIDTH + destY - Mask_radius;
srcX = blockIdx.x * TILE_WIDTH + destX - Mask_radius;
TILE_WIDTH * TILE_WIDTH
? 编辑:已添加图片。在绿色中有输出瓦片,在红色中我们有掩模以114索引为中心。很明显,面具借用了不同瓷砖的元素。 最后,此图像指的是一个频道。
示例:根据下图,我试图写一个例子。输出图块具有基于blockIdx.x=1
和blockIdx.y=1
的{{1}}和destY=0
。也,
destX=0
,srcY = 1*6+0-3=3
和srcX = 3
。根据计算和图像示例,我们没有匹配。在第一个共享内存位置中,应存储的值是全局索引src = (3*18+3)*3+0=171
。上述计算有什么问题?有人可以帮忙吗?
57
答案 0 :(得分:7)
您的问题在概念上类似于我在StackOverflow上的第一个问题:Moving a (BS_X+1)(BS_Y+1) global memory matrix by BS_XBS_Y threads。
您遇到以下问题:大小为TILE_WIDTHxTILE_WIDTH
的每个线程块应填充大小为(TILE_WIDTH + Mask_width - 1)x(TILE_WIDTH + Mask_width - 1)
的共享内存区域。
4)一般来说,有两次加载的直观解释是什么?
由于共享内存区(TILE_WIDTH + Mask_width - 1)x(TILE_WIDTH + Mask_width - 1)
大于块大小TILE_WIDTHxTILE_WIDTH
并假设它小于2xTILE_WIDTHxTILE_WIDTH
,因此每个线程最多应将两个元素从全局内存移动到共享记忆。这就是你加载两个阶段的原因。
1)
destY
和destX
索引。将输出索引除以输入切片宽度意味着什么?
这涉及第一个加载阶段,它被指定从全局内存加载TILE_WIDTHxTILE_WIDTH
个元素并填充共享内存区域的最上部分。
所以,操作
dest = threadIdx.y * TILE_WIDTH + threadIdx.x;
在
时展平通用线程的2D坐标destX = dest % w;
destY = dest / w;
进行逆运算,因为它计算通用线程相对于共享内存区域的2D坐标。
2)
srcY
添加srcX
索引。为什么destY
和destX
索引参与srcY
添加srcX
索引?
srcY = blockIdx.y * TILE_WIDTH + destY - Mask_radius;
srcX = blockIdx.x * TILE_WIDTH + destX - Mask_radius;
如果块大小和共享内存大小相同,则 (blockIdx.x * TILE_WIDTH, blockIdx.y * TILE_WIDTH)
将是全局内存位置的坐标。由于您也是从neighboor tile中“借用”内存值,因此您必须将上述坐标移动(destX - Mask_radius, destY - Mask_radius)
。
3)为什么在第二次加载时我们使用偏移量TILE_WIDTH * TILE_WIDTH?
您有此偏移量,因为在第一个内存阶段,您已经填充了共享内存的“第一个”TILE_WIDTHxTILE_WIDTH
位置。
修改强>
下图说明了扁平线程索引dest
与共享内存位置之间的对应关系。在图片中,蓝色框表示通用图块的元素,而红色框表示邻居图块的元素。蓝色和红色框的并集对应于整个共享内存位置。如您所见,线程块的所有256
个线程都涉及在绿线上方填充共享内存的上半部分,而填充共享的下半部分只涉及145
记忆在绿线下面。现在您还应该了解TILE_WIDTH x TILE_WIDTH
偏移量。
请注意,由于特定的参数选择,每个线程最多有2
个内存加载。例如,如果你有TILE_WIDTH = 8
,那么线程块中的线程数是64
,而共享内存大小是12x12=144
,这意味着每个线程负责执行自2
以来至少 144/64=2.25
共享内存写入。