Analyse julia package’s source code to learn coding tips. Below are some notes.

  1. Distances.jl
  2. lightML.jl
  3. lightOPT.jl
  4. Optim.jl

Distances.jl-simd

主要知识点是 @inline, @simd, @imbounds, typealias, type, <:

typealias UnionXX Union{xx,xx,xx}

这种用来表示一种类型的集合, 非常常用

当定义一个类型后, 即声明type xx end

创建的时候可以像函数一样使用

x1,x2,x3 = s

s = (x1,x2,x3)

这种方法的使用

这个库是对距离计算的一个优化包, 我看了他的实现后发现很巧妙, 用了@simd和@imbounds来并行优化, 这个技巧算是一种向量化加速的技巧,使用SIMD.

核心部分是

function evaluate(d::UnionMetrics, a::AbstractArray, b::AbstractArray)
    if length(a) != length(b)
        throw(DimensionMismatch("first array has length $(length(a)) which does not match the length of the second, $(length(b))."))
    end
    if length(a) == 0
        return zero(result_type(d, a, b))
    end
    s = eval_start(d, a, b)
    if size(a) == size(b)
        @simd for I in eachindex(a, b)
            @inbounds ai = a[I]
            @inbounds bi = b[I]
            s = eval_reduce(d, s, eval_op(d, ai, bi))
        end
    else
        for (Ia, Ib) in zip(eachindex(a), eachindex(b))
            @inbounds ai = a[Ia]
            @inbounds bi = b[Ib]
            s = eval_reduce(d, s, eval_op(d, ai, bi))
        end
    end
    return eval_end(d, s)
end

这里

可以看到分为4个部分, eval_start(), eval_op(), eval_reduce(), eval_end(),这四个部分把原来的计算并行化了, reduce可以看做一个向右的fold, 使用eval_op()来进行并行化, @imbounds来声明并行部分, 还有一个技巧就是cosine dist余弦距离的实现

# Cosine dist
function eval_start{T<:Real}(::CosineDist, a::AbstractArray{T}, b::AbstractArray{T})
    zero(T), zero(T), zero(T)
end
@inline eval_op(::CosineDist, ai, bi) = ai * bi, ai * ai, bi * bi
@inline function eval_reduce(::CosineDist, s1, s2)
    a1, b1, c1 = s1
    a2, b2, c2 = s2
    return a1 + a2, b1 + b2, c1 + c2
end
function eval_end(::CosineDist, s)
    ab, a2, b2 = s
    max(1 - ab / (sqrt(a2) * sqrt(b2)), zero(eltype(ab)))
end
cosine_dist(a::AbstractArray, b::AbstractArray) = evaluate(CosineDist(), a, b)

可以看到这里fold迭代的是一个set, 利用这个技巧, 可以巧妙的进行计算中间数, 最后在eval_end()中计算.

lightML

这个是我自己写的机器学习框架

分成三个部分