| 15 | class EltwiseGrad : public OpGrad { |
| 16 | public: |
| 17 | virtual std::vector<Express::VARP> onGrad(Express::EXPRP expr, |
| 18 | const std::vector<Express::VARP>& backwardOutput) override { |
| 19 | std::vector<VARP> res; |
| 20 | auto inputs = expr->inputs(); |
| 21 | res.resize(inputs.size()); |
| 22 | auto op = expr->get(); |
| 23 | auto outputDiff = backwardOutput[0]; |
| 24 | switch (op->main_as_Eltwise()->type()) { |
| 25 | case MNN::EltwiseType_SUM: { |
| 26 | for (int i = 0; i < res.size(); ++i) { |
| 27 | res[i] = outputDiff; |
| 28 | } |
| 29 | break; |
| 30 | } |
| 31 | case MNN::EltwiseType_SUB: { |
| 32 | res[0] = outputDiff; |
| 33 | auto negDiff = _Negative(outputDiff); |
| 34 | for (int i = 1; i < res.size(); ++i) { |
| 35 | res[i] = negDiff; |
| 36 | } |
| 37 | break; |
| 38 | } |
| 39 | case MNN::EltwiseType_PROD: { |
| 40 | for (int i = 0; i < res.size(); ++i) { |
| 41 | std::vector<VARP> prods{outputDiff}; |
| 42 | for (int j = 0; j < inputs.size(); ++j) { |
| 43 | if (j == i) { |
| 44 | continue; |
| 45 | } |
| 46 | prods.emplace_back(inputs[j]); |
| 47 | } |
| 48 | std::unique_ptr<OpT> eltOp(new OpT); |
| 49 | eltOp->type = OpType_Eltwise; |
| 50 | eltOp->main.type = OpParameter_Eltwise; |
| 51 | eltOp->main.value = new EltwiseT; |
| 52 | eltOp->main.AsEltwise()->type = EltwiseType_PROD; |
| 53 | res[i] = Variable::create(Expr::create(eltOp.get(), prods)); |
| 54 | } |
| 55 | break; |
| 56 | } |
| 57 | case MNN::EltwiseType_MAXIMUM: { |
| 58 | for (int i = 0; i < inputs.size(); ++i) { |
| 59 | auto mask = _Sign(inputs[i] - Variable::create(expr, 0)) + _Const(1.0f, {}, NCHW); |
| 60 | res[i] = mask * outputDiff; |
| 61 | } |
| 62 | break; |
| 63 | } |
| 64 | default: |
| 65 | return res; |
| 66 | } |
| 67 | return res; |
| 68 | } |
| 69 | }; |
| 70 | class BinaryGrad : public OpGrad { |
| 71 | public: |