构建我的问题:
我正在编写自定义卷积(对于CNN),其中任意大小的HxWxD输入音量与FxFxD滤波器进行卷积。 D可以是3或4但也可以更多。我是RenderScript的新手,目前正在调查方法,目标是创建一个可以在将来使用的框架,因此我不想以最近可能会弃用的方式使用API。我现在正以23为目标,但可能需要在某个时候回到18-19,这需要讨论。
看来如果我定义一个3D Allocation并使用float作为内核中in-parameter的类型,内核会访问每个元素,也会沿着Z轴。像这样:
内核:
void __attribute__((kernel)) convolve(float in, uint32_t x, uint32_t y, uint32_t z){
rsDebug("x y z: ", x, y, z);
}
爪哇:
Allocation in;
Type.Builder tb = new Type.Builder(mRS, Element.F32(mRS));
Type in_type = tb.setX(W).setY(H).setZ(D).create();
in = Allocation.createTyped(mRS, in_type);
//...
mKonvoScript.forEach_convolve(in);
当W = H = 5且D = 3时,3D体积中有75个浮点数。运行程序打印75个输出:
x y:{0.000000,0.000000,0.000000} x y:{1.000000,0.000000,0.000000} ... x y:{0.000000,0.000000,1.000000} x y:{1.000000,0.000000,1.000000} ...
等
模式重复3x25次。
OTOH参考不清楚z坐标,renderscript: accessing 'z' coordinate的答案表明不支持z坐标参数。
此外,我还需要将过滤器绑定到内核中的rs_allocation变量。现在我有:
内核:
rs_allocation gFilter;
//...
float f = rsGetElementAt_float(gFilter, 1,2,3);
爪哇:
Allocation filter;
Type filter_type = tb.setX(F).setY(F).setZ(D).create();
filter = Allocation.createTyped(mRS, filter_type);
这似乎运行良好(没有编译或运行时错误)。但是从2014年开始有一个SE条目,表明从版本20开始,我们只能绑定1D分配,这与我的结果相矛盾。
那里有很多矛盾和过时的信息,所以我希望内部有人可以对此发表评论,并从可持续性和最优性的角度推荐一种方法。
(1)我应该继续使用传递的xyz坐标来计算带有绑定3D分配的卷积吗?或者这种方法会在某个时候被弃用吗?
(2)还有其他方法可以做到这一点,例如我可以将所有分配重新整形为1D,将它们传递给内核并使用索引算术。这也允许将某些值彼此接近。另一种方法可能是将输入的3D体积细分为深度为4的块,并使用float4作为类型。假设(1)可以使用,从优化的角度来看,使用(1)与其他方法相比是否存在缺点?
(3)一般来说,是否存在理想的存储器布局公式,例如为了最优原因将问题重新表述为float3或float4深度,而不是直接的"方法如(1)?
答案 0 :(得分:2)
1)现在支持z作为您可以查询的坐标,因此我的旧答案已过时。这也是为什么上面的示例代码不会生成编译器错误(假设您的目标是相对现代的API级别)。
2)即使对于1D事物也停止使用bind()(这是我们现在唯一支持的事情,但即使这不是一个很好的技术)。您可以在.rs文件中使用rs_allocation作为全局变量,使用Java中的set_ ()来获得对这些全局分配的等效访问。然后使用相应类型的rsGetElementAt _ ()和rsSetElementAt _ *()直接在.rs文件中读/写。
3)进行这样的内存布局优化对某些设备有益,而对其他设备则更糟。如果您可以使用常规的x / y / z API,那么这些API将为实现提供有效布局的最佳机会。