Python矢量化与Julia for循环

Qua*_*ick 3 optimization vectorization python-3.x julia

在Julia中有很多关于速度矢量化和去矢量化代码的文章,但是我的问题是我在Python和Julia中运行的一个非常简单的代码片段来比较性能。我有一个巨大的Python代码,当且仅当此类功能明显加速时,我才会将其转录为Julia。

我正在Jupyter笔记本中运行所有内容,并且我知道Julia在.jl文件中运行得更快;但是,与从终端运行相比,这种情况的差异可以忽略不计。

Python代码使用广播和矢量化:

def test(x0,dx,i):
   q = np.arange(-x0,x0,dx)  
   z = np.zeros(shape=(i,len(q)), dtype=np.complex128)
   B = np.exp(-1j*q)

   for s in range(1,i):
      A = np.exp(-(q-q[:,np.newaxis])**2)*np.exp(-1j*s*q)
      z[s] = B*np.sum(A,axis=1)*dx

   return z
Run Code Online (Sandbox Code Playgroud)

在Julia翻译中,我尝试使用for循环,但最终一次使用了理解,因为它比另一个for循环要快:

function test(x0,dx,n)
    z = zeros(ComplexF64, (n, Int(2*x0/dx + 1)))
    B = exp.(-1im*(-x0:dx:x0-dx))

    for s in 1:n-1
        for (i,q) in enumerate(-x0:dx:x0-dx)    
            A = [exp(-(q-Q)^2)exp(-1im*s*Q) for Q in -x0:dx:x0-dx]
            z[s,i] = B[i]*sum(A)*dx
        end       
    end   
    z
end
Run Code Online (Sandbox Code Playgroud)

结果是

%timeit test(10,.1,10)
Run Code Online (Sandbox Code Playgroud)

每个循环2.81 ms±247 µs(平均±标准偏差,共运行7次,每个循环100个)

@btime test(10,.1,10)
Run Code Online (Sandbox Code Playgroud)

55.075毫秒(2176212分配:61.20 MiB)

也就是说,Julia代码要慢得多。我绝对可以确定我在这里做错了,因为分配的空间不会那么大。我尽了最大努力来优化它,但是几天前我开始学习Julia,并且走得更远。任何有关如何提高性能的提示都将受到高度赞赏。

Osc*_*ith 6

最初有几件事阻碍了这一点:第一个也是最大的问题是循环理解,即在正确诊断后分配一吨(16毫秒)。一旦解决,最大的问题就是重复计算相同复杂指数(1.6 ms)的方式。

解决了这两个问题后,认识到问题中的线性代数既可以使代码更简洁,也可以让茱莉亚召唤blas进行更有效的矩阵乘法。(900 s)。这是最新的代码,比等效的numpy好约3倍

using LinearAlgebra
function test(x0,dx,n)
    Q = collect(-x0:dx:x0-dx)
    A = complex.(exp.(-(Q.-transpose(Q)).^2))
    B = exp.(-im.*transpose(1:n-1).*Q)
    z = Matrix{ComplexF64}(undef, n-1, length(Q))
    for (i, q) in enumerate(Q)
        total = transpose(@view A[:, i]) * B
        z[:, i] = dx*exp(-q*im) .* total
    end
    z
end
Run Code Online (Sandbox Code Playgroud)

作为对numba尝试的响应,这是另一种尝试,它通过解决一个bug来降低到725?s,该bug中乘以实数和复数数组会将实数转换为复数。手动编码乘法即可得出结果。

function test(x0,dx,n)
    Q = collect(-x0:dx:x0-dx)
    A = exp.(-(Q.-transpose(Q)).^2)
    B = exp.(-im.*transpose(1:n-1).*Q)
    rB = real.(B)
    iB = imag.(B)
    z = Matrix{ComplexF64}(undef, n-1, length(Q))
    for (i, q) in enumerate(Q)
        At = transpose(@view A[:, i])
        total =  (At * rB) .+ (At * iB).*im
        z[:, i] = dx*exp(-q*im) .* total
    end
    z
end
Run Code Online (Sandbox Code Playgroud)

  • 我把它降低到1.6ms (2认同)