python Julia返回意外值

tzcvj98z  于 2022-12-17  发布在  Python
关注(0)|答案(4)|浏览(149)

我经常使用Python for ML,并且对转换为Julia很感兴趣,因为它在速度上有很大的改进。为了感受一下,我刚刚用Python和Julia编写了一个简单的循环,以便比较两者的运行时间,但是我似乎在Julia实现中得到了意想不到的结果。
以下是两个版本:
在朱莉娅:

B = Array{Float64, 2}(undef, 10000,10000)

function f(x)
    return x^2
end

function g(x)
    return x^3
end

function h(x)
    return x^4
end

function compose(f,g,h,x)
    return f(g(h(x)))
end

for i in 1:10000
    for j in 1:10000
        B[i,j] = compose(f,g,h,i+j)
    end
end

println(sum(B))

在Python中:

import numpy as np

B = np.zeros((10000, 10000), dtype=np.float64)

def f(x):
    return x**2

def g(x):
    return x**3

def h(x):
    return x**4

def compute(x):
    return f(g(h(x)))

for i in range(10000):
    for j in range(10000):
        B[i, j] = compute(i+j+2)

print(np.sum(B))

编辑:Julia版本返回~8.3e22,而Python返回~1.0e109(这是我所期望的)。
虽然Julia版本与Python版本相比运行速度非常快,但它的结果并不是我所期望的。如上所述,我是第一次使用Julia,但我不知道我的错误可能在哪里。这是我的数组/数据类型处理的结果吗?我的函数没有做我所认为的事情吗?

pbgvytdp

pbgvytdp1#

我不知道你是如何比较这两个代码的,但在我的机器朱莉娅只是1000倍快。

f(x) = x^2
g(x) = x^3
h(x) = (x^2)^2
compute(x) = f(g(h(x)))

function compute_sum(B)
    for j in 1:10000
        for i in 1:10000
            B[i,j] = compute(i+j+0.0)
        end 
    end 
    sum(B)
end

B = zeros(10000, 10000)
@time compute_sum(B)
1.0337869071875959e109
  0.126618 seconds (1 allocation: 16 bytes)

还有巨蟒:

from time import time

t0 = time()
for i in range(10000):
    for j in range(10000):
        B[i, j] = compute(i+j+2)

s = np.sum(B)
print('Time:', time()-t0, 'sec')
print(s)
Time: 126.33235883712769 sec
1.0337869071875948e+109
ndh0cuux

ndh0cuux2#

我认为,通过省略B并使用sum的迭代器特性,甚至可以更快地实现这一点

f(x) = x^2
g(x) = x^3
h(x) = (x^2)^2
compute(x) = f(g(h(x)))

large_sum(n) = sum(compute(i+j+0.0) for i=1:n, j=1:n)
    
@time large_sum(10000)

收益率

0.115042 seconds
1.0337869071880225e109

以及

julia> @allocated large_sum(10000)
0
  • edit:* 如果你想使用整数(对我来说,@AboAmmar的解决方案似乎表明Python也可以使用Float 64?)
large_sum2(n) = sum(compute(big(i+j)) for i=1:n, j=1:n)
@time s = large_sum2(10000)

其产生

46.161187 seconds (1.60 G allocations: 37.124 GiB, 23.40% gc time)
10337869071875958659210675038435022389685259621942996488934459692733527441076067397940855599887078973410000000

以及

julia> Float64(s)
1.0337869071875959e109

这看起来仍然比Python解决方案(@ AboAmmar的)快

toe95027

toe950273#

我把你的代码合并成一个块,这样更容易计时。然后我对下面的代码做了一些修改,以提高性能。
1.正确数字的主要问题是整数溢出,因为ij开始时是Int64类型。由于我们最后存储为Float64,因此将输入强制转换为Float64
1.通过将代码的主要内容放入函数中,我们可以利用编译。

function f(x)
    return x^2
end

function g(x)
    return x^3
end

function h(x)
    return x^4
end

function compose(f,g,h,x)
    return f(g(h(x)))
end

println("Global block")

@time begin
    # B is an untyped global
    B = Array{Float64, 2}(undef, 10000,10000)
    for i in 1:10000
        for j in 1:10000
            # The i and j are of type Int64
            # You are experiencing integer overflow
            B[i,j] = compose(f,g,h,i+j)
        end
    end

    println(sum(B))
end

println("Global block with global typed")

@time begin
    # In recent versions of Julia, we can bind the type of globals
    BB :: Matrix{Float64} = Array{Float64, 2}(undef, 10000,10000)
    for i in 1:10000
        for j in 1:10000
            # Cast to Float64 to fix the integer overflow
            BB[i,j] = compose(f,g,h,Float64(i+j))
        end
    end

    # This should yield the correct answer
    println(sum(BB))
end

function main()
    # It is best to contain in functions that can be compiled
    # We also do not have to worry about binding globals to types
    # The following are all _local_ variables
    B = Array{Float64, 2}(undef, 10000,10000)
    T = eltype(B)
    for i in 1:10000
        @simd for j in 1:10000
            @inbounds B[i,j] = compose(f,g,h,T(i+j))
        end
    end

    println(sum(B))
end

# Execute twice to check for compilation time
println("Main 1:")
@time main() # first executing may include compilation time
println("Main 2:")
@time main() # should already be compiled now

function better()
    # As Ronny suggests, you can perform this calculation without allocating the array, saving time
    sum = 0.0
    for i in 1:10000
        for j in 1:10000
            sum += compose(f,g,h,Float64(i+j))
        end
    end
    println(sum)
end

println("Better 1:")
@time better()
println("Better 2:")
@time better()

当我执行此命令时,在速度较慢的计算机上得到以下结果:
x一个一个一个一个x一个一个二个x
请注意,您也可以在一行中执行此操作。

julia> using BenchmarkTools

julia> @benchmark mapreduce(∘(f,g,h,Float64,t->t[1]+t[2]), +,  Iterators.product(1:10000, 1:10000))
BenchmarkTools.Trial: 3 samples with 1 evaluation.
 Range (min … max):  1.783 s …  1.791 s  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     1.784 s             ┊ GC (median):    0.00%
 Time  (mean ± σ):   1.786 s ± 4.441 ms  ┊ GC (mean ± σ):  0.00% ± 0.00%

  █    █                                                 █  
  █▁▁▁▁█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█ ▁
  1.78 s        Histogram: frequency by time        1.79 s <

 Memory estimate: 0 bytes, allocs estimate: 0.
gjmwrych

gjmwrych4#

Julia中的整数是64位的(不像Python,没有大小限制)你有整数溢出。
一种选择是迭代Float64 s

jula> using BenchmarkTools 

julia> @btime B = [compose($f,$g,$h,i+j) for i in 1.0:10000.0, j in 1.0:10000.0]
  859.809 ms (2 allocations: 762.94 MiB)
10000×10000 Matrix{Float64}:
...

请注意,$符号是使用BenchmarkTools宏正确测量速度所必需的,通常在代码中不会放置它们。

相关问题