OpenCL을 들춰보며..

잡설..1

OpenCL이란 말은 들어본지가 참 오래되었던 것 같다. 여기에 OpenGL이라는 것도 있으니까 뭔가 소프트웨어적으로 가속을 가능하게 하는 라이브러리쯤으로나 여겼지 들여다 볼 생각을 하진 않았던 것 같다. 사실 OpenCL/GL이 눈에 띄는 곳이 주로 많은 계산량이 요구되는 게임이라 게임하기 급급한 차에 생소한 것이 보인다고 덜컥 설치하던 것을 중단하고 책을 들여다 볼 일은 없으니까 말이다.

이 둘의 차이점은 약자를 풀지 않아도 들어나지만 C는 computer를 의미하고 G는 graphic을 의미한다. 직역하면 각각은 개방형 컴퓨터 언어, 개방형 그래픽 언어가 된다. 개방형이라는 뜻은 어떤 조건에 국한되지 않는다는 것을 말한다. 즉, 모든 언어를 다 지원하고 모든 플랫폼상에서 다 지원이 되어야된다는 뜻으로 해석할 수 있는데 OpenCL은 지원언어가 C로 국한된다. 어찌되었든 지원하는 분야가 많아진다는 것은 그 라이브러리의 버전이 다양해지고 그에 따른 노동이 많이 들어갔다는 것을 의미하지 싶다.

사실 구분이 이렇게 될 뿐이지 OpenGL이라는 것도 OpenCL처럼 컴퓨터 자원을 최적화(병렬화)해서 이용하겠다는 취지이기 때문에 같은 문제를 OpenCL로도 OpenGL로도 풀 수 있겠지만 OpenGL을 이용하려면 나의 문제를 그래픽적인 방법으로 해석해서 풀어야 한다는 차이가 있다. API가 다른 이유로.

잡설..2

이와 같이 놓이게 되는 것들이 OpenMP (이미 살펴봤다), OpenMPI (MPI의 일종으로 보임), OpenACC 등인데 요새의 컴퓨팅은 진짜 그런 것인지 아닌지 모르겠으나, node 단위로는 OpenMP나 OpenCL 혹은 CUDA 등으로 node가 가진 컴퓨팅 자원을 총동원하고 그것을 MPI로 묶는 Hyper-Parallel Processing을 한다고 하는데, 어디서 이런 방식으로 병렬 프로세싱을 하는지 모르지만 공학적/경제적 의미로 보면 있는 지원을 놀린다는 것은 낭비를 의미하니까 모든 자원을 남김없이 최대한 가동해야 하는 것이 맞겠지만, 너무 빡빡해서 어설프게 만든 하드웨어는 일찌감치 수명을 다하거나 전력을 과하게 낭비한다거나 과열로 엄청난 소음을 일으킬 것 같은 느낌이 든다. 이것은 내가 그러한 조건에서 병렬처리를 해보았기 때문에 그런 것인데, 일례로 냉방이 잘 안되는 곳에 수십대의 Xeon workstation을 가져다 놓고 모든 core를 fully 기동하게 되면 그 소음과 열은 정말 엄청나다. 사실 요새 이런 일은 비트코인 채굴로 컴퓨터를 과하게 돌려야 할 이유가 없는 이들도 하고 있다고 듣긴 했다만.

MPI만 기동하겠다면 모든 core, 모든 node를 풀 가동하는 것을 의미하지만 여기에 OpenCL을 더 하겠다는 것은 GPU의 힘까지 더하겠다는 의미로 받아야 한다. 대개 많은 연산을 병렬로 수행하는 경우 그래픽 카드는 놀게 되는 것과 좀 다르다고 봐야하지 싶다.

잡설..3: Metal/CUDA/…

OpenCL로 초점을 옮겨보면 플랫폼이 NVIDIA graphic card로 국한되는 CUDA와 달리 최적화가 쉽지 않다고 한다. 또 한가지 사실은 MacOS의 경우에서는 10.14부터 OpenCL을 퇴출시키고 Metal이라는 프레임워크를 제공한다. 이미 version 2까지 나왔고 애플의 경우는 스스로 생산하는 PC/Laptop과 함께 계통이 다른 Smart Phone/Tablet 등이 있어서 이들의 개발 프레임워크를 통합하려는 치원에서 별도의 환경을 지원하게 된 것이니까 OpenCL로 뭘 해보겠다 하면 target은 Linux 환경으로 고착되는 게 아닌가 하는 생각이 든다. 그렇다고 Metal을 하자니 이것은 MacOS/iOS에 한정되고. 그런데 이런 식으로 사고하게 되면 (그러니까 노력투자 대비 효과) 컴퓨터 세계에서 배워둬야 할 것은 없다고 본다. 어차피 시간 지나면 다 옛날 (놀이)기술이 되는 것이니.

마치 increment build를 하듯이 fundament를 세우고 그 위에 기존의 fundament와 다른 점을 학습하면 부담은 줄어든다.

어쨌든 이럴 바에야 (OpenCL이 플랫폼에 상관없는 병렬처리 만병통치약이 되지 못할 바에야), 또 어차피 NVIDIA H/W를 쓸 거라면 그냥 CPU에 의지하지 말고 CUDA만 잘 쓰는 게 낫지 않을까 하는 생각도 하게 된다. OpenCL이나 Metal을 쓰면 한 단계 걸쳐가는 결과가 되니까 이 역시도 빛 좋은 개살구인 OpenMP 같은 것 아닐까 하는 우려도 되고 말이다.

