나는 왜 Julia 를 사용하는가?

YebinPapa·2022년 12월 16일
1

Velog 의 코드블럭이 julia 언어에 대한 syntax highlighting 을 빨리 해줬으면 좋겠다...


나는 python을 1998년 경부터 사용해 왔다. 나는 프로그래밍을 할 줄 아는 과학자일 뿐, 프로그래머는 아니다. 내 연구/개발에 python 을 사용하여 수치해석, 실험 장치 구동, 데이터 분석 등등을 해 왔다. numpy나 matplotlib 이 있기도 전부터 사용했고, 그때는 아마 numbers 와 numarray 라는 두 라이브러리가 수치해석쪽에 널리 사용되었던것 같다. 어느 순간에 둘이 합쳐져서 numpy 가 되어 지금까지 잘 사용되고 있다. 솔직히 2022년이 들어설 때 까지만 해도 내가 어느정도 다룰 줄 아는 언어는 python 이 유일했다. Julia 라는 언어는 2021년쯤부터 이름을 들었고, 스크립트 언어인데 빠르다 라는 것만 알고 있었다.

올해 모종의 일을 수행하기 위해 코딩을 해야 할 일이 생겼고, 당연히 파이썬으로 코드를 짜서 돌렸다... numpy 를 주로 이용해서 코딩을 했다. 내 기대보다 많이 느렸다. 이것은 한번 작업해서 결과를 얻으면 되는 것이 아니라, 짠 코드를 데이터가 쌓일 때마다 계속 반복 수행시켜야 하는 일이었다.

뭔가 알고리즘 적으로 개선의 여지가 있는 것은 아니었다. 알고리즘은 이미 수십년전부터 알려져 있었으며, 어려운 것도 아니었다. 푸리에/역 푸리에 변환과 1차원 인터폴레이션을 무지 많이 하는 것, 그리고 같은 크기의 배열(array) 를 많이 곱하고 더하고 빼는 것 뿐이었다. 한번에 10메가 정도의 이미지 파일 수백장을 읽어서 이 작업을 해야한다. 문제는 루프(for) 가 많이 돌아간다는 것이다. 루프가 많이 돌아가는 것은 python 에 쥐약이다. for 를 사용하지 않고 numpy 로 처리할 수 있으면 좋겠지만, 그 방법을 발견하지 못했다.

여기서 파이썬을 계속 쓴다면 내가 아는 선택지는 다음과 같았다.

  1. 이 부분을 C/C++/Fortran 으로 짠다.
  2. Cython 이나 numba 를 사용한다.
  3. multiprocessing 을 이용한다.

python 은 GIL(global interpreter lock) 때문에 multithreading 이 이 분에서는 의미가 없다. 한번에 읽는 데이터의 총 크기가 10기가 정도 인데 multiprocessig 을 하려면 사용하는 프로세서 개수만큼 곱해서 필요하므로(맞나?) 이것도 선택지는 아니다. C/C++/Fotran 으로 짜는것은 배보다 배꼽이 크다고 생각했다. Cython 이나 numba 를 써볼 까 하다가, julia 를 배워보기로 했다.

Julia 는 빠르다. 특히 루프가.

이미 짜논 python 코드를 julia 로 line-by-line 으로 바꾸기 시작했다. Julia 공식 문서와 구글 써치를 이용하여 언어를 하나하나 배워 나갔다. Python 과 Julia 를 초보에게 소개하는 문서를 보면 큰 차이를 못느끼게 되어있다. 예를 들면 인자로 주어지는 반지름에 대해 원의 면적을 구하는 함수는 각각 다음과 같다.

# Python
import numpy as np

def area_of_circle(radius):
	return np.pi*radius*radius
# Julia
function area_of_circie(radius)
	return pi*radius*radius
end

처음 느낀 두 언어 사이의 큰 차이는 아주 간단한 것이었다. 예를 들어 256x256 크기의 배열 에 이 배열의 중앙을 중심으로 반지름 50 안에 있으면 1.0, 밖에 있으면 0.0 의 값을 갖도록 하겠다고 하자. 우선 아주 기초적인 파이썬 코드는 다음과 같다.

import numpy as np

Rc = 50**2
img = np.zeros((256, 256))
for i in np.arange(256):
    for j in np.arange(256):
        if (i-125)**2+(j-125)**2 < Rc:
            img[i, j] = 1.0

이제 np.meshgrid 함수를 이용하여 좀 세련되게 짜 보면 다음과 같다.

import numpy as np

X, Y = np.meshgrid(np.arange(256), np.arange(256))
R = (X-125)**2+(Y-125)**2
img = np.zeros(R.shape)
img[R<50**2] = 1.0

jupyter 에서 수행시간을 측정해보니 앞의 것이 20.4 ms, 뒤의 것이 418 µs 가 나왔다. meshgrid 를 이용하는 것이 50배 정도 빨랐다. python 에서 이런 수치 계산 코드를 짜다보면 forwhile 같은 루프를 실행시키는 것을 피하고 numpy 에서 제공하는 vectorized 된 함수를 사용해야 한다는 일종의 강박이 생기게 된다. 당연히 np.meshgrid 에 상응하는 julia 함수가 있을것이라고 생각했지만, 내가 구글에서 찾은 답은 "그냥 for 루프 돌리세요" 였다.

이에 대한 julia 코드는 다음과 같다.

Rc = 50.0^2
img = zeros(Float64, (256, 256))
for j in 1:256, i in 1:256
    if (i-125)^2+(j-125)^2<Rc
        img[i, j] = 1.0
    end
end

같은 PC 에서, jupyter 환경에서 실행시간은 124 μs 정도였다. numpy 보다 3배 이상 빨랐다.


Julia 에서는 vectorization 이 오히려 성능에 큰!! 해가 되는 경우가 많다. 예를 들어,

function test3(img)
    h, w = size(img)
    q1, q2 = 0.0, 0.0
    for j in 1:w, i in 1:h
        q1, q2 = cos.([i, j])
    end
end

function test4(img)
    h, w = size(img)
    q1, q2 = 0.0, 0.0
    for j in 1:w, i in 1:h
        q1, q2 = cos(i), cos(i)
    end
end

를 보자. test3test4 는 루프 안에서 정확히 같은 일을 수행한다. 차이는 q1, q2 를 구할 때, vectorizaion 을 사용했는지 아닌지 뿐이다. 인자 img 에 임의의 256x256 배열을 넝ㅎ고 수행했을 때, test3 함수는 5.025 ms, test4 함수는 1.030 ms 의 시간이 걸렸다. julia 에서 섯부른 vectorizaion 은 오히려 큰 해가 된다.


루프문이 빠르다는 것(그것도 매우 빠르다는 것)은 속도에서의 이점 뿐만이 아니다. 만약 당신이 어떤 새로운 알고리즘을 시험해 봐야 할 때 아마 당신의 머릿속에 떠오르는 것을 구현하는 데는 루프를 쓰는 것이 vectorized 된 어떤 것보다 (아마도.. 높은 확률로..) 구현하기 쉬울 것이다. 그런데 그것이 실제로 쓸만한지 확인하려면, 파이썬이나 매트랩에서는 vectorized 된 함수의 조합을 사용하던가 python 이라면 cython 이나 numba 등을 알아 보야 할 것이다.(매트랩은 잘 모르니..) 그러나 Julia 에서는 그냥 루프로 돌리면 (상당수준까지 만족스럽게) 된다.


Multithreading

개인적으로 아주 만족스러운 부분이다. for 루프 앞에 Threads.@threads 만 붙였는데 계산 속도가 몇배가 빨라진다. 물론 항상 그런건 아니지만 많은 경우 멀티스레드를 이용하여 계산속도를 빠르게 할 수 있다.


Julia 의 단점

  1. Julia 는 어떤 함수를 구현하여 처음 실행 시킬 때 컴파일 타임이 필요하므로 첫번째 수행에서 수행시간이 많이 걸린다. 이것이 가장 성가실때는 ploting 할 때인데 python 의 경우 matplotlib 을 사용할 때 특별히 시간이 많이 걸리는 플롯이 아니라면 거의 실시간으로 그려주지만, julia 의 경우는 첫번째 플롯은 매우 느리고, 두번째 플롯부터도 (python 에 비해) 상당히 느리다. 이것은 좀 상당히 거슬린다.

  2. Julia 는 2012년에 발표된 최신 언어이다. 그리고 많은 변화를 겪었다. 당신이 구글링으로 어떤 기능을 찾았는데, 그 기능이 이미 사라졌거나, 사라질 예정일 수도 있다. 예를 들어 julia 초기 버젼에 사용했던 linspace 함수는 파이썬이나 매트랩의 동명의 함수와 같은 기능을 하는 함수이지만 이제는 julia 공식 라이브러리에서 사라진 함수이다. 물론 당신이 구현해서 쓸 수는 있다. 문제는 많은 웹상의 이전 자료들이 linspace 함수를 사용하기 때문에 혼동을 줄 수 있다.

  3. 주관적인 느낌이지만 Plots.jl 이든 Makie.jl 이든 python 의 플로팅 툴과 비교하여 느릴 뿐만 아니라 안예쁘다.

  4. velog 에서 code block 의 syntex highlighting 이 안먹힌다.

  5. 만족스러운 GUI tool 을 찾지 못했다. (PyQt 같은 것.. QML.jl 있긴 한데..)

  6. 많이 사용되는 패키지중에도 가끔 예기치 않는 오류가 날 때가 있다. (JDL 이라든가..)

  7. 신생 언어이므로 당신이 원하는 라이브러리/패키지가 없을 가능성이 python 보다는 당연히 높다.

  8. 이 언어를 배워 취직하기는 (아직까지는) 거의 불가능하다.

  9. 한글로 된 자료가 매우 부족한것은 당연하다.

profile
Julia, Python, JS;Physics, Math, Image processing

0개의 댓글