我需要一些帮助来优化分段线性传递函数的基于特征的实现(输出值等于输入但是上限到一个范围,在这种情况下为[-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;
}
}
我的整个程序在每个切换案例中花费以下部分样本:
Threshold: 3.3%
Piecewise Linear: 18%
Fast Sigmoid: < 0.1%
快速sigmoid很少使用,但分段线性情况应该与阈值情况一样频繁出现(虽然我不知道如何使用Visual Studio进行测量)。所以在我看来,我花了相当多的时间在Piecewise线性一元表达式中,并想知道是否有一种替代方法来实现Eigen中的功能,也许是通过使用一些内置方法来提高速度。这是一个非常简单的传递函数,因此它在计算上应该非常便宜 - 我的猜测是由于我的自定义lambda而不是其他任何因素,成本更多地与优化不佳有关。
思想?
编辑:到目前为止,我已经想出了Leeor的回答:case 1U:
//Piecewise linear
outputSum = outputSum.max((SignalT)-0.5).min((SignalT)0.5);
break;
答案 0 :(得分:1)
如果现有代码尚未以这种方式编译,请使用FPU最大和最小指令。
outputSum = outputSum.unaryExpr( [] (SignalT elem)
{
return std::fmax( -0.5f, std::fmin( 0.5f, elem ) );
}
Eigen可能已经内置了这样的操作,但是对文档的一瞥并没有改变任何内容。
答案 1 :(得分:0)
可能是分支预测,您的if条件会创建一个复杂的数据相关控制流,多个返回站点可能使其难以优化。
也许像这样的三元运营商会消除分支机构:
return (elem>0? 1 : -1) * (std::min(std::abs(elem),0.5));
(确保使用支持浮点数上的abs的lib,我认为cmath应该没问题。)
通过条件移动来查看编译器是否以这种方式发出较少分支的代码。