C++ 如何在Eigen中实现高性能分段线性传递函数?

C++ 如何在Eigen中实现高性能分段线性传递函数?,c++,performance,eigen,C++,Performance,Eigen,我需要一些帮助来优化分段线性传递函数的基于特征值的实现(输出值等于输入,但限制在一个范围内,在本例中为[-0.5,0.5])。下面是我分析的函数: typedef float SignalT; typdedef Eigen::Array<SignalT, Eigen::Dynamic, Eigen::Dynamic> Signal2D; void ActivateSum(unsigned char const idx, Signal2D::ColXpr& outputSum)

我需要一些帮助来优化分段线性传递函数的基于特征值的实现(输出值等于输入,但限制在一个范围内,在本例中为[-0.5,0.5])。下面是我分析的函数:

typedef float SignalT;
typdedef Eigen::Array<SignalT, Eigen::Dynamic, Eigen::Dynamic> Signal2D;
void ActivateSum(unsigned char const idx, Signal2D::ColXpr& outputSum)
{
    switch (idx)
    {
    case 0U:
        //Threshold
        outputSum = (outputSum >= (SignalT) 0.0).cast<SignalT>();
        break;
    case 1U:
        //Piecewise linear
        outputSum = outputSum.unaryExpr([](SignalT const elem)
        {
            if (elem >(SignalT) 0.5)
                return (SignalT) 0.5;
            else if (elem < (SignalT)-0.5)
                return (SignalT)-0.5;
            else
                return elem;
        }
        );
        break;
    case 2U:
        //Fast Sigmoid
        outputSum *= ((SignalT) 1.0 + outputSum.abs()).inverse();
        break;
    default:
        assert(0);
        throw;
    }
}

可能是分支预测,您的if条件创建了一个复杂的依赖于数据的控制流,多个返回站点可能使其难以优化

也许这样的三元运算符可以消除分支:

        return (elem>0? 1 : -1) * (std::min(std::abs(elem),0.5));
(请确保使用支持浮动abs的lib,我认为cmath应该可以)


通过使用条件移动,查看编译器是否以这种方式发出较少的分支代码。

如果现有代码尚未以这种方式编译,请使用FPU最大和最小指令

    outputSum = outputSum.unaryExpr( [] (SignalT elem)
    {
        return std::fmax( -0.5f, std::fmin( 0.5f, elem ) );
    }

Eigen可能已经内置了这样的操作,但是浏览文档并没有发现任何问题。

您想要饱和算法。“分段线性传递函数”过于笼统,建议1。您有任意数量的任意坡度线,而不是只有一条坡度线=1和2。“你在频域中,而你不是。”Potatoswatter我不知道它叫什么,但你可以看看代码,看看我想要什么(我以为它叫分段线性传递函数)。关于开关/案例;无论您使用if/else、查找表还是开关/case,都会对性能产生绝对的影响。原因是outputSum的长度大于20000,因此操作的核心在那些
case
子句中。三元运算符生成的分支与
if
的分支相同。编译器的优化器看到的控制流图将完全相同。@Potatoswatter,不完全相同,原始代码从if代码中的多个位置从函数中返回。如果一个编译器可以用条件运算来交换它,我会感到非常惊讶。是的,确实如此<代码>输出总和=输出总和。最大值((信号T)-0.5)。最小值((信号T)0.5)@ausairman酷,这是否提高了性能?一定要从两个方面进行描述;我认为Eigen足够聪明,可以交错链式操作,但你不能太确定。是的,基本上,该操作现在占用的CPU时间与阈值函数相同。
        return (elem>0? 1 : -1) * (std::min(std::abs(elem),0.5));
    outputSum = outputSum.unaryExpr( [] (SignalT elem)
    {
        return std::fmax( -0.5f, std::fmin( 0.5f, elem ) );
    }