확실히 C++11 부터 지원되는 thread (혹은 pthread)를 잘 쓰는 것 보다 OpenMP는 못한 면이 있다. 어찌보면 OpenMP가 세련되 보이긴 하지만, Open MP가 지원되는 환경 보다 C++11이 지원되는 환경이 더 많으니까.

OpenCL이 뭐냐 그래서?

아주 간단하게 보면 OpenCL은 병렬 연산을 수행하는 주체인 kernel과 그 kernel을 통해 주고 받는 데이터 관계를 정의해주는 것으로 이루어진다고 보면 된다.

즉, 내가 convolution 연산을 수행해야한다고 보면 (어차피 discrete한 세계에서 convolution은 matrix multiplication이라고 봐도 무방하다) 곱하고 더하는(누적하는) 과정(multiply and accumulate)이 가장 기초적인 과정이 되고 이것을 loop로 돌리는 과정이 좀 더 큰 과정이 되겠다. 따라서 이 loop을 하나의 함수로 만들어보면 그 자체가 kernel이 되겠다.

DSP로 보면 mac을 loop로 정해진 만큼 돌리는, MAC은 속도를 올려주려면 참조하는 데이터가 모두 local memory여야 할테고 loop에서 indirect addression을 해야하는 것이어야 할 것이다.

그러니까, 더 풀어보자면

일련의 과정을 대행 해주는 프레임워크로 보면 된다.

CUDA라든가 그외의 병렬 처리 array를 다뤄본 사람이라면 그 프로그래밍 방법이 크게 다르지 않다고 생각할 것이다. CUDA도 사실상 이와 별로 다르지 않다. 사실 다른 가속기가 되어도 내용은 다르지 않다. DMA로 데이터와 명령을 보내주고 다시 DMA로 결과 데이터를 가져오는 과정의 연속일 뿐이다.

이것을 assembly를 직접 써서 하긴 괴로우니까 고차원 언어 형식을 빌어다 써야 하니까 어떻게 하면 좀 폼나게 쓸까 해서 이런 저런 형태가 나올 뿐.

애초의 설계야 최대한 쓰기 쉽고 단순하게 가져가려했겠지만 지원하는 하드웨어를 다양하게 하고 이런 저런 변종을 모두 지원하려고 보니 함수의 개수도 많아지고 들고 나고 하는 데이터의 형식이나 kernel 함수를 넣는 방법도 지저분해졌지 싶다. 그래서 생각보다 모양새는 별로 깔끔하지 않다. 차라리 직설적인 CUDA를 그냥 쓰는 게 낫지 하는 생각도 든다. 사실 CUDA는 NVDIA H/W에만 지원이 되니까 경쟁자인 AMD 입장에서는 OpenCL에 더 열을 올렸을 게 맞다. GPU를 집적하는 인텔의 입장도 마찬가지였을 것이다만.

그래픽 가속기든 무슨 가속기든..

GPU는 거창하게 볼 것도 없이 그냥 SIMD (Single Instruction Multiple Data) 엔진 덩어리일 뿐이다. SIMD 엔진이 만들기 쉽고 집적도도 높일 수 있고 다양한 응용분야에 적용이 가능하기 때문인 것이다. 이를테면 명령어 한 개로 4개 8개 16개…의 입력데이터의 곱셈이나 덧셈을 한꺼번에 해낸다거나 하는 것 말이다.

예를 들어 8비트 데이터를 처리하는데 128b의 통로를 가지고 있다고 하면 16개의 데이터를 입력 시킬 수 있으니까 덧셈을 여기에 적용하면 16개 입력을 한꺼번에 처리할 수 있듯 말이다. 예전에도 이런 프로세서들은 많았다. 이름만 다 달리 불렸을 뿐이고 장점을 각기 다르게 부각시켰지 사실 SIMD engine이다. MIMD도 있고 하지만 하드웨어의 이용률, 프로그래밍의 간결함 등등 노력대비/투자대비 성능이 SIMD 엔진이 우월했기 때문이라고 본다.

자연계에서 많은 연산을 요구하는 것은 사실상 convolution 연산 뿐이다. Rendering도 그렇고 Lense 효과 (image filter)도 그렇고 audio signal을 처리하는 것도 마찬가지고. 이게 AI (Deep learning)으로 가도 달라지는 게 없다. 대부분은 vector/matrix operation이고 다만 nonlinear 연산 (ReLu: Rectified Linear Unit? 사실상 음수부분만 끊어버리는 함수)이 추가된 정도니까 기존 SIMD array의 끝단에서 음수면 끊어버리고 이후의 연산을 고려해서 scale up/down만 추가해주면 AI dedicated processing engine이 되는 것이니까 하드웨어가 더 복잡해질 이유도 없고 살짝 변경한 것만으로도 기존의 graphic core를 거의 그대로 사용하면서도 AI를 대응하는 셈이니까 거저먹기라고 봐야지 싶다.

대충의 결론

OpenCL은 사실 그 용도가 엄밀히 말해서 GPU를 활용하는 데 있는데, 사실상 SIMD array에서 실행되는 프로그램 (kernel)을 해석해주고 입출력 데이터를 주고 받게끔 해주는 프레임웍이라고 보면 된다. 표면적으로는 특정 device에 국한되지 않는 software를 만들어야 할 때 필요한 기술이 될 것이다만, 역시나 진정 최적화를 노린다면 device dependent하게 갈 수 밖에 없고, 그러다보면 이 바닥 표준이 되어버린 CUDA로 가고 NVIDIA H/W를 premium 주고 사게 되는 게 아닐까 한다.

다음은 OpenGL과 Metal/CoreML을 살짝 들여다봐야할 것 같다.