C ++:将数学函数及其派生类分组为一个实体

时间:2018-11-20 19:47:36

标签: c++

我想实现各种数学函数,例如Sigmoid(逻辑),ReLU等。我想一起实现它们的导数。

鉴于这些数学函数都是非常简单的一线函数,我想将它们内联。此外,我希望能够按名称将功能组织为单个实体,并能够像这样调用常规激活或派生功能:

Sigmoid.Activate(0.5)
Sigmoid.Derivate(0.5)

最后,我希望能够将它们存储为对象的字段,因此,如果要为神经网络合并神经元,我将能够拥有一个名为activation的字段,并且可以这样称呼它:

this->activation.Derivate(this->input);

在寻找合适的方法来实现这一目标时,我感到矛盾。我读到,一般而言,静态内联函数是一种代码味道。但是,为每个使用函数的对象创建单独的实例似乎是多余的,而且浪费内存。实际上,完全拥有任何实例似乎是浪费的,因为我本质上只是想将两个函数归为一个名称。我已经考虑过为每个函数使用名称空间,但是那样我将无法指定对象应使用哪个函数。

静态类似乎是唯一有效的解决方案。有没有更优雅的方法可以做到这一点?

3 个答案:

答案 0 :(得分:2)

这可能不符合您的所有条件,但是,我认为这很有用。类并不是所有事物的解决方案,所以为什么不将类的activation字段作为返回(值,派生)对的函数指针类型:

// Example library
using value_derivative = std::pair<double,double>;
enum ReturnType {
    VALUE,
    DERIVATIVE
};
using ActivationFunction = std::function<value_derivative(double)>;

value_derivative sigmoid(double z) {
    double ez = exp(-z);
    double val = 1.0/(1+ez);
    return std::make_pair(val, val*(1.0-val));
}

// Example usage
ActivationFunction activation = sigmoid;
auto act = activation(1);
double value = std::get<VALUE>(act);
double derivative = std::get<DERIVATIVE>(act);
std::tie(value,derivative) = activation(2);

请注意,这样做的附带好处是,当激活函数具有一个很好的微分方程时,在计算值时使用中间项来计算导数通常会更简单。

答案 1 :(得分:2)

如果需要能够在运行时上为Neuron的字段分配一对函数,那么您将至少需要一个多态对象的实例。 std::function对此非常方便,但是您可以使用抽象基类实现类似的功能。您可以使用简单的结构将两个std::function组合在一起。

struct Activation {
    std::function<double(double)> activate;
    std::function<double(double)> derivative;
};

然后,您可以为Sigmoid拥有此结构的单个实例:

const Activation& sigmoid() {
    static const Activation activation {
        [](double z){ return 1.0/(1.0+exp(-z)); },
        [](double z){ auto a=exp(z); auto b=1.0+a; return a/(b*b);  }
    };
    return activation;
}

然后,您可以在Neuron的字段中存储对此实例的引用:

class Neuron {
    const Activation& activation;
  public:
    Neuron(const Activation& activation) : activation(activation) {}
    void doSomething() {
        std::cout << activation.derivative(0.5) << "\n";
    }
};

int main() {
    Neuron n(sigmoid());
    n.doSomething();
}

Live demo

答案 2 :(得分:0)

使用函子可以将这些功能存储为对象。这些是()运算符已重载的类,因此您可以像调用函数一样调用该类:

class my_functor {
    return_type operator() (param_type param) { /* .. */ }
}

这样做的一个优点是您还可以在类内部存储状态。您可以将其称为:

std::cout << this->instance_of_my_functor(42);

由于功能存储状态的功能,所以功能优于函数指针,您可能会发现这是有益的。也可以将继承与它们一起使用,并根据需要覆盖运算符。