簡體   English   中英

如何在Eigen中實現高性能的分段線性傳遞函數?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM