#ifndef CAFFE_NEURON_LAYERS_HPP_ #define CAFFE_NEURON_LAYERS_HPP_ #include #include #include #include "caffe/blob.hpp" #include "caffe/common.hpp" #include "caffe/layer.hpp" #include "caffe/proto/caffe.pb.h" #define HDF5_DATA_DATASET_NAME "data" #define HDF5_DATA_LABEL_NAME "label" namespace caffe { /** * @brief An interface for layers that take one blob as input (@f$ x @f$) * and produce one equally-sized blob as output (@f$ y @f$), where * each element of the output depends only on the corresponding input * element. */ template class NeuronLayer : public Layer { public: explicit NeuronLayer(const LayerParameter& param) : Layer(param) {} virtual void Reshape(const vector*>& bottom, const vector*>& top); virtual inline int ExactNumBottomBlobs() const { return 1; } virtual inline int ExactNumTopBlobs() const { return 1; } }; /** * @brief Computes @f$ y = |x| @f$ * * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$ * @param top output Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the computed outputs @f$ y = |x| @f$ */ template class AbsValLayer : public NeuronLayer { public: explicit AbsValLayer(const LayerParameter& param) : NeuronLayer(param) {} virtual void LayerSetUp(const vector*>& bottom, const vector*>& top); virtual inline const char* type() const { return "AbsVal"; } virtual inline int ExactNumBottomBlobs() const { return 1; } virtual inline int ExactNumTopBlobs() const { return 1; } protected: /// @copydoc AbsValLayer virtual void Forward_cpu(const vector*>& bottom, const vector*>& top); virtual void Forward_gpu(const vector*>& bottom, const vector*>& top); /** * @brief Computes the error gradient w.r.t. the absolute value inputs. * * @param top output Blob vector (length 1), providing the error gradient with * respect to the outputs * -# @f$ (N \times C \times H \times W) @f$ * containing error gradients @f$ \frac{\partial E}{\partial y} @f$ * with respect to computed outputs @f$ y @f$ * @param propagate_down see Layer::Backward. * @param bottom input Blob vector (length 2) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$; Backward fills their diff with * gradients @f$ * \frac{\partial E}{\partial x} = * \mathrm{sign}(x) \frac{\partial E}{\partial y} * @f$ if propagate_down[0] */ virtual void Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); }; /** * @brief Computes @f$ y = x + \log(1 + \exp(-x)) @f$ if @f$ x > 0 @f$; * @f$ y = \log(1 + \exp(x)) @f$ otherwise. * * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$ * @param top output Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the computed outputs @f$ * y = \left\{ * \begin{array}{ll} * x + \log(1 + \exp(-x)) & \mbox{if } x > 0 \\ * \log(1 + \exp(x)) & \mbox{otherwise} * \end{array} \right. * @f$ */ template class BNLLLayer : public NeuronLayer { public: explicit BNLLLayer(const LayerParameter& param) : NeuronLayer(param) {} virtual inline const char* type() const { return "BNLL"; } protected: /// @copydoc BNLLLayer virtual void Forward_cpu(const vector*>& bottom, const vector*>& top); virtual void Forward_gpu(const vector*>& bottom, const vector*>& top); /** * @brief Computes the error gradient w.r.t. the BNLL inputs. * * @param top output Blob vector (length 1), providing the error gradient with * respect to the outputs * -# @f$ (N \times C \times H \times W) @f$ * containing error gradients @f$ \frac{\partial E}{\partial y} @f$ * with respect to computed outputs @f$ y @f$ * @param propagate_down see Layer::Backward. * @param bottom input Blob vector (length 2) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$; Backward fills their diff with * gradients @f$ * \frac{\partial E}{\partial x} * @f$ if propagate_down[0] */ virtual void Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); }; /** * @brief During training only, sets a random portion of @f$x@f$ to 0, adjusting * the rest of the vector magnitude accordingly. * * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$ * @param top output Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the computed outputs @f$ y = |x| @f$ */ template class DropoutLayer : public NeuronLayer { public: /** * @param param provides DropoutParameter dropout_param, * with DropoutLayer options: * - dropout_ratio (\b optional, default 0.5). * Sets the probability @f$ p @f$ that any given unit is dropped. */ explicit DropoutLayer(const LayerParameter& param) : NeuronLayer(param) {} virtual void LayerSetUp(const vector*>& bottom, const vector*>& top); virtual void Reshape(const vector*>& bottom, const vector*>& top); virtual inline const char* type() const { return "Dropout"; } protected: /** * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$ * @param top output Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the computed outputs. At training time, we have @f$ * y_{\mbox{train}} = \left\{ * \begin{array}{ll} * \frac{x}{1 - p} & \mbox{if } u > p \\ * 0 & \mbox{otherwise} * \end{array} \right. * @f$, where @f$ u \sim U(0, 1)@f$ is generated independently for each * input at each iteration. At test time, we simply have * @f$ y_{\mbox{test}} = \mathbb{E}[y_{\mbox{train}}] = x @f$. */ virtual void Forward_cpu(const vector*>& bottom, const vector*>& top); virtual void Forward_gpu(const vector*>& bottom, const vector*>& top); virtual void Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); /// when divided by UINT_MAX, the randomly generated values @f$u\sim U(0,1)@f$ Blob rand_vec_; /// the probability @f$ p @f$ of dropping any input Dtype threshold_; /// the scale for undropped inputs at train time @f$ 1 / (1 - p) @f$ Dtype scale_; unsigned int uint_thres_; }; /** * @brief Computes @f$ y = \gamma ^ {\alpha x + \beta} @f$, * as specified by the scale @f$ \alpha @f$, shift @f$ \beta @f$, * and base @f$ \gamma @f$. */ template class ExpLayer : public NeuronLayer { public: /** * @param param provides ExpParameter exp_param, * with ExpLayer options: * - scale (\b optional, default 1) the scale @f$ \alpha @f$ * - shift (\b optional, default 0) the shift @f$ \beta @f$ * - base (\b optional, default -1 for a value of @f$ e \approx 2.718 @f$) * the base @f$ \gamma @f$ */ explicit ExpLayer(const LayerParameter& param) : NeuronLayer(param) {} virtual void LayerSetUp(const vector*>& bottom, const vector*>& top); virtual inline const char* type() const { return "Exp"; } protected: /** * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$ * @param top output Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the computed outputs @f$ * y = \gamma ^ {\alpha x + \beta} * @f$ */ virtual void Forward_cpu(const vector*>& bottom, const vector*>& top); virtual void Forward_gpu(const vector*>& bottom, const vector*>& top); /** * @brief Computes the error gradient w.r.t. the exp inputs. * * @param top output Blob vector (length 1), providing the error gradient with * respect to the outputs * -# @f$ (N \times C \times H \times W) @f$ * containing error gradients @f$ \frac{\partial E}{\partial y} @f$ * with respect to computed outputs @f$ y @f$ * @param propagate_down see Layer::Backward. * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$; Backward fills their diff with * gradients @f$ * \frac{\partial E}{\partial x} = * \frac{\partial E}{\partial y} y \alpha \log_e(gamma) * @f$ if propagate_down[0] */ virtual void Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); Dtype inner_scale_, outer_scale_; }; /** * @brief Computes @f$ y = log_{\gamma}(\alpha x + \beta) @f$, * as specified by the scale @f$ \alpha @f$, shift @f$ \beta @f$, * and base @f$ \gamma @f$. */ template class LogLayer : public NeuronLayer { public: /** * @param param provides LogParameter log_param, * with LogLayer options: * - scale (\b optional, default 1) the scale @f$ \alpha @f$ * - shift (\b optional, default 0) the shift @f$ \beta @f$ * - base (\b optional, default -1 for a value of @f$ e \approx 2.718 @f$) * the base @f$ \gamma @f$ */ explicit LogLayer(const LayerParameter& param) : NeuronLayer(param) {} virtual void LayerSetUp(const vector*>& bottom, const vector*>& top); virtual inline const char* type() const { return "Log"; } protected: /** * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$ * @param top output Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the computed outputs @f$ * y = log_{\gamma}(\alpha x + \beta) * @f$ */ virtual void Forward_cpu(const vector*>& bottom, const vector*>& top); virtual void Forward_gpu(const vector*>& bottom, const vector*>& top); /** * @brief Computes the error gradient w.r.t. the exp inputs. * * @param top output Blob vector (length 1), providing the error gradient with * respect to the outputs * -# @f$ (N \times C \times H \times W) @f$ * containing error gradients @f$ \frac{\partial E}{\partial y} @f$ * with respect to computed outputs @f$ y @f$ * @param propagate_down see Layer::Backward. * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$; Backward fills their diff with * gradients @f$ * \frac{\partial E}{\partial x} = * \frac{\partial E}{\partial y} y \alpha \log_e(gamma) * @f$ if propagate_down[0] */ virtual void Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); Dtype base_scale_; Dtype input_scale_, input_shift_; Dtype backward_num_scale_; }; /** * @brief Computes @f$ y = (\alpha x + \beta) ^ \gamma @f$, * as specified by the scale @f$ \alpha @f$, shift @f$ \beta @f$, * and power @f$ \gamma @f$. */ template class PowerLayer : public NeuronLayer { public: /** * @param param provides PowerParameter power_param, * with PowerLayer options: * - scale (\b optional, default 1) the scale @f$ \alpha @f$ * - shift (\b optional, default 0) the shift @f$ \beta @f$ * - power (\b optional, default 1) the power @f$ \gamma @f$ */ explicit PowerLayer(const LayerParameter& param) : NeuronLayer(param) {} virtual void LayerSetUp(const vector*>& bottom, const vector*>& top); virtual inline const char* type() const { return "Power"; } protected: /** * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$ * @param top output Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the computed outputs @f$ * y = (\alpha x + \beta) ^ \gamma * @f$ */ virtual void Forward_cpu(const vector*>& bottom, const vector*>& top); virtual void Forward_gpu(const vector*>& bottom, const vector*>& top); /** * @brief Computes the error gradient w.r.t. the power inputs. * * @param top output Blob vector (length 1), providing the error gradient with * respect to the outputs * -# @f$ (N \times C \times H \times W) @f$ * containing error gradients @f$ \frac{\partial E}{\partial y} @f$ * with respect to computed outputs @f$ y @f$ * @param propagate_down see Layer::Backward. * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$; Backward fills their diff with * gradients @f$ * \frac{\partial E}{\partial x} = * \frac{\partial E}{\partial y} * \alpha \gamma (\alpha x + \beta) ^ {\gamma - 1} = * \frac{\partial E}{\partial y} * \frac{\alpha \gamma y}{\alpha x + \beta} * @f$ if propagate_down[0] */ virtual void Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); /// @brief @f$ \gamma @f$ from layer_param_.power_param() Dtype power_; /// @brief @f$ \alpha @f$ from layer_param_.power_param() Dtype scale_; /// @brief @f$ \beta @f$ from layer_param_.power_param() Dtype shift_; /// @brief Result of @f$ \alpha \gamma @f$ Dtype diff_scale_; }; /** * @brief Rectified Linear Unit non-linearity @f$ y = \max(0, x) @f$. * The simple max is fast to compute, and the function does not saturate. */ template class ReLULayer : public NeuronLayer { public: /** * @param param provides ReLUParameter relu_param, * with ReLULayer options: * - negative_slope (\b optional, default 0). * the value @f$ \nu @f$ by which negative values are multiplied. */ explicit ReLULayer(const LayerParameter& param) : NeuronLayer(param) {} virtual inline const char* type() const { return "ReLU"; } protected: /** * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$ * @param top output Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the computed outputs @f$ * y = \max(0, x) * @f$ by default. If a non-zero negative_slope @f$ \nu @f$ is provided, * the computed outputs are @f$ y = \max(0, x) + \nu \min(0, x) @f$. */ virtual void Forward_cpu(const vector*>& bottom, const vector*>& top); virtual void Forward_gpu(const vector*>& bottom, const vector*>& top); /** * @brief Computes the error gradient w.r.t. the ReLU inputs. * * @param top output Blob vector (length 1), providing the error gradient with * respect to the outputs * -# @f$ (N \times C \times H \times W) @f$ * containing error gradients @f$ \frac{\partial E}{\partial y} @f$ * with respect to computed outputs @f$ y @f$ * @param propagate_down see Layer::Backward. * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$; Backward fills their diff with * gradients @f$ * \frac{\partial E}{\partial x} = \left\{ * \begin{array}{lr} * 0 & \mathrm{if} \; x \le 0 \\ * \frac{\partial E}{\partial y} & \mathrm{if} \; x > 0 * \end{array} \right. * @f$ if propagate_down[0], by default. * If a non-zero negative_slope @f$ \nu @f$ is provided, * the computed gradients are @f$ * \frac{\partial E}{\partial x} = \left\{ * \begin{array}{lr} * \nu \frac{\partial E}{\partial y} & \mathrm{if} \; x \le 0 \\ * \frac{\partial E}{\partial y} & \mathrm{if} \; x > 0 * \end{array} \right. * @f$. */ virtual void Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); }; #ifdef USE_CUDNN /** * @brief CuDNN acceleration of ReLULayer. */ template class CuDNNReLULayer : public ReLULayer { public: explicit CuDNNReLULayer(const LayerParameter& param) : ReLULayer(param), handles_setup_(false) {} virtual void LayerSetUp(const vector*>& bottom, const vector*>& top); virtual void Reshape(const vector*>& bottom, const vector*>& top); virtual ~CuDNNReLULayer(); protected: virtual void Forward_gpu(const vector*>& bottom, const vector*>& top); virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); bool handles_setup_; cudnnHandle_t handle_; cudnnTensorDescriptor_t bottom_desc_; cudnnTensorDescriptor_t top_desc_; }; #endif /** * @brief Sigmoid function non-linearity @f$ * y = (1 + \exp(-x))^{-1} * @f$, a classic choice in neural networks. * * Note that the gradient vanishes as the values move away from 0. * The ReLULayer is often a better choice for this reason. */ template class SigmoidLayer : public NeuronLayer { public: explicit SigmoidLayer(const LayerParameter& param) : NeuronLayer(param) {} virtual inline const char* type() const { return "Sigmoid"; } protected: /** * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$ * @param top output Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the computed outputs @f$ * y = (1 + \exp(-x))^{-1} * @f$ */ virtual void Forward_cpu(const vector*>& bottom, const vector*>& top); virtual void Forward_gpu(const vector*>& bottom, const vector*>& top); /** * @brief Computes the error gradient w.r.t. the sigmoid inputs. * * @param top output Blob vector (length 1), providing the error gradient with * respect to the outputs * -# @f$ (N \times C \times H \times W) @f$ * containing error gradients @f$ \frac{\partial E}{\partial y} @f$ * with respect to computed outputs @f$ y @f$ * @param propagate_down see Layer::Backward. * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$; Backward fills their diff with * gradients @f$ * \frac{\partial E}{\partial x} * = \frac{\partial E}{\partial y} y (1 - y) * @f$ if propagate_down[0] */ virtual void Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); }; #ifdef USE_CUDNN /** * @brief CuDNN acceleration of SigmoidLayer. */ template class CuDNNSigmoidLayer : public SigmoidLayer { public: explicit CuDNNSigmoidLayer(const LayerParameter& param) : SigmoidLayer(param), handles_setup_(false) {} virtual void LayerSetUp(const vector*>& bottom, const vector*>& top); virtual void Reshape(const vector*>& bottom, const vector*>& top); virtual ~CuDNNSigmoidLayer(); protected: virtual void Forward_gpu(const vector*>& bottom, const vector*>& top); virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); bool handles_setup_; cudnnHandle_t handle_; cudnnTensorDescriptor_t bottom_desc_; cudnnTensorDescriptor_t top_desc_; }; #endif /** * @brief TanH hyperbolic tangent non-linearity @f$ * y = \frac{\exp(2x) - 1}{\exp(2x) + 1} * @f$, popular in auto-encoders. * * Note that the gradient vanishes as the values move away from 0. * The ReLULayer is often a better choice for this reason. */ template class TanHLayer : public NeuronLayer { public: explicit TanHLayer(const LayerParameter& param) : NeuronLayer(param) {} virtual inline const char* type() const { return "TanH"; } protected: /** * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$ * @param top output Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the computed outputs @f$ * y = \frac{\exp(2x) - 1}{\exp(2x) + 1} * @f$ */ virtual void Forward_cpu(const vector*>& bottom, const vector*>& top); virtual void Forward_gpu(const vector*>& bottom, const vector*>& top); /** * @brief Computes the error gradient w.r.t. the sigmoid inputs. * * @param top output Blob vector (length 1), providing the error gradient with * respect to the outputs * -# @f$ (N \times C \times H \times W) @f$ * containing error gradients @f$ \frac{\partial E}{\partial y} @f$ * with respect to computed outputs @f$ y @f$ * @param propagate_down see Layer::Backward. * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$; Backward fills their diff with * gradients @f$ * \frac{\partial E}{\partial x} * = \frac{\partial E}{\partial y} * \left(1 - \left[\frac{\exp(2x) - 1}{exp(2x) + 1} \right]^2 \right) * = \frac{\partial E}{\partial y} (1 - y^2) * @f$ if propagate_down[0] */ virtual void Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); }; #ifdef USE_CUDNN /** * @brief CuDNN acceleration of TanHLayer. */ template class CuDNNTanHLayer : public TanHLayer { public: explicit CuDNNTanHLayer(const LayerParameter& param) : TanHLayer(param), handles_setup_(false) {} virtual void LayerSetUp(const vector*>& bottom, const vector*>& top); virtual void Reshape(const vector*>& bottom, const vector*>& top); virtual ~CuDNNTanHLayer(); protected: virtual void Forward_gpu(const vector*>& bottom, const vector*>& top); virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); bool handles_setup_; cudnnHandle_t handle_; cudnnTensorDescriptor_t bottom_desc_; cudnnTensorDescriptor_t top_desc_; }; #endif /** * @brief Tests whether the input exceeds a threshold: outputs 1 for inputs * above threshold; 0 otherwise. */ template class ThresholdLayer : public NeuronLayer { public: /** * @param param provides ThresholdParameter threshold_param, * with ThresholdLayer options: * - threshold (\b optional, default 0). * the threshold value @f$ t @f$ to which the input values are compared. */ explicit ThresholdLayer(const LayerParameter& param) : NeuronLayer(param) {} virtual void LayerSetUp(const vector*>& bottom, const vector*>& top); virtual inline const char* type() const { return "Threshold"; } protected: /** * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the inputs @f$ x @f$ * @param top output Blob vector (length 1) * -# @f$ (N \times C \times H \times W) @f$ * the computed outputs @f$ * y = \left\{ * \begin{array}{lr} * 0 & \mathrm{if} \; x \le t \\ * 1 & \mathrm{if} \; x > t * \end{array} \right. * @f$ */ virtual void Forward_cpu(const vector*>& bottom, const vector*>& top); virtual void Forward_gpu(const vector*>& bottom, const vector*>& top); /// @brief Not implemented (non-differentiable function) virtual void Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { NOT_IMPLEMENTED; } Dtype threshold_; }; /** * @brief Parameterized Rectified Linear Unit non-linearity @f$ * y_i = \max(0, x_i) + a_i \min(0, x_i) * @f$. The differences from ReLULayer are 1) negative slopes are * learnable though backprop and 2) negative slopes can vary across * channels. The number of axes of input blob should be greater than or * equal to 2. The 1st axis (0-based) is seen as channels. */ template class PReLULayer : public NeuronLayer { public: /** * @param param provides PReLUParameter prelu_param, * with PReLULayer options: * - filler (\b optional, FillerParameter, * default {'type': constant 'value':0.25}). * - channel_shared (\b optional, default false). * negative slopes are shared across channels. */ explicit PReLULayer(const LayerParameter& param) : NeuronLayer(param) {} virtual void LayerSetUp(const vector*>& bottom, const vector*>& top); virtual void Reshape(const vector*>& bottom, const vector*>& top); virtual inline const char* type() const { return "PReLU"; } protected: /** * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times ...) @f$ * the inputs @f$ x @f$ * @param top output Blob vector (length 1) * -# @f$ (N \times C \times ...) @f$ * the computed outputs for each channel @f$i@f$ @f$ * y_i = \max(0, x_i) + a_i \min(0, x_i) * @f$. */ virtual void Forward_cpu(const vector*>& bottom, const vector*>& top); virtual void Forward_gpu(const vector*>& bottom, const vector*>& top); /** * @brief Computes the error gradient w.r.t. the PReLU inputs. * * @param top output Blob vector (length 1), providing the error gradient with * respect to the outputs * -# @f$ (N \times C \times ...) @f$ * containing error gradients @f$ \frac{\partial E}{\partial y} @f$ * with respect to computed outputs @f$ y @f$ * @param propagate_down see Layer::Backward. * @param bottom input Blob vector (length 1) * -# @f$ (N \times C \times ...) @f$ * the inputs @f$ x @f$; For each channel @f$i@f$, backward fills their * diff with gradients @f$ * \frac{\partial E}{\partial x_i} = \left\{ * \begin{array}{lr} * a_i \frac{\partial E}{\partial y_i} & \mathrm{if} \; x_i \le 0 \\ * \frac{\partial E}{\partial y_i} & \mathrm{if} \; x_i > 0 * \end{array} \right. * @f$. * If param_propagate_down_[0] is true, it fills the diff with gradients * @f$ * \frac{\partial E}{\partial a_i} = \left\{ * \begin{array}{lr} * \sum_{x_i} x_i \frac{\partial E}{\partial y_i} & \mathrm{if} \; x_i \le 0 \\ * 0 & \mathrm{if} \; x_i > 0 * \end{array} \right. * @f$. */ virtual void Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); bool channel_shared_; Blob multiplier_; // dot multiplier for backward computation of params Blob backward_buff_; // temporary buffer for backward computation Blob bottom_memory_; // memory for in-place computation }; } // namespace caffe #endif // CAFFE_NEURON_LAYERS_HPP_