欧几里得距离矩阵之间的最小距离

时间:2019-10-21 23:26:27

标签: julia gpu julia-gpu

我有一些代码可以计算一个矩阵中每个笛卡尔坐标与另一个矩阵中其他坐标之间的距离。对于每个坐标,将返回最小距离以及产生最小坐标的索引位置。

function MED3D(m1, m2)
    n1::Int = size(m1,1)
    Dist = SharedArray{Float64}((n1,3))
    @sync @distributed for k in 1:n1
        Dist[k,:] = MD3D(m1[k,:], m2, k)
    end
    return Dist
end

@everywhere function MD3D(v1, m2, k)
    dsum::Float64 = Inf
    dtemp::Float64 = Inf
    i = 0
    for j in 1:size(m2,1)
        @inbounds dtemp = sqrt((v1[1] - m2[j,1]) * (v1[1] - m2[j,1]) + (v1[2] - m2[j,2]) * (v1[2] - m2[j,2]) + (v1[3] - m2[j,3]) * (v1[3] - m2[j,3]))
        if dtemp < dsum
            dsum = dtemp
            i = j
        end
    end
    return [dsum, k, i]
end

m1 = rand(10,3)
m2 = rand(15,3)
results = MED3D(m1,m2)

虽然这在较小的3D点云下可以正常工作,但我希望通过使用基于GPU的分析来提高大点云的性能。但是,由于我必须返回索引位置和最小距离,因此无法在Julia中使用更典型的方法进行矩阵运算。我尝试了几种不同的方法来采用CUarrays来完成此任务,但到目前为止,它们都失败了,而没有使用实际的for循环。此外,由于将距离矩阵存储在内存中,因此许多实现它的方法都显得效率极低,对于我的特定数据集,它很快超过了128gb的内存。

有人可以帮助我如何在Julia中正确实现此功能以在GPU上运行吗? CUarrays甚至是正确的方法,还是考虑到我除了返回距离外还返回索引,所以它太抽象了吗?我曾尝试使用乘积和点来计算L2范数,但这并不能完全满足我的需求。

更新:

这是我尝试使用广播将内部循环GPU化的失败尝试。

using CuArrays
function difff(m1,m2)
    n1 = size(m1,1)
    Dist = Array{Float64}(undef, n1,3)
    m2 = CuArray(m2)
    m1 = CuArray(m1)
    for z in 1:size(m1)
        v1 = transpose(m1[z,:])
        i = 0
        dsum::Float64 = Inf
        mi = v1 .- m2
        mi = mi .* mi
        mi = sum(mi, dims=2)
        mi = mi .^ 0.5
        mi = findmin(mi)
        i = mi[2][1]
        dsum = mi[1]
        @inbounds Dist[z,:] = [dsum,z,i]
    end
end

更新:

尝试#2失败。我试图计算最小距离而忘记了索引。这对于我的应用程序不是理想的,但是我可以接受。但是,这仅在第一个数组只有一行时才能正常工作。我试图通过使用mapslices解决此问题,但这不起作用。

using CuArray
a = rand(1,3)
b = rand(3,3)

a = CuArray(a)
b = CuArray(b)

function GK(m1, m2)
    reduce(min, sum((m1 .- m2) .^ 2,dims=2) .^ 0.5)
end

mapslices(GK(b), a, 2)

更新:

通过使用外循环来取得进展,但是肯定有更好的方法吗?

using CuArray
using BenchmarkTools
aa = rand(2,3)
bb = rand(5000000,3)

a = CuArray(aa)
b = CuArray(bb)

function GK(m1, m2)
    reduce(min, sum((m1 .- m2) .^ 2,dims=2) .^ 0.5)
end

function D(a,b)
    Dist = Array{Float64}(undef,size(a,1),1)
    for i in 1:size(a,1)
        Dist[i] = GK(a[i,:]',b)
    end
    return Dist
end

@benchmark test = D(a,b)
@benchmark test = D(aa,bb)

更新:

在我以前的分布式版本,修改后的分布式版本,GPU版本和串行版本之间进行一些基准测试。编辑:在进行1000亿次比较后,GPU版本不再胜过我以前的分布式版本...关于为什么这样做的任何想法是吗??

using Distributed
using SharedArrays
using CuArrays
using BenchmarkTools

aa = rand(4,3)
bb = rand(500000,3)
a = CuArray(aa)
b = CuArray(bb)

function MED3D(m1, m2)
    n1::Int = size(m1,1)
    Dist = SharedArray{Float64}((n1,1))
    @sync @distributed for k in 1:n1
        Dist[k] = MD3D(m1[k,:]', m2)
    end
    return Dist
end

@everywhere function MD3D(v1, m2)
    dsum::Float64 = Inf
    dtemp::Float64 = Inf
    for j in 1:size(m2,1)
        @inbounds dtemp = sqrt((v1[1] - m2[j,1]) * (v1[1] - m2[j,1]) + (v1[2] - m2[j,2]) * (v1[2] - m2[j,2]) + (v1[3] - m2[j,3]) * (v1[3] - m2[j,3]))
        if dtemp < dsum
            dsum = dtemp
        end
    end
    return dsum
end

function MED3DGK(m1, m2)
    n1::Int = size(m1,1)
    Dist = SharedArray{Float64}((n1,1))
    @sync @distributed for k in 1:n1

        @inbounds Dist[k] = GK(m1[k,:]',m2)
    end
    return Dist
end

@everywhere function GK(m1, m2)
    reduce(min, sum((m1 .- m2) .^ 2,dims=2) .^ 0.5)
end

function D(a,b)
    Dist = Array{Float64}(undef,size(a,1),1)
    for i in 1:size(a,1)
        @inbounds Dist[i] = GK(a[i,:]',b)
    end
    return Dist
end

@benchmark test = D(a,b)
@benchmark test = D(aa,bb)
@benchmark test = MED3D(aa,bb)
@benchmark test = MED3DGK(aa,bb)

更新:

使用NearestNeighbors.jl进行分布式处理。关于如何使其更快的想法?

function MED3D(m1, m2)
    m2 = Matrix(m2')
    kdtree = KDTree(m2)
    n1::Int = size(m1,1)
    Dist = SharedArray{Float64}((n1,1))
    Ind = SharedArray{Float64}((n1,1))
    @sync @distributed for k in 1:n1
        Ind[k,:], Dist[k,:] = knn(kdtree, m1[k,:], 1)
    end
    return [Ind,Dist]
end

1 个答案:

答案 0 :(得分:1)

我不确定它对您的情况是否有帮助,但是默认情况下,当获取切片 m1[k,:] 时,julia 会复制该内存(尽管这可能取决于 knn 函数对该切片的作用) .

如果将其更改为 knn(kdtree, @view m1[k,:], 1)

是否有任何改进