自定义MXNet操作员和kAddTo

时间:2017-07-06 22:13:48

标签: mxnet

我是在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_的值,看看它们是否相等。

我还没有检查过这个。

1 个答案:

答案 0 :(得分:1)

操作员无法控制将在哪种模式下执行。问题是,只有图优化器知道使用运算符的上下文,并且如果运算符需要在kWriteTokAddTo中执行,则可以做出决定。更确切地说,这发生here in the method DetectInplaceAddTo。即使在某些情况下它已在kAddTo中执行,由于优化计算图的逻辑发生变化,将来可能会改变此行为。

  

“内存规划和就地操作是自动的。将会完成   自动。用户无需担心。“

这意味着操作员无法控制它执行的模式,但是操作符必须严格遵守已请求的模式(kWriteTokAddTo)。例如,如果模式为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");