1

編輯:添加函數頭提示以改善下面的代碼性能計算SOFTMAX衍生物

function backward(l::SoftMax, DLDY::Array{Float64}; kwargs...) 
    # credits: https://stats.stackexchange.com/questions/79454/softmax-layer-in-a-neural-network?newreg=d1e89b443dd346ae8bccaf038a944221 
    m,n =size(l.x) 

    ly = Array{Float64}(n) 
    for batch=1:m 
     ly = l.y[batch,:] 

     for i=1:n 
     li = ly[i] 
     l.jacobian[:,i] = -li * ly 
     l.jacobian[i,i] = li*(1-li) 
     end 

     # l.jacobian = ly'.*repmat(ly, 1, n) 
     # for i=1:n 
     # li = l.y[batch,i] 
     # l.jacobian[i,i] = li*(1.0-li) 
     # end 

     # # n x 1 = n x n * n x 1 
     l.dldx[batch,:] = l.jacobian * DLDY[batch,:] 
    end 

    return l.dldx 

end 

以上是我爲我SOFTMAX層的後退功能的代碼。軟件https://stats.stackexchange.com/questions/79454/softmax-layer-in-a-neural-network?newreg=d1e89b443dd346ae8bccaf038a944221中的回答很好地描述了計算softmax導數的方式。在這裏,我正在尋找更有效的方法來計算導數,因爲上面的代碼需要0.05~6秒才能評估1000乘以100,而之前的softmax +交叉熵組合層僅需要0.002秒。

我正在尋找一種讓代碼運行更快的方法。我不確定我是否正在使用計算雅可比矩陣的最有效方式,但我嘗試了另一種方法,然後將其與ly相乘,然後將其乘以ly。事實證明,情況更糟,因爲顯然朱莉婭的repmat需要太多的分配。

本質上,我正在尋找一種有效的方法來將數組與數組中的每個元素相乘,並將結果連接成方矩陣。任何朱莉婭大師對此有何看法?謝謝!

+1

如果問題中存在正在運行的代碼(緩慢,我猜),回答有關速度的問題要容易得多。如果您添加可運行代碼,那麼響應通常很快。 –

+0

我不認爲有辦法在這裏顯示我的「可運行」代碼,因爲它相對龐大而複雜。除了這部分真的讓代碼變得緩慢外,它實際上是將函數「落後」,我提出這個問題。我相信我在功能上要達到的目標應該是比較明顯的,同時我也盡力用文字來形容。正如我在原始文章中所說的,第二個循環'i = 1:n'是需要最多時間的東西,並且是通過在此處發佈代碼進行優化的主要部分。如果您對我的代碼有任何疑問,我也很樂意澄清。 –

回答

2

抱怨可運行的代碼(抱怨仍然相關)後,我會嘗試更具建設性的評論。取代環:

for i=1:n 
    li = ly[i] 
    l.jacobian[:,i] = -li * ly 
    l.jacobian[i,i] = li*(1-li) 
end 

有(無循環必要):

l.jacobian .= -ly .* ly' 
l.jacobian[diagind(jacobian)] .= ly.*(1.0.-ly) 

所得l.jacobian應該是相同的,並且它是更有效的。

至於說明,使用的主要特點是:broadcastdiagind的點符號。

+1

這確實使代碼更快!現在,落後功能的平均運行時間爲「0.03」秒,比以前快了近兩倍。我現在將尋找一種方法來取消外部循環'batch1:m'來嘗試使其更快!感謝您使用'。='操作的建設性意見! –

+2

似乎應該有可能改善外環。如果你在StackOverflow上提出關於它的另一個問題,並且包含一個函數和幾行來演示它,你可以得到更快的響應或至少在投票方面更好;) –