Optimization 提高以下计算softmax导数的代码性能的提示

Optimization 提高以下计算softmax导数的代码性能的提示,optimization,machine-learning,neural-network,julia,softmax,Optimization,Machine Learning,Neural Network,Julia,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{Floa

编辑:添加了函数标题

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层向后函数的代码。本线程中的答案很好地描述了计算softmax导数的方法。在这里,我正在寻找一种更有效的方法来计算导数,因为上面的代码需要
0.05~6
秒来计算1000 x 100,而之前的softmax+交叉熵组合层只需要
0.002

因此,我正在寻找一种使代码运行更快的方法。我不确定我是否使用了计算雅可比矩阵的最有效的方法,但我尝试了另一种方法,即我
repmat(ly,1,n)
,然后用
ly
进行点乘。结果更糟,因为显然julia的
repmat
占用了太多的分配


本质上,我正在寻找一种有效的方法,将数组与数组中的每个元素相乘,并将结果合并成一个方阵。朱莉娅大师对此有什么想法吗?谢谢

在抱怨了可运行代码之后(抱怨仍然相关),我将尝试一个更具建设性的评论。更换回路:

 for i=1:n
    li = ly[i]
    l.jacobian[:,i] = -li * ly
    l.jacobian[i,i] = li*(1-li)
 end
带(无需循环):

得到的
l.jacobian
应该是相同的,而且效率更高


作为一种解释,使用的关键特性是:
broadcast
diagind

如果问题中有运行缓慢的代码,那么回答有关速度的问题就容易多了。如果您添加可运行代码,响应通常很快。我不认为有办法在这里显示我的“可运行”代码,因为它比较庞大和复杂。除此之外,真正使代码变慢的部分实际上是向后调用函数
,这是我提出的问题。我相信我试图在功能上实现的应该是相对明显的,同时我也尽力用语言来描述。正如我在最初的帖子中所说,第二个循环
I=1:n
花费的时间最多,也是我在这里发布代码进行优化的主要部分。如果你对我的代码有任何疑问,我也很乐意澄清。这确实让代码更快了!后退功能现在平均运行
0.03
秒,几乎是前一个的两倍。现在我将寻找一种方法来取消batch1:m的外部循环
,以使其更快!感谢您对使用
=
操作提出的建设性建议!看来应该可以改进外环。如果您询问有关StackOverflow的另一个问题,并包含一个函数和几行代码以进行演示运行,您可以得到更快的响应,或者至少在投票方面得到更好的响应;)
 l.jacobian .= -ly .* ly'
 l.jacobian[diagind(jacobian)] .= ly.*(1.0.-ly)