我是在MXNet中编写C ++自定义运算符,但在运算符调用中设置kAddTo
时很难找到文档。作为一个最小的例子,假设我的新运算符被称为foo()
,我想执行以下计算:
A = mx.sym.Variable('A')
B = mx.sym.Variable('B')
T = mx.sym.foo(A)
T += mx.sym.foo(B)
一般情况下,如何确保上面的第四行累积到T而不是为mx.sym.foo(B)
的结果创建新的临时存储,然后执行T = T + temp
计算?
(使用Kernighan-Ritchie调试器,也就是打印语句,我发现在第3行和第4行都设置了kWriteTo
。永远不会设置枚举kAddTo
。)
关于我的具体问题的更多详细信息:在我当前的实现中foo()
在执行计算之前将输出内存清零,并使用适当的值填充它。我绝对只想在创建新的输出位置时执行此归零,而不是在累积到现有输出位置时执行此归零。
更新
离线,一位同事建议使用
mx.sym.elemwise_add(lhs=T, rhs=mx.sym.foo(B), out=T)
代替上面第4行。但是,我仍然看到kWriteTo
在两个计算行中都被设置了。然后我收到了以下回复:
“内存规划和就地操作是自动的。它将自动完成。用户无需担心。“,这可能意味着
req[0]
在这种情况下不是准确的指标。如果您想验证它是否为就地addTo,您可以打印出outputs[0].dptr_
和lhs.dptr_
的值,看看它们是否相等。
我还没有检查过这个。
答案 0 :(得分:1)
操作员无法控制将在哪种模式下执行。问题是,只有图优化器知道使用运算符的上下文,并且如果运算符需要在kWriteTo
或kAddTo
中执行,则可以做出决定。更确切地说,这发生here in the method DetectInplaceAddTo。即使在某些情况下它已在kAddTo
中执行,由于优化计算图的逻辑发生变化,将来可能会改变此行为。
“内存规划和就地操作是自动的。将会完成 自动。用户无需担心。“
这意味着操作员无法控制它执行的模式,但是操作符必须严格遵守已请求的模式(kWriteTo
或kAddTo
)。例如,如果模式为kWriteTo
且操作员尝试将diff添加到输出,而不是覆盖其中的内容,则会导致不可预测的结果,因为输出可能会填充垃圾。另一方面,如果模式为kAddTo
但是操作员不支持它可能会更糟,因为,不是将结果添加到输出,它只会覆盖输出(这样的情况通常非常难以调试)。这会不时导致this one等错误。
简而言之:
一般情况下,我如何确保上面的第四行累积 进入T而不是为结果创建新的临时存储 mx.sym.foo(B)然后执行T = T + temp计算?
你不能,这不是运营商决定执行哪种模式。即使配置使用模式kAddTo
和未来版本的MXNet。同样在将来,可能会创建新的API以向图形优化器(或建议)发送提示以使用特定模式。但我不知道这种发展。
现在的问题是:“MXNet 0.10 / 0.11将在哪种特殊情况下使用kAddTo
”?
通过查看following code:
,这很棘手 for (uint32_t nid = 0; nid < idx.num_nodes(); ++nid) {
const auto& inode = idx[nid];
if (inode.source->op() != ewise_plus_op) continue; // <= HERE
int sid = storage_id[idx.entry_id(inode.inputs[0])];
kAddTo
似乎仅在_grad_add
期间使用,这很难过。这也许是一个错误,因为可能代替:
static const Op* ewise_plus_op = Op::Get("_grad_add");
实际意图是:
static const Op* ewise_plus_op = Op::Get("elemwise_add");