[英]How do I implement a high-performance piecewise linear transfer function in 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)
{
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%
快速S型曲線很少使用,但分段線性情況應與閾值情況一樣頻繁發生(盡管我不知道如何使用Visual Studio進行測量)。 所以在我看來,我在分段線性一元表達式中花費了很多時間,並且想知道是否存在另一種方法來實現Eigen中的功能,也許是通過使用一些內置方法來加快速度。 這是一個非常簡單的傳遞函數,因此它實際上應該在計算上非常便宜-我的猜測是,由於我的自定義Lambda導致的成本降低與最差的優化息息相關。
思考?
編輯:到目前為止,我已經想出了這一點,這要歸功於Leeor的回答:
case 1U:
//Piecewise linear
outputSum = outputSum.max((SignalT)-0.5).min((SignalT)0.5);
break;
如果您現有的代碼尚未以這種方式編譯,請使用FPU最大和最小指令。
outputSum = outputSum.unaryExpr( [] (SignalT elem)
{
return std::fmax( -0.5f, std::fmin( 0.5f, elem ) );
}
Eigen可能已經內置了此類操作,但是瀏覽文檔並沒有發現任何問題。
可能是分支預測,如果條件產生復雜的數據相關控制流,可能有多個返回站點,可能難以優化。
也許像這樣的三元運算符將消除分支:
return (elem>0? 1 : -1) * (std::min(std::abs(elem),0.5));
(請確保您使用的庫在浮點數上支持Abs,我認為cmath應該很好)。
看看您的編譯器是否通過條件移動來發出較簡單的代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.