Pure Julia의 행렬 연산 라이브러리 Gaius.jl에서 Intel MKL을 물리 치고 싶습니다.

8869 단어 mklJulia
LoopVectorization.jl 을 사용하면 Pure Julia에서 Intel MKL에 필적하는 속도의 행렬 연산을 할 수 있다는 것으로 커뮤니티가 고조되고 있다 같다.

게다가 LoopVectorization.jl을 사용한 BLAS-like 라이브러리인 Gaius.jl

LoopVectorization.jl이란?



Julia의 for 루프를 벡터화해 주는 @avx 라는 매크로를 제공해 줍니다. 공식 Example에 따라
function my_gemm!(Y, A, B)
    @avx for m in 1:size(A,1), n in 1:size(B,2)
        Ymn = zero(eltype(Y))
        for k in 1:size(A,2)
            Ymn += A[m,k] * B[k,n]
        end
        Y[m,n] = Ymn
    end
end

와 같이 작성하면 벡터화 된 행렬 행렬 곱 함수를 구현할 수 있습니다.

Gaius.jl이란?



LoopVectorization.jl에 의해 벡터화 된 행렬 행렬 곱 함수와 분할 통치를 결합하여 만들어진 BLAS-like 라이브러리입니다. 설치는
]add https://github.com/MasonProtter/Gaius.jl

그렇다면 OK. julia 버전이 1.3 이상이어야 하므로 주의합시다.

사용법은 이런 느낌.
using Gaius
d = 1000
A, B = randn(d,d), randn(d,d)
C = similar(A)
Gaius.mul!(C, A, B) # Gaius.jlを使って計算

using LinearAlgebra
D = similar(C)
mul!(D, A, B) # Julia組み込みの行列行列積
C  D # -> true

제대로 환경 변수 JULIA_NUM_THREADS 를 사용해 thread수를 지정해 두지 않으면 성능이 나오지 않기 때문에 주의. 스레드 수를 변경한 후에는 다시 컴파일해야 한다고 생각합니다.

성능 비교


GaiusLinearAlgebramul! 의 성능을 비교해 봅시다.

이번 테스트를 실시하는 환경은 다음과 같습니다.
Julia Version 1.3.1
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
      "CentOS release 6.5 (Final)"
  CPU: Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz:
                 speed         user         nice          sys         idle          irq
       #1-16  1200 MHz  9233372591 s       8111 s  147348681 s  8423904558 s          1 s
  Memory: 62.743385314941406 GB (60272.515625 MB free)
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, sandybridge)
Environment:
  JULIA_NUM_THREADS = 16

내장 mul!는 MKL을 사용합니다.
julia> BLAS.vendor()
:mkl

실험 결과



크기 N 정사각형 행렬을 임의로 생성하고 BenchmarkTools 를 사용하여 행렬 행렬 곱에 걸리는 시간을 측정합니다.

사용한 코드는 다음과 같다.
using BenchmarkTools, Gaius, LinearAlgebra
results_mkl, results_gaius = BenchmarkTools.Trial[], BenchmarkTools.Trial[]
for n in 100:100:5000
    A, B, Y = randn(n,n), randn(n,n), zeros(n,n)
    t_mkl = @benchmark mul!($Y, $A, $B)
    t_gaius = @benchmark Gaius.mul!($Y, $A, $B)
    push!(results_mkl, t_mkl)
    push!(results_gaius, t_gaius)
end

결과를 플롯합니다.



열심히 하고 있습니다만, 유석에 MKL를 쓰러뜨리는 것은 힘들군요. MKL 쪽이 2.5배 정도 빠릅니다. 생각보다 엉망이었습니다. 다른 환경에서 어떻게 될지 궁금한 곳입니다.
Float64 이외의 비교나 OpenBLAS와의 비교도 하고 싶었습니다만, 귀찮았으므로 생략하고 있습니다. (누군가 해주세요.)

요약



LoopVectorization.jl과 Gaius.jl을 소개하고 벤치 마크했습니다. 앞으로 기대하자. 다른 환경에서 시도한보고와 여기를 바꾸면 빨라질보고 등 기다리고 있습니다.

좋은 웹페이지 즐겨찾기