iOS Metal Performance Shaders Image Upsample

时间:2016-09-17 04:42:26

标签: ios gpu metal

对于使用Metal Performance Shader的iOS应用程序,我想为CNN平均池化层反向传播编写GPU加速函数。这几乎与图像上采样相同。例如,如果输入是

2 5 6
3 6 7
8 9 0

Upsampled图片应为

2 2 5 5 6 6
2 2 5 5 6 6
3 3 6 6 7 7
3 3 6 6 7 7
8 8 9 9 0 0
8 8 9 9 0 0

我写了以下内核函数:

kernel void upsample(texture2d<float, access::read> inTexture [[texture(0)]],
                     texture2d<float, access::write> outTexture [[texture(1)]],
                     uint2 gid [[thread_position_in_grid]])
{
    const float4 color = inTexture.read(gid);

    uint2 p;
    p = uint2(gid.x * 2, gid.y * 2);
    outtexture.write(color, p);
    p = uint2(gid.x * 2 + 1, gid.y * 2); 
    outtexture.write(color, p);
    p = uint2(gid.x * 2, gid.y * 2 + 1);
    outtexture.write(color, p);
    p = uint2(gid.x * 2 + 1, gid.y * 2 + 1);  
    outtexture.write(color, p);
}

但我不确定这是否正确。我怎么知道原作&#34; gid&#34;是否与输入纹理中的坐标有关,而与输出纹理无关?

3 个答案:

答案 0 :(得分:0)

你写的内容对我来说是正确的,假设你派出了一个与源纹理尺寸相同的网格。

网格中的线程位置与您读取或写入的坐标之间没有固有的对应关系。 gid只是您使用计算命令编码器调度的工作项网格中的一个点。在你的内核中,你可以随意解释这个。如果您调度2D网格并且正在处理纹理,那么将gid视为一对坐标通常是有意义的,就像您在此处所做的那样。

您也可以自己调度一维网格并将其“包裹”到2D网格中,但使用2D线程位置可以在内核中省去(昂贵的)整数除法,此外还可以更直观。

答案 1 :(得分:0)

@fireman 我描述了你的采样代码,但是逐个编写4个数据需要花费很多。 还有你关于gid的问题。它与输入和输出纹理的内核处理区域的工作项有关。也许它在输入中包含1个像素,包含4个像素用于输出。

答案 2 :(得分:0)

此需求现在由MPSCNNUpsampling系列内核处理。参见MetalPerformanceShaders / MPSCNNUpsampling.h

相关问题