cond_take.cpp 3.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
/**
 * \file src/core/include/megbrain/imperative.h
 *
 * This file is part of MegBrain, a deep learning framework developed by Megvii.
 *
 * \copyright Copyright (c) 2014-2019 Megvii Inc. All rights reserved.
 *
 */

#include "megbrain/imperative/ops/cond_take.h"
#include "megbrain/imperative/ops/opr_attr.h"
#include "megbrain/opr/misc.h"
#include "../dnn_op_helper.h"
#include "../op_trait.h"

using namespace megdnn;

namespace mgb::imperative {

MGB_DYN_TYPE_OBJ_FINAL_IMPL(CondTake);

namespace {

class MegDNNDynOutMallocImpl final: public megdnn::DynOutMallocPolicy {
    using Output = std::array<TensorPtr, 2>;
    
    CompNode m_cn;
    Output m_out;

    public:
        MegDNNDynOutMallocImpl(CompNode cn): m_cn{cn} {}

        megdnn::TensorND alloc_output(
                size_t id, DType dtype, const TensorShape &shape,
                void *user_data) override;

        void* alloc_workspace(size_t sz, void *user_data) override;
        void free_workspace(void *ptr, void *user_data) override;
        TensorPtr at(size_t id);
};

megdnn::TensorND MegDNNDynOutMallocImpl::alloc_output(
        size_t id, DType dtype, const TensorShape &shape,
        void * /*user_data*/) {
    TensorLayout m_layout(shape, dtype);
    m_out[id] = Tensor::make(m_layout, m_cn);
    return m_out[id]->dev_tensor().as_megdnn();
}

void* MegDNNDynOutMallocImpl::alloc_workspace(size_t sz, void * /*user_data*/) {
    return m_cn.alloc_device(sz);
}

void MegDNNDynOutMallocImpl::free_workspace(void *ptr, void * /*user_data*/) {
    m_cn.free_device(ptr);
}

TensorPtr MegDNNDynOutMallocImpl::at(size_t id) {
    return m_out[id];
}

cg::OperatorNodeBase* apply_on_var_node(
        const OpDef& def,
        const VarNodeArray& inputs) {
    def.cast_final_safe<CondTake>();
    auto&& graph = inputs[0]->owner_graph();

    opr::CondTake::Param param;
    param.val = 1;
    cg::OperatorNodeConfig config;
    cg::OperatorNodeBase* opr = graph->insert_opr(
            std::make_unique<opr::CondTake>(
                    inputs[0], inputs[1], param, config));
    return opr;
}

SmallVector<TensorPtr> apply_on_physical_tensor(
        const OpDef& def,
        const SmallVector<TensorPtr>& inputs) {
    auto opr = def.cast_final_safe<CondTake>();
    mgb_assert(opr.same_type<CondTake>());
    mgb_assert(inputs.size() == 2, "CondTake take 2 inputs, got %lu",
               inputs.size());

    auto&& inp = inputs[0];
    auto&& msk = inputs[1];
    mgb_assert(inp->layout().eq_shape(msk->layout()),
               "input shape does not match mask shape");
    mgb_assert(msk->get_value().dtype().enumv() == DTypeEnum::Bool,
               "mask dtype must be bool");
    DnnOprCaller<megdnn::CondTake> dnn_op(inp->comp_node());
    dnn_op.op->param().val = 1;

    TensorLayout m_layout({dnn_op.op->get_workspace_in_bytes(inp->layout())},
                           dtype::Byte());

    auto dnn_workspace = dnn_op.create_workspace(m_layout);
    MegDNNDynOutMallocImpl policy{inp->comp_node()};

    dnn_op.op->exec(inp->dev_tensor().as_megdnn(),
                  msk->dev_tensor().as_megdnn(),
                  dnn_workspace,
                  &policy);

    SmallVector<TensorPtr> out;
    out.push_back(policy.at(0));
    out.push_back(policy.at(1));
    return out;
}

OP_TRAIT_REG(CondTake, CondTake, opr::CondTake)
    .apply_on_var_node(apply_on_var_node)
    .apply_on_physical_tensor(apply_on_physical_tensor)
    .fallback();

} // namespace

} // namespace mgb::imperative