提出我的问题:
我正在编写一个自定义卷积(用于 CNN),其中任意大小的 HxWxD 输入体积与 FxFxD 滤波器卷积。D 可以是 3 或 4,但也可以更多。我是 RenderScript 的新手,目前正在研究可能创建一个可以在未来使用的框架的方法,所以我不想最终以一种可能很快会弃用的方式使用 API。我现在的目标是 23,但可能需要在某个时候回到 18-19,这有待讨论。
看来,如果我定义一个 3D 分配并使用浮点作为内核中参数的类型,内核也会沿 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 个输出:
xy: {0.000000, 0.000000, 0.000000} xy: {1.000000, 0.000000, 0.000000} ... xy: {0.000000, 0.000000, 1.000000} xy: {1.000000, 0.000000, 1.
等等
该模式重复 3x25 次。
OTOH 参考不清楚 z 坐标,renderscript 的答案:访问“z”坐标表示不支持 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 及以后的版本我们只能绑定一维分配,这与我的结果相矛盾。
那里有很多相互矛盾和过时的信息,所以我希望内部有人可以对此发表评论,并从可持续性和最优性的角度推荐一种方法。
(1) 我应该继续使用传递的 xyz 坐标来计算具有绑定 3D 分配的卷积吗?或者这种方法会在某个时候被弃用吗?
(2) 还有其他方法可以做到这一点,例如我可以将所有分配重塑为一维,将它们传递到内核并使用索引算法。这也将允许将某些值彼此靠近。另一种方法可能是将输入的 3D 体积细分为深度为 4 的块,并在类型中使用 float4。假设(1)可以使用,从优化的角度来看,与其他方法相比,使用(1)是否有缺点?
(3) 一般而言,是否存在理想的内存布局公式,例如,出于优化原因,将问题重新表述为 float3 或 float4 深度,而不是像 (1) 这样的“直截了当”的方法?