我已经在几个张量流层的标准操作中看到过(例如https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/kernels/maxpooling_op_gpu.cu.cc),代码CUDA_1D_KERNEL_LOOP(索引,nthreads)作为前向和后向传递的一部分......
我认为"指数"这里与底部特征地图坐标有某种关系,但我不确定它的确切含义......有谁可以提供帮助?
答案 0 :(得分:5)
CUDA_1D_KERNEL_LOOP(i, n)
是tensorflow/core/util/cuda_kernel_helper.h
中定义的预处理器宏。它提供了一个通用控制流语句,用于Tensorflow代码库中的许多Cuda内核。
该语句通常用于迭代内核中数组的元素。参数i
是控制变量的名称,参数n
是控制语句的停止条件。 Cuda内核以并行线程启动。每个线程通常在数组元素的子集上操作。宏为访问所需的数组元素提供了一些便利。
在您链接到的示例中,CUDA_1D_KERNEL_LOOP(index, nthreads)
被解释为:
for (int index = blockIdx.x * blockDim.x + threadIdx.x; index < nthreads; index += blockDim.x * gridDim.x)
因此,在进入后续代码块之前,index
在CUDA_1D_KERNEL_LOOP
内被声明并初始化。 index
的确切含义取决于它在代码块中的使用方式。
答案 1 :(得分:0)
当我第一次阅读这个宏时,让我困惑的一件事是,“为什么它是一个循环,这不是内核已经并行化了吗?”答案是,当你拥有比GPU实际支持的更多“线程”时,循环处理这种情况。
例如,假设您正在进行并行向量添加,并且您已经决定对于GPU,每个块将使用512个线程,最多安排4096个块(这些是Caffe2中的默认参数)。这意味着您最多只能安排2097152个线程。假设你的矢量实际上有4M个元素;现在你无法为每个元素分配一个线程。因此每个线程必须负责对向量中的多个元素求和:这就是这个循环的用途!
这是一个较小的示例,它精确地描述了工作最终如何安排。假设blockDim.x == 2
,gridDim.x == 2
和nthreads == 7
。然后,如果我们将GPU线程标识为(blockIdx.x, threadIdx.x)
,我们会分配它们以对向量执行以下工作:[(0,0), (0,1), (1,0), (1,1), (0,0), (0,1), (1,0)]
。特别是,我们可以看到,根据网格大小,只有四个GPU线程可用;因此,对于blockIdx.x == 0
threadIdx.x == 0
,index
将处理两个0
和4
处的向量元素。