| 70 | class BinaryGrad : public OpGrad { |
| 71 | public: |
| 72 | virtual std::vector<Express::VARP> onGrad(Express::EXPRP expr, |
| 73 | const std::vector<Express::VARP>& backwardOutput) override { |
| 74 | std::vector<VARP> res; |
| 75 | auto inputs = expr->inputs(); |
| 76 | res.resize(inputs.size()); |
| 77 | auto op = expr->get(); |
| 78 | auto outputDiff = backwardOutput[0]; |
| 79 | std::vector<VARP> output(expr->outputSize()); |
| 80 | for (int i = 0; i < expr->outputSize(); ++i) { |
| 81 | output[i] = Variable::create(expr, i); |
| 82 | } |
| 83 | int activateType = op->main_as_BinaryOp()->activationType(); |
| 84 | if (activateType == 1) { // relu |
| 85 | auto mask = _Cast<float>(_Greater(output[0], _Scalar(0.0f))); |
| 86 | outputDiff = mask * backwardOutput[0]; |
| 87 | } |
| 88 | switch (op->main_as_BinaryOp()->opType()) { |
| 89 | case BinaryOpOperation_ADD: { |
| 90 | res[0] = outputDiff; |
| 91 | res[1] = outputDiff; |
| 92 | break; |
| 93 | } |
| 94 | case BinaryOpOperation_SUB: { |
| 95 | res[0] = outputDiff; |
| 96 | res[1] = _Negative(outputDiff); |
| 97 | break; |
| 98 | } |
| 99 | case BinaryOpOperation_MUL: { |
| 100 | res[0] = outputDiff * inputs[1]; |
| 101 | res[1] = outputDiff * inputs[0]; |
| 102 | break; |
| 103 | } |
| 104 | case BinaryOpOperation_MAXIMUM: { |
| 105 | auto mask0 = _Sign(inputs[0] - output[0]) + _Const(1.0f, {}, NCHW); |
| 106 | auto mask1 = _Sign(inputs[1] - output[0]) + _Const(1.0f, {}, NCHW); |
| 107 | auto maskSum = mask0 + mask1; |
| 108 | res[0] = outputDiff * mask0 / maskSum; |
| 109 | res[1] = outputDiff * mask1 / maskSum; |
| 110 | break; |
| 111 | } |
| 112 | case BinaryOpOperation_MINIMUM: { |
| 113 | auto mask0 = _Sign(output[0] - inputs[0]) + _Const(1.0f, {}, NCHW); |
| 114 | auto mask1 = _Sign(output[0] - inputs[1]) + _Const(1.0f, {}, NCHW); |
| 115 | auto maskSum = mask0 + mask1; |
| 116 | res[0] = outputDiff * mask0 / maskSum; |
| 117 | res[1] = outputDiff * mask1 / maskSum; |
| 118 | break; |
| 119 | } |
| 120 | case BinaryOpOperation_REALDIV: { |
| 121 | res[0] = _Divide(outputDiff, inputs[1]); |
| 122 | // d (u / v) = dx / v , -dx*u(1/v)*(1/v) |
| 123 | res[1] = _Negative(_Multiply(outputDiff, _Divide(output[0], inputs[1]))); |
| 124 | break; |
| 125 | } |
| 126 | case BinaryOpOperation_POW: { |
| 127 | // d (pow(x, y)) = dv * pow(x, y) / x * y , dv * pow(x, y) * ln(x) |
| 128 | res[0] = outputDiff * output[0] * OpGrad::divideAvoidZero(inputs[1], inputs[0]); |
| 129 | res[1] = outputDiff * output[0] * _Log(inputs[0]); |
nothing calls this directly
no test coverage detected