확장형 고성능 컴퓨팅 수강 기록

박건도
5 min readDec 28, 2020

데이터사이언스 대학원에 입학한지 2학기째가 되었고, 심화 과목이라고 할 수 있는 확장형 고성능 컴퓨팅 수업을 듣게 되었다. 최근의 데이터사이언스 또는 인공지능 트렌드는 많은 데이터와 Over-parameterize된 알고리즘을 통해서 성능을 끌어올리는 방향인데, 이를 위해서는 컴퓨팅 리소스의 효과적인 활용이 필수적이다. 관련 학회 등을 보면 정말 다양한 아이디어들이 쏟아져 나오고, 비슷한 아이디어를 생각했다 하더라도 빠른 시간 안에 다양하게 실험 및 검증을 진행하지 못해 인정받지 못하는 경우가 많다. 따라서 제한된 리소스를 최대한 낭비없이 잘 활용하는 것이 중요하고, 이번 수업에서는 이 목적을 달성하기 위한 제반 지식과 기술들을 배웠다. 기술이야 수업을 통해 배우기보다는 스스로 찾아보고 적용해 보는 부분이 크기 때문에 수업에서는 지식 분야에 더 집중해서 알려주셨다. 뿐만 아니라 최근의 성능 향상은 많은 부분이 병렬화에서 나오기 때문에 병렬화를 위한 지식과 노하우에 대해 배울 수 있었다.(사실 병렬화는 이론이 많다기보다는 경험이 중요하다고 하신다.)

이번 글에서는 한학기 동안 배웠던 내용을 간단히 생각나는대로 적어본다. 수업이 끝나면 다 까먹기 때문에 나중에 필요할 때 기억을 되살릴 목적으로…. ㅎㅎ

  • 기본적으로 최적화는 C/C++이 기본인 것 같다. Python같은 언어에 비해서는 편의기능이 없어서 다루기가 쉽지 않지만 그만큼 사용자가 Customize할 수 있는 여지가 많고 Overhead가 적다. 그리고 메모리 접근을 직접 통제할 수 있다는 점이 가장 크다고 생각한다.
  • Process/Thread: 컴퓨터에서 처리하는 업무 단위로 보면 되고, 비슷한 개념이지만 Process 안에 여러 개의 Thread가 있다고 보면 된다. Thread간에는 Data/Code 등을 공유하는 부분이 많지만, process간에는 명시적으로 공유하지 않으면 공유되지 않는다.
  • Superscalar processor: 한번에 여러 개의 Thread를 Issue/Fetch할 수 있는 프로세서
  • Simultaneous multi-threading(SMT, hyperthreading): CPU 성능 같은 걸 볼 때 하이퍼쓰레딩이라는 말을 많이 들어봤었다. 물리적인 하드웨어를 늘린 것이 아니고 여러 Thread를 실행할 때 발생하는 비효율을 최대한 줄여서 성능을 높이는 방식이라고 보면 될 것 같다. Superscalar processor과 비교하면 각 Cycle마다 context switch를 함으로써 vertical waste를 줄이고, Execution할 instruction을 효율적으로 선택해서 horizontal waster를 줄이는 장점이 있다.
  • 메모리 구조: 이번 수업을 들으면서 가장 많이 느낀 건메모리 구조/ 메모리 접근 방식 등을 잘 생각하면서 코딩을 하는 것이 성능에 미치는 영향이 정말 크다는 것이다. 이전에는 메모리에 대해 크게 생각을 안해봤었는데 실제로 접해보니 많은 차이를 느낄 수 있었다. 예를 들면 Cache에 있는 정보를 접근하는 것과 memory에 접근하는 것이 300배 가량 시간 차이가 난다고 한다.
  • 메모리는 Hierarchy가 있는데 L1 ~L4 cache, Main memory, 하드 디스크의 순서로 보면 된다. 앞에 있을수록 용량은 작은 대신 빠르고, 뒤에 있을수록 느리고 용량이 크다. 이는 CPU 기반의 하드웨어 시스템에 해당하는 내용이고, GPU에는 별도의 main memory와 Local memory, Cache 등이 있다. CUDA 문서에 이러한 구조가 잘 설명되어 있다. CPU의 Main memory와 GPU의 main memory는 별개이고, 둘 간의 통신은 그리 빠르지 않다.
  • OpenMP: C에서 #pragma를 이용하여 간단하게 Thread병렬화 할 수 있는 라이브러리이다.
  • MPI(Message Passing Interface): 프로세스간에 정보를 주고 받을 수 있도록 해주는 인터페이스이다. HPC에서 Node간 통신할 때 사실상 표준이다. Node를 한개만 쓸거라면 위의 OpenMP를 이용하여 Thread 병렬화를 하는 것이 더 좋다. 프로세스간에는 메모리를 공유하지 않으므로 필요한 정보들을 Copy하는 오버헤드가 생기기 때문이다.
  • OpenCL: CUDA에 대항하여 여러 회사들이 연합해서 만든 병렬 프로그래밍 라이브러리이다. GPU뿐 아니라 Intel CPU, ARM CPU 등에서도 작동한다. CUDA에 비하면 자료가 많이 안나오는 것 같다.ㅠㅠ
  • CUDA: NVIDIA에서 나온 GPU를 잘 활용할 수 있도록 NVIDIA에서 관리하는 라이브러리이다. 아마 실용적인 측면에서 앞으로 가장 많이 접하게 될 것 같다. Document가 상세하게 되어 있고, 이 때문에 많이들 쓴다고 한다.(OpenCL에 비해서) 주요 CUDA 명령어를 좀 적어보면
  • cudaMalloc: GPU에 메모리를 최초 할당
  • cudaMemcpy: CPU -> GPU / GPU->CPU로 정보를 옮길 때 쓴다.
  • 커널함수<<<gridDim, blockDim>>>: GPU에서 함수를 실행시킬 때 쓴다. gridDim과 blockDim은 work group을 정의하기 위해 쓴다.
  • __global__: kernel 함수(GPU에서 동작할 함수)를 정의할 때 앞에 붙여준다.
  • __shared__: GPU 내부의 Shared memory를 활용하기 위해 쓴다. Tiling 기법을 적용할 때 사용할 수 있다.
  • __syncthreads(): 커널함수 안에서 다른 Thread들과 싱크를 맞추기 위해 쓴다.
  • cudaFree: GPU의 메모리 릴리즈할 때 쓴다.

마지막 프로젝트 과제를 하면서 직접 cuda로 CNN 코드를 짜보았는데, 성능이 PyTorch에 비하면 형편없었다ㅠ 그만큼 Tensorflow나 PyTorch같은 라이브러리들은 딥러닝에 있어서는 최적화가 잘 되어 있는 것 같다. 앞으로 CUDA를 활용한다면 좀 색다른 걸 시도할 때? 정도가 될 것 같다.

--

--