首页 文章

自定义MXNet操作员和kAddTo

提问于
浏览
3

我是在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调试器,也就是打印语句,我发现 kWriteTo 在第3行和第4行都设置了 . 枚举 kAddTo 永远不会被设置 . )

关于我的具体问题的更多细节:在我当前的实现中 foo() 在执行计算之前将输出内存清零,并使用适当的值填充它 . 我绝对只想在创建新输出位置时执行此归零,而不是在累积到现有输出位置时执行此归零 .

Update

离线,一位同事建议使用

mx.sym.elemwise_add(lhs=T, rhs=mx.sym.foo(B), out=T)

代替上面第4行 . 但是,我仍然看到 kWriteTo 正在两个计算行中设置 . 然后我收到了以下回复:

“内存规划和就地操作是自动的 . 它将自动完成 . 用户无需担心它 . “,这可能意味着req [0]在这种情况下不是一个准确的指标 . 如果要验证它是否为就地addTo,可以打印输出[0] .dptr_和lhs.dptr_的值以查看它们是否相等 .

我还没检查过这个 .

1 回答

  • 1

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

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

    这意味着操作员无法控制执行的模式,但操作员必须严格遵守已请求的模式( kWriteTokAddTo ) . 例如,如果模式是 kWriteTo 并且操作员尝试将diff添加到输出,而不是覆盖其中的内容,则会导致不可预测的结果,因为输出可能会填充垃圾 . 另一方面,如果模式是 kAddTo 但操作员不支持它可能会更糟,因为,不是将结果添加到输出,它将覆盖输出(这样的情况通常很难调试) . 这会不时地导致像this one这样的错误 .

    简而言之:

    通常,如何确保上面的第四行累积到T中,而不是为mx.sym.foo(B)的结果创建新的临时存储,然后执行T = T临时计算?

    你不能,这不是运营商决定执行哪种模式 . 即使配置使用模式 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");
    

相关问题