Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 3.x Python向量化与Julia for循环_Python 3.x_Optimization_Julia_Vectorization - Fatal编程技术网

Python 3.x Python向量化与Julia for循环

Python 3.x Python向量化与Julia for循环,python-3.x,optimization,julia,vectorization,Python 3.x,Optimization,Julia,Vectorization,在Julia中有很多关于速度矢量化与开发矢量化代码的帖子,但我的问题涉及一段非常简单的代码,我用Python和Julia运行该代码来比较性能。我有一个巨大的Python代码,我将转录给Julia,当且仅当像这样的函数大大加快时 我在Jupyter笔记本上运行所有东西,我知道Julia在.jl文件中运行得更快;然而,与从终端运行相比,这种情况下的差异可以忽略不计 Python代码使用广播和矢量化: def test(x0,dx,i): q = np.arange(-x0,x0,dx)

在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
在Julia翻译中,我尝试使用for循环,但最终使用了一次comprehension,因为它比另一个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
结果是

%timeit test(10,.1,10)
每个回路2.81 ms±247µs(7次运行的平均值±标准偏差,每个100个回路)

55.075毫秒(2176212次分配:61.20兆字节)


也就是说,Julia代码要慢得多。我绝对肯定我在这里做错了什么,因为拨款不应该那么大。我试着尽可能地优化它,但几天前我开始学习Julia,不能再进一步了。任何关于如何提高性能的提示,我们都将不胜感激

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

一旦这两个问题都得到解决,认识到问题中的线性代数既可以让代码更简洁,也可以让julia调用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
作为对numba尝试的回应,这里还有一次尝试,通过解决一个bug,将实数数组和复数数组相乘,将实数转换为复数,从而将时间降到725μs。手动对乘法进行编码可以得到这样的结果

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

为了便于比较,我想添加一个优化的Python(Numba)解决方案。Oscar Smith的解决方案看起来仍然有点慢,但这也可能是处理器速度较慢的结果

一些比较,优化的Numba和优化的Julia代码对于学习如何在Julia中编写高效的代码非常有用

代码

import numpy as np
import numba as nb

def Test_orig(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

@nb.njit(fastmath=True,parallel=True)
def Test_nb(x0,dx,n):
    q = np.arange(-x0,x0,dx)
    B = np.exp(-1j*q)
    z = np.zeros(shape=(n,q.shape[0]), dtype=np.complex128)

    TMP_1 = np.empty(shape=(q.shape[0],q.shape[0]), dtype=np.complex128)
    for i in nb.prange(q.shape[0]):
        for j in range(q.shape[0]):
            TMP_1[i,j]=np.exp(-(q[i]-q[j])**2)

    TMP_2 = np.empty(shape=(q.shape[0],q.shape[0]), dtype=np.complex128)
    for s in nb.prange(1,n):
        for j in range(q.shape[0]):
            TMP_2[s,j]=np.exp(-1j*s*q[j])

    for s in nb.prange(1,n):
        for i in range(q.shape[0]):
            sum=0.j
            for j in range(q.shape[0]):
                sum+=TMP_1[i,j]*TMP_2[s,j]
            z[s,i]=sum*B[i]*dx
    return z
计时

%timeit res_1=Test_orig(10,.1,10)
2.64 ms ± 276 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit res_2=Test_nb(10,.1,10)
192 µs ± 7.06 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
#@nb.njit(fastmath=True,parallel=False,cache=True) -> single threaded, caching possible
472 µs ± 19.7 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
#@nb.njit(fastmath=False,parallel=False,cache=True) -> without fastmath compiler flag
643 µs ± 10.9 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

res_1=Test_orig(10,.1,10)
res_2=Test_nb(10,.1,10)
np.allclose(res_1,res_2)
True
编辑:Julia计时(来自Oscar Smith的函数)


进步很好!过一会儿我会研究你的解决方案。我真的希望Julia能在这里超越Python。我把它降到了1.6msDon't do this:
length=size(-x0:dx:x0dx)[1]
。执行此操作:
N=length(-x0:dx:x0dx)
<代码>长度是一个内置函数,最好先使用它,然后像这样扭转它。因此,您再次使Python比Julia更快!我又一次困惑了,翻译我的代码是否值得。你能运行我的代码吗?我用的是一台4年的笔记本电脑,所以我的cpu肯定不是最强的。对于我来说,使用eqivilent设置(Fastmath=False,parallel=False)运行测试需要763毫秒,而我最近的版本需要227ms。我不久前安装了Julia,并做了一些尝试。当然,我必须再试一次。我的问题是找到一些非常好的例子来编写代码。事实上,我确实遇到了与提问者相同的问题。我在击败numba时遇到困难的部分原因是,目前存在一个julia性能错误,其中real*complex数组比它应该的慢,因为没有向量{real}*矩阵{complex}的方法,所以它提升了向量。
%timeit res_1=Test_orig(10,.1,10)
2.64 ms ± 276 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit res_2=Test_nb(10,.1,10)
192 µs ± 7.06 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
#@nb.njit(fastmath=True,parallel=False,cache=True) -> single threaded, caching possible
472 µs ± 19.7 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
#@nb.njit(fastmath=False,parallel=False,cache=True) -> without fastmath compiler flag
643 µs ± 10.9 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

res_1=Test_orig(10,.1,10)
res_2=Test_nb(10,.1,10)
np.allclose(res_1,res_2)
True
@benchmark test(10,.1,10)
BenchmarkTools.Trial:
  memory estimate:  1.16 MiB
  allocs estimate:  1014
  --------------
  minimum time:     643.072 μs (0.00% GC)
  median time:      662.869 μs (0.00% GC)
  mean time:        729.127 μs (4.15% GC)
  maximum time:     34.947 ms (97.25% GC)
  --------------
  samples:          6841
  evals/sample:     1