blob: 23ace73fb832d5e5c3888aac5c7144939eba8bdf [file] [log] [blame]
#include "caffe2/operators/leaky_relu_op.h"
#include "caffe2/utils/eigen_utils.h"
#include "caffe2/utils/math.h"
namespace caffe2 {
template <>
bool LeakyReluOp<float, CPUContext>::RunOnDevice() {
const auto& X = Input(0);
auto* Y = Output(0, X.sizes(), at::dtype<float>());
ConstEigenVectorMap<float> Xvec(X.template data<float>(), X.numel());
EigenVectorMap<float> Yvec(Y->template mutable_data<float>(), Y->numel());
Yvec = Xvec.cwiseMax(0.f) + Xvec.cwiseMin(0.f) * alpha_;
return true;
}
template <>
bool LeakyReluGradientOp<float, CPUContext>::RunOnDevice() {
const auto& Y = Input(0);
const auto& dY = Input(1);
auto* dX = Output(0, Y.sizes(), at::dtype<float>());
CAFFE_ENFORCE_EQ(Y.numel(), dY.numel());
ConstEigenVectorMap<float> Yvec(Y.template data<float>(), Y.numel());
ConstEigenVectorMap<float> dYvec(dY.template data<float>(), dY.numel());
EigenVectorMap<float> dXvec(dX->template mutable_data<float>(), dX->numel());
Eigen::VectorXf gtZero = (Yvec.array() >= 0.0f).cast<float>();
dXvec = dYvec.array() * gtZero.array() -
dYvec.array() * (gtZero.array() - 1.0f) * alpha_;
return true;
}
REGISTER_CPU_OPERATOR(LeakyRelu, LeakyReluOp<float, CPUContext>);
REGISTER_CPU_OPERATOR(
LeakyReluGradient,
LeakyReluGradientOp<float, CPUContext>);
OPERATOR_SCHEMA(LeakyRelu)
.NumInputs(1)
.NumOutputs(1)
.Arg("alpha", "*(type: float; default: 0.01)* Coefficient of leakage.")
.AllowInplace({{0, 0}})
.CostInferenceFunction(PointwiseCostInference<2>)
.IdenticalTypeAndShape()
.SetDoc(R"DOC(
The *LeakyRelu* op takes one input tensor $X$ and an argument $alpha$, and produces one output tensor $Y$ of the same shape as $X.$ The op performs the element wise leaky relu operation, defined as
$$y=LeakyRelu(x) =\begin{cases}\alpha x & x < 0\\x & otherwise\end{cases}$$
The default value of *alpha* is 0.01.
Github Links:
- https://github.com/pytorch/pytorch/blob/main/caffe2/operators/leaky_relu_op.h
- https://github.com/pytorch/pytorch/blob/main/caffe2/operators/leaky_relu_op.cc
<details>
<summary> <b>Example</b> </summary>
**Code**
```
workspace.ResetWorkspace()
op = core.CreateOperator(
"LeakyRelu",
["X"],
["Y"],
alpha=0.01
)
workspace.FeedBlob("X", np.random.randn(3, 3).astype(np.float32))
print("X:\n", workspace.FetchBlob("X"), "\n")
workspace.RunOperatorOnce(op)
print("Y:\n", workspace.FetchBlob("Y"))
```
**Result**
```
X:
[[-0.91060215 0.09374836 2.1429708 ]
[-0.748983 0.19164062 -1.5130422 ]
[-0.29539835 -0.8530696 0.7673204 ]]
Y:
[[-0.00910602 0.09374836 2.1429708 ]
[-0.00748983 0.19164062 -0.01513042]
[-0.00295398 -0.0085307 0.7673204 ]]
```
</details>
)DOC")
.Input(0, "X", "Input tensor of data to be operated on.")
.Output(0, "Y", "Output tensor, calculated as described above.");
OPERATOR_SCHEMA(LeakyReluGradient)
.NumInputs(2)
.NumOutputs(1)
.AllowInplace({{1, 0}})
.Arg("alpha", "Coefficient of leakage")
.InheritOnnxSchema()
.IdenticalTypeAndShapeOfInput(1);
class GetLeakyReluGradient : public GradientMakerBase {
using GradientMakerBase::GradientMakerBase;
vector<OperatorDef> GetGradientDefs() override {
return SingleGradientDef(
"LeakyReluGradient",
"",
vector<string>{O(0), GO(0)},
vector<string>{GI(0)});
}
};
REGISTER_GRADIENT(LeakyRelu, GetLeakyReluGradient);
} // namespace caffe2