我决定将一些Python代码从Peter Harrington的机器学习行动翻译成Julia,从kNN算法开始。
在对他提供的数据集进行规范化之后,我写了一些函数:find_kNN()
,mass_kNN
(为多个输入找到kNN的函数),以及将给定数据集拆分为随机选取的列车的函数和测试数据集,调用mass_kNN()
,并多次绘制结果精度。
然后我比较了Julia代码和等效Python代码之间的运行时间。 (我在朱莉娅使用距离找到欧几里德距离和牛羚进行绘图,但是关闭绘图并不会影响时间。)
结果:
朱莉娅:
已用时间:1.175523034秒(分配455531636字节,gc时间47.54%)
的Python:
经过的时间:0.9517326354980469秒
我想知道是否有办法加快我的Julia代码,或者它是否在此时尽可能快地运行(我的意思是如果我在制作代码方面犯了任何明显的错误跑得最快。)
Julia notebook
Python notebook
repo包含笔记本和数据集
谢谢!..
修改:删除convert()
语句并将所有内容传递给Real,将时间减慢到2.29秒。
答案 0 :(得分:6)
首先,我删除了plot_probs
的最后两行 - 我认为绘图并不是一个非常棒的基准测试,它在很大程度上超出了我(或你)的控制范围 - 如果它是一个真正的因素,可以尝试PyPlot。我还花了几次plot_probs
来看看第一次花费多少时间来编译它:
**********elapsed time: 1.071184218 seconds (473218720 bytes allocated, 26.36% gc time)
**********elapsed time: 0.658809962 seconds (452017744 bytes allocated, 40.29% gc time)
**********elapsed time: 0.660609145 seconds (452017680 bytes allocated, 40.45% gc time)
所以一次支付0.3秒的罚款。转到实际的算法,我使用了内置的分析器(例如@profile plot_probs(norm_array, 0.25, [1:3], 10, 3)
),它显示了所有的时间(基本上)花在这里:
[ push!(dist, euclidean(set_array[i,:][:], input_array)) for i in 1:size(set_array, 1) ]
[ d[i] = get(d, i, 0) + 1 for i in labels[sortperm(dist)][1:k] ]
使用像这样的数组理解不是惯用的Julia(或者就此而言的Python)。第一个也很慢,因为所有切片都会产生许多数据副本。我不是Distances.jl
的专家,但我认为你可以用
dist = Distances.colwise(Euclidean(), set_array', input_array)
d = Dict{Int,Int}()
for i in labels[sortperm(dist)][1:k]
d[i] = get(d, i, 0) + 1
end
给了我
**********elapsed time: 0.731732444 seconds (234734112 bytes allocated, 20.90% gc time)
**********elapsed time: 0.30319397 seconds (214057552 bytes allocated, 37.84% gc time)
通过在mass_kNN
中进行一次转置,可以提取更多性能,但这需要触及太多的地方,这篇文章足够长。尝试微观优化它导致我使用
dist=zeros(size(set_array, 1)
@inbounds for i in 1:size(set_array, 1)
d = 0.0
for j in 1:length(input_array)
z = set_array[i,j] - input_array[j]
d += z*z
end
dist[i] = sqrt(d)
end
将其送到
**********elapsed time: 0.646256408 seconds (158869776 bytes allocated, 15.21% gc time)
**********elapsed time: 0.245293449 seconds (138817648 bytes allocated, 35.40% gc time)
所以花了大约一半的时间 - 但不是真的值得,而且不太灵活(例如,如果我想要L1)。其他代码审查点(未经请求,我知道):
Vector{Float64}
和Matrix{Float64}
比Array{Float64,1}
和Array{Float64,2}
更容易被发现,并且不太可能被混淆。Float64[]
比Array(Float64, 0)
Int64
只能写为Int
,因为它不需要是64位整数。