Kinetica는 GPU를 이용한 in-memory DB로서, 주로 OLTP용보다는 OLAP용으로 사용됩니다. 아래에 간단한 TPC-H data와 query를 이용하여 일반 DBMS(여기서는 postgresql)와의 성능 비교 및 그때 CPU-GPU간의 NVLink가 어떤 효과를 내는지 nvprof로 분석해보았습니다. 아래 test는 모두 POWER9 + V100 GPU의 IBM AC922 서버로 진행했습니다.
Postgresql과 Kinetica 모두 TPC-H에서 제공되는 dbgen으로 생성한 data를 사용했습니다. 여기서 DB 크기는 10GB로 했습니다. 이렇게 하면 delimeter가 '|'로 되어 있는 SAM file들이 만들어지는데, 실제로 DB에 load를 하려면 맨 끝에 붙은 '|'은 제거해야 하더군요.
[root@localhost dbgen]# nohup ./dbgen -s 10 &
[root@localhost dbgen]# ls -ltr *.tbl
-rw-r--r--. 1 root root 14176368 Oct 23 09:35 supplier.tbl
-rw-r--r--. 1 root root 389 Oct 23 09:35 region.tbl
-rw-r--r--. 1 root root 243336157 Oct 23 09:35 part.tbl
-rw-r--r--. 1 root root 1204850769 Oct 23 09:35 partsupp.tbl
-rw-r--r--. 1 root root 1749195031 Oct 23 09:35 orders.tbl
-rw-r--r--. 1 root root 2224 Oct 23 09:35 nation.tbl
-rw-r--r--. 1 root root 7775727688 Oct 23 09:35 lineitem.tbl
-rw-r--r--. 1 root root 244847642 Oct 23 09:35 customer.tbl
Postgres에서는 다음과 같이 dbgen에 포함된 dss.ddl script를 이용하여 필요한 table들을 생성했습니다.
[root@localhost dbgen]# su - postgres
Last login: Mon Oct 22 17:27:48 KST 2018 on pts/1
-bash-4.2$ createdb dss
-bash-4.2$ psql dss
psql (9.2.23)
Type "help" for help.
dss=# \i /home/data/2.17.3/dbgen/dss.ddl
dss=# \d ORDERS
Table "public.orders"
Column | Type | Modifiers
-----------------+-----------------------+-----------
o_orderkey | integer | not null
o_custkey | integer | not null
o_orderstatus | character(1) | not null
o_totalprice | numeric(15,2) | not null
o_orderdate | date | not null
o_orderpriority | character(15) | not null
o_clerk | character(15) | not null
o_shippriority | integer | not null
o_comment | character varying(79) | not null
그 다음에 다음과 같이 SAM file에서 postgresql table 안으로 loading을 합니다. 아래는 LINEITEM의 table 예만 들었습니다.
dss=# copy lineitem from '/home/data/2.17.3/dbgen/lineitem.csv' with (FORMAT csv, DELIMITER '|');
COPY 59986052
Kinetica에도 이 SAM file을 만들고 load 하기 위해서는 다음과 같은 menu를 이용하면 됩니다. 다만 Kinetica는 GPU를 이용한 분산 DB이기 때문에, shard key를 지정하는 등 추가적인 설정 과정을 거쳐야 합니다. (여기서는 상세히 표시하지 않았습니다. 저도 제가 직접 못하고 저희 파트너사인 Unione INC의 엔지니어 도움을 받았습니다.)
먼저, TPC-H의 query들 중 1개씩의 query를 수행해보겠습니다. 이 query는 join 등이 그렇게까지 크지 않은 query라서 GPUdb가 일반 RDBMS에 비해 그다지 더 유리하지도 않은 query입니다. 그런데도, 또 별다른 tuning 없이도, Kinetica가 20배 정도 빠른 것을 보실 수 있습니다. 모두 2번씩 돌린 것이므로, postgresql에서도 data는 이미 memory에 cache된 상태라서 disk 병목은 전혀 없다고 보셔도 됩니다.
-bash-4.2$ time psql -d dss -f /home/data/RunQuery/q16.sql > /tmp/ooo
real 1m1.267s
user 0m0.374s
sys 0m0.000s
[root@localhost ~]# time /opt/gpudb/bin/kisql -host 127.0.0.1 -f /home/data/RunQuery/q16.sql > /tmp/iii
real 0m3.046s
user 0m3.729s
sys 0m0.770s
특히 Kinetica의 경우는 아래처럼 query 결과에 Query Execution Time과 Data Transfer Time을 각각 명기합니다. GPUdb에서는 query execution보다 data를 transfer하는데 더 많은 시간이 걸린다는 것을 보실 수 있습니다. 이런 것 때문에 특히 CPU와 GPU간의 연결이 CPU냐 GPU냐가 매우 중요합니다.
| Brand#54 | ECONOMY PLATED BRASS | 14 | 4 |
| Brand#55 | STANDARD BURNISHED BRASS | 14 | 4 |
+------------+-----------------------------+----------+----------------+
Rows read = 27840
Query Execution Time: 0.495 s
Data Transfer Time: 2.283 s
이 시스템에 CPU core는 32개나 있지만 GPU는 딱 2장 뿐입니다. 이럴 경우 저런 query를 10개씩 병렬로 수행하면 CPU가 더 빠를 수도 있지 않을까요 ? 꼭 그렇지는 않습니다.
여기서는 TPC-H의 16번과 19번 query 2개를 5번씩, 총 10개를 한꺼번에 수행하는 방식으로 돌리겠습니다.
Postgres에서 돌릴 script는 다음과 같습니다.
-bash-4.2$ cat 1.sh
date
echo "Starting"
psql -d dss -f /home/data/RunQuery/q16.sql &
psql -d dss -f /home/data/RunQuery/q19.sql &
...(총 10줄)
wait
date
echo "Finished"
Kinetica에서 돌릴 script도 사실상 똑같은 내용입니다.
[root@localhost ~]# cat /tmp/1.sh
date
echo "Starting"
/opt/gpudb/bin/kisql -host 127.0.0.1 -f /home/data/RunQuery/q16.sql &
/opt/gpudb/bin/kisql -host 127.0.0.1 -f /home/data/RunQuery/q19.sql &
/opt/gpudb/bin/kisql -host 127.0.0.1 -f /home/data/RunQuery/q16.sql &
/opt/gpudb/bin/kisql -host 127.0.0.1 -f /home/data/RunQuery/q19.sql &
... (총 10줄)
wait
date
echo "Finished"
각각의 수행 결과는 다음과 같습니다. Kinetica도 GPU가 2장 뿐인 환경에서도 10개의 동시 query를 잘 수행해내며, 여전히 6배 정도 빠릅니다.
Postgresql는 다음과 같습니다.
-bash-4.2$ time ./1.sh > p.txt
real 1m6.947s
user 0m1.891s
sys 0m0.055s
Kinetica는 다음과 같습니다.
[root@localhost ~]# time /tmp/1.sh > /tmp/k.txt
real 0m8.545s
user 0m29.965s
sys 0m20.525s
Kinetica에서 이 query를 처리하기 전에, nvprof를 이용해 profile data를 받기 위해서 Kinetica의 구동 script 중 일부를 수정한 뒤 restart 해주어야 합니다. 수정은 다음과 같이 간단합니다. 아래 붉은 색 부분의 명령어를 삽입해주기만 하면 됩니다.
[root@localhost ~]# vi /opt/gpudb/core/bin/gpudb
...
# nohup $HOST_MANAGER_CMD >> $HOST_MANAGER_LOG_FILENAME 2>&1 &
nohup /usr/local/cuda-9.2/bin/nvprof --log-file /tmp/nvprof/%p.txt --export-profile /tmp/nvprof/%p.nvvp --print-gpu-trace --profile-child-processes $HOST_MANAGER_CMD >> $HOST_MANAGER_LOG_FILENAME 2>&1 &
...
이렇게 얻은 profile data를 분석해보면, GPUdb의 대표적인병목인 cuda memcpy HtoD (CPU to GPU) 및 DtoH (GPU to CPU)의 사용되는 대역폭을 보실 수 있습니다. 대략 35GB/sec에 달합니다. 참고로, POWER9과 V100 GPU 사이를 연결하는 NVLink는 3개의 port를 aggregate시킨 것이라서, 이론상 단방향 대역폭이 75GB/sec (양방향 150GB/sec)에 달합니다. PCIe Gen3 버스의 이론상 단방향 대역폭이 16GB/sec(양방향 32GB/sec)에 불과하다는 것을 생각하면, Kinetica와 같은 GPUdb를 사용할 경우 CPU와 GPU의 연결은 반드시 NVLink가 되어야 한다는 것을 쉽게 아실 수 있습니다.
2018년 10월 25일 목요일
2018년 10월 5일 금요일
IBM이 자랑하는 POWER9 + V100 GPU의 조합이 H2O DriverlessAI에 어떤 도움이 될까 ?
H2O Driverless AI는 model training 중 GPU에서 돌리는 것이 더 효과적이라고 판단될 때마다 필요에 따라 드문드문 GPU를 사용합니다. 이는 우측 하단의 "GPU usage" tab을 클릭하면 아래와 같이 보실 수 있습니다.
물론 nvidia-smi 에서도 모니터링하실 수 있습니다. GPU 1개당 1개의 process가 수행되는 것이 아니라, GPU 메모리가 허용하는 한 필요에 따라 GPU 1개당 여러 개의 process들이 수행되기도 합니다.
Fri Oct 5 03:36:45 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 396.26 Driver Version: 396.26 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla P100-SXM2... On | 00000002:01:00.0 Off | 0 |
| N/A 34C P0 64W / 300W | 455MiB / 16280MiB | 40% Default |
+-------------------------------+----------------------+----------------------+
| 1 Tesla P100-SXM2... On | 00000003:01:00.0 Off | 0 |
| N/A 36C P0 77W / 300W | 455MiB / 16280MiB | 38% Default |
+-------------------------------+----------------------+----------------------+
| 2 Tesla P100-SXM2... On | 0000000A:01:00.0 Off | 0 |
| N/A 32C P0 71W / 300W | 455MiB / 16280MiB | 40% Default |
+-------------------------------+----------------------+----------------------+
| 3 Tesla P100-SXM2... On | 0000000B:01:00.0 Off | 0 |
| N/A 36C P0 64W / 300W | 455MiB / 16280MiB | 38% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 94004 C ...el-running(prot=False)-XGBoostModel-fit 445MiB |
| 1 94011 C ...el-running(prot=False)-XGBoostModel-fit 445MiB |
| 2 94044 C ...el-running(prot=False)-XGBoostModel-fit 445MiB |
| 3 94126 C ...el-running(prot=False)-XGBoostModel-fit 445MiB |
+-----------------------------------------------------------------------------+
과연 여기서 NVLink가 어느 정도의 효과를 발휘할까요 ? 그것을 확인하는 가장 쉽고 생생한 방법은 nvprof 명령을 이용하여 DriverlessAI process들이 GPU를 어떻게 사용하는지 profile을 떠보는 것입니다.
먼저, DAI의 홈 디렉토리에 있는 start-dai.sh를 다음과 같이 수정합니다. 원래의 line은 #으로 막아놓았고, 아래 붉은색의 명령어들이 새로 삽입된 nvprof 명령어입니다.
[root@p57a22 dai-1.3.1-linux-ppc64le]# cat start-dai.sh
#!/bin/bash
if [ "x${RUN_DAI_CREATE_PIDFILE}" == "x1" ]; then
# python -m h2oai &
/usr/local/cuda-9.2/bin/nvprof --log-file /tmp/nvprof1.%p.txt --export-profile /tmp/nvprof1.%p.nvvp --print-gpu-trace --profile-child-processes python -m h2oai &
echo $! > ${RUN_DAI_PIDFILE_DIR}/dai.pid
else
# exec python -m h2oai
exec /usr/local/cuda-9.2/bin/nvprof --log-file /tmp/nvprof1.%p.txt --export-profile /tmp/nvprof1.%p.nvvp --print-gpu-trace --profile-child-processes python -m h2oai
fi
위와 같이 해놓고 kill-dai.sh를 수행하여 기존 DAI를 stop시킨 뒤, run-dai.sh를 수행하여 DAI를 새로 구동한 뒤에 큼직한 dataset으로 training을 해봅니다. 이때, 다음과 같이 child process마다 txt와 nvvp로 텍스트와 바이너리 로그 파일이 생성되는 것을 보실 수 있습니다.
[root@p57a22 dai-1.3.1-linux-ppc64le]# ls -l /tmp/nvprof1*
...
-rw-r--r-- 1 root root 170096640 Oct 5 03:16 /tmp/nvprof1.83368.nvvp
-rw-r--r-- 1 root root 233180816 Oct 5 03:22 /tmp/nvprof1.83368.txt
-rw-r--r-- 1 root root 180073472 Oct 5 03:16 /tmp/nvprof1.83405.nvvp
-rw-r--r-- 1 root root 246428557 Oct 5 03:20 /tmp/nvprof1.83405.txt
...
이 중 하나를 CUDA에 딸려 있는 NVIDIA Visual Profiler (NVVP)로 분석해보면 다음과 같습니다.
"CUDA memcpy HtoD" (Host to Device, 즉 서버 CPU에서 GPU로의 memcpy도 9 GB/s에 가깝고 DtoD (GPU간의 memcpy)는 134 GB/s에 가깝게 사용되는 것을 보실 수 있습니다.
특히 8개의 GPU를 장착한 일반 x86 기반 GPU 서버들은 NVLink를 1개씩만 이용하여 연결되므로 GPU간의 통신은 이론상 50 GB/s, CPU와 GPU간의 통신은 이론상 32 GB/s가 최대인 것에 비해, IBM AC922은 3개의 NVLink를 aggregation시켜 CPU와 GPU이나 GPU끼리나 모두 150 GB/s로 연결된 것이 H2O DriverlessAI의 운용에 크게 유리하다는 것을 쉽게 보실 수 있습니다.
물론 nvidia-smi 에서도 모니터링하실 수 있습니다. GPU 1개당 1개의 process가 수행되는 것이 아니라, GPU 메모리가 허용하는 한 필요에 따라 GPU 1개당 여러 개의 process들이 수행되기도 합니다.
Fri Oct 5 03:36:45 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 396.26 Driver Version: 396.26 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla P100-SXM2... On | 00000002:01:00.0 Off | 0 |
| N/A 34C P0 64W / 300W | 455MiB / 16280MiB | 40% Default |
+-------------------------------+----------------------+----------------------+
| 1 Tesla P100-SXM2... On | 00000003:01:00.0 Off | 0 |
| N/A 36C P0 77W / 300W | 455MiB / 16280MiB | 38% Default |
+-------------------------------+----------------------+----------------------+
| 2 Tesla P100-SXM2... On | 0000000A:01:00.0 Off | 0 |
| N/A 32C P0 71W / 300W | 455MiB / 16280MiB | 40% Default |
+-------------------------------+----------------------+----------------------+
| 3 Tesla P100-SXM2... On | 0000000B:01:00.0 Off | 0 |
| N/A 36C P0 64W / 300W | 455MiB / 16280MiB | 38% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 94004 C ...el-running(prot=False)-XGBoostModel-fit 445MiB |
| 1 94011 C ...el-running(prot=False)-XGBoostModel-fit 445MiB |
| 2 94044 C ...el-running(prot=False)-XGBoostModel-fit 445MiB |
| 3 94126 C ...el-running(prot=False)-XGBoostModel-fit 445MiB |
+-----------------------------------------------------------------------------+
과연 여기서 NVLink가 어느 정도의 효과를 발휘할까요 ? 그것을 확인하는 가장 쉽고 생생한 방법은 nvprof 명령을 이용하여 DriverlessAI process들이 GPU를 어떻게 사용하는지 profile을 떠보는 것입니다.
먼저, DAI의 홈 디렉토리에 있는 start-dai.sh를 다음과 같이 수정합니다. 원래의 line은 #으로 막아놓았고, 아래 붉은색의 명령어들이 새로 삽입된 nvprof 명령어입니다.
[root@p57a22 dai-1.3.1-linux-ppc64le]# cat start-dai.sh
#!/bin/bash
if [ "x${RUN_DAI_CREATE_PIDFILE}" == "x1" ]; then
# python -m h2oai &
/usr/local/cuda-9.2/bin/nvprof --log-file /tmp/nvprof1.%p.txt --export-profile /tmp/nvprof1.%p.nvvp --print-gpu-trace --profile-child-processes python -m h2oai &
echo $! > ${RUN_DAI_PIDFILE_DIR}/dai.pid
else
# exec python -m h2oai
exec /usr/local/cuda-9.2/bin/nvprof --log-file /tmp/nvprof1.%p.txt --export-profile /tmp/nvprof1.%p.nvvp --print-gpu-trace --profile-child-processes python -m h2oai
fi
위와 같이 해놓고 kill-dai.sh를 수행하여 기존 DAI를 stop시킨 뒤, run-dai.sh를 수행하여 DAI를 새로 구동한 뒤에 큼직한 dataset으로 training을 해봅니다. 이때, 다음과 같이 child process마다 txt와 nvvp로 텍스트와 바이너리 로그 파일이 생성되는 것을 보실 수 있습니다.
[root@p57a22 dai-1.3.1-linux-ppc64le]# ls -l /tmp/nvprof1*
...
-rw-r--r-- 1 root root 170096640 Oct 5 03:16 /tmp/nvprof1.83368.nvvp
-rw-r--r-- 1 root root 233180816 Oct 5 03:22 /tmp/nvprof1.83368.txt
-rw-r--r-- 1 root root 180073472 Oct 5 03:16 /tmp/nvprof1.83405.nvvp
-rw-r--r-- 1 root root 246428557 Oct 5 03:20 /tmp/nvprof1.83405.txt
...
이 중 하나를 CUDA에 딸려 있는 NVIDIA Visual Profiler (NVVP)로 분석해보면 다음과 같습니다.
"CUDA memcpy HtoD" (Host to Device, 즉 서버 CPU에서 GPU로의 memcpy도 9 GB/s에 가깝고 DtoD (GPU간의 memcpy)는 134 GB/s에 가깝게 사용되는 것을 보실 수 있습니다.
특히 8개의 GPU를 장착한 일반 x86 기반 GPU 서버들은 NVLink를 1개씩만 이용하여 연결되므로 GPU간의 통신은 이론상 50 GB/s, CPU와 GPU간의 통신은 이론상 32 GB/s가 최대인 것에 비해, IBM AC922은 3개의 NVLink를 aggregation시켜 CPU와 GPU이나 GPU끼리나 모두 150 GB/s로 연결된 것이 H2O DriverlessAI의 운용에 크게 유리하다는 것을 쉽게 보실 수 있습니다.
2017년 10월 27일 금요일
caffe-ibm의 LMS 기능에 대한 설명
전에 올린 DDL 관련 포스팅(https://hwengineer.blogspot.kr/2017/10/caffe-ddl-alexnet-training.html)에서, LMS(large model support) 기능을 믿고 batch_size를 화끈하게 2048이나 4096으로 올리면 어떤가라는 질문이 있을 수 있습니다. 결론부터 말씀드리면 LMS를 쓴다고 해도 batch_size를 무한정 키울 수는 없습니다.
먼저 저 포스팅에 나와 있듯이, LMS 기능은 '기존 GPU memory 한계 때문에 돌릴 수 없었던 큰 모델도 돌릴 수 있게 해주는 기능'이지, 이 때문에 반드시 더 빠른 성능을 낼 수 있는 것은 아닙니다. 아무리 NVLink를 통해 가져온다고 해도, host server memory가 GPU memory보다는 느리니까요.
그와는 별도로, LMS도 무한정 host memory를 쓸 수는 없습니다. Lab에서 들은 이야기입니다만, LMS를 쓴다고 해도 아래 정보들은 반드시 GPU memory 상에 올라가야 한다고 합니다.
- input tensor
- output tensor
- weight
- gradient (training인 경우)
그리고 이 정보들이 차지하는 memory의 양은 batch_size가 늘어날 수록 함께 늘어나는데, 그로 인해 결국 한계가 있습니다. LMS의 핵심은, deep learning에서 layer별로 training을 할 때, 당장 처리하고 있는 layer는 GPU memory 위에 두더라도, 이미 처리했거나 나중에 처리할 layer들은 host memory에 저장할 수 있다는 것입니다. 따라서, LMS로 처리가능한 최대 neural network 크기는 그 neural network에서 가장 큰 layer의 크기에 달려 있다고 할 수 있습니다.
가령 전에 테스트했던, Alexnet의 deploy.prototxt 이용해서 'caffe time'을 수행할 때 보면 아래와 같이 data, conv1, relu1 등 총 24개의 layer가 만들어집니다.
$ grep "Creating Layer" caffe_time.log
…
I1025 16:37:01.848961 29514 net.cpp:90] Creating Layer data
I1025 16:37:01.867213 29514 net.cpp:90] Creating Layer conv1
…
I1025 16:37:03.477823 29514 net.cpp:90] Creating Layer fc8
I1025 16:37:03.481210 29514 net.cpp:90] Creating Layer prob
그리고 각 layer마다 다음과 같이 Top shape가 정해지면서 "Memory required for data"가 연산됩니다. 그리고 그 값은 처음 layer에서는 작아도 나중에는 매우 커지지요.
…
I1025 16:37:01.867137 29514 net.cpp:135] Top shape: 10 3 1600 1200 (57600000)
I1025 16:37:01.867183 29514 net.cpp:143] Memory required for data: 230400000
…
I1025 16:37:02.231456 29514 net.cpp:135] Top shape: 10 96 398 298 (113859840)
I1025 16:37:02.231468 29514 net.cpp:143] Memory required for data: 685839360
…
I1025 16:37:02.246103 29514 net.cpp:135] Top shape: 10 256 49 37 (4641280)
I1025 16:37:02.246112 29514 net.cpp:143] Memory required for data: 3315185920
…
이런 특성들로 인해, wide한 (layer별 메모리 필요량이 많은) neural network보다는 deep한 (layer 개수가 많은) neural network이 LMS의 잇점을 훨씬 더 잘 살릴 수 있습니다.
LMS의 진정한 장점을 정리하면 아래와 같습니다.
1) width로는 10-30배 정도 더 큰 모델 사용 가능
2) depth로는 무한대의 큰 모델을 사용 가능
특성상 layer들이 많은 RNN에서 LMS가 특히 유용하게 쓰일 수 있다고 합니다. 그리고 요즘 신경망 발전 방향이 wide해지는 방향이 아니라 점점 deep해지는 방향이라고 합니다. 가령 몇년 전에 나온 Alexnet 같은 경우 이론상 7개 layer라고 하는데, 그로부터 4년 뒤에 나온 ResNet 같은 경우 1000개 layer라고 하지요. LMS의 적용 범위는 점점 넓어지고 있다고 할 수 있습니다.
먼저 저 포스팅에 나와 있듯이, LMS 기능은 '기존 GPU memory 한계 때문에 돌릴 수 없었던 큰 모델도 돌릴 수 있게 해주는 기능'이지, 이 때문에 반드시 더 빠른 성능을 낼 수 있는 것은 아닙니다. 아무리 NVLink를 통해 가져온다고 해도, host server memory가 GPU memory보다는 느리니까요.
그와는 별도로, LMS도 무한정 host memory를 쓸 수는 없습니다. Lab에서 들은 이야기입니다만, LMS를 쓴다고 해도 아래 정보들은 반드시 GPU memory 상에 올라가야 한다고 합니다.
- input tensor
- output tensor
- weight
- gradient (training인 경우)
그리고 이 정보들이 차지하는 memory의 양은 batch_size가 늘어날 수록 함께 늘어나는데, 그로 인해 결국 한계가 있습니다. LMS의 핵심은, deep learning에서 layer별로 training을 할 때, 당장 처리하고 있는 layer는 GPU memory 위에 두더라도, 이미 처리했거나 나중에 처리할 layer들은 host memory에 저장할 수 있다는 것입니다. 따라서, LMS로 처리가능한 최대 neural network 크기는 그 neural network에서 가장 큰 layer의 크기에 달려 있다고 할 수 있습니다.
가령 전에 테스트했던, Alexnet의 deploy.prototxt 이용해서 'caffe time'을 수행할 때 보면 아래와 같이 data, conv1, relu1 등 총 24개의 layer가 만들어집니다.
$ grep "Creating Layer" caffe_time.log
…
I1025 16:37:01.848961 29514 net.cpp:90] Creating Layer data
I1025 16:37:01.867213 29514 net.cpp:90] Creating Layer conv1
…
I1025 16:37:03.477823 29514 net.cpp:90] Creating Layer fc8
I1025 16:37:03.481210 29514 net.cpp:90] Creating Layer prob
그리고 각 layer마다 다음과 같이 Top shape가 정해지면서 "Memory required for data"가 연산됩니다. 그리고 그 값은 처음 layer에서는 작아도 나중에는 매우 커지지요.
…
I1025 16:37:01.867137 29514 net.cpp:135] Top shape: 10 3 1600 1200 (57600000)
I1025 16:37:01.867183 29514 net.cpp:143] Memory required for data: 230400000
…
I1025 16:37:02.231456 29514 net.cpp:135] Top shape: 10 96 398 298 (113859840)
I1025 16:37:02.231468 29514 net.cpp:143] Memory required for data: 685839360
…
I1025 16:37:02.246103 29514 net.cpp:135] Top shape: 10 256 49 37 (4641280)
I1025 16:37:02.246112 29514 net.cpp:143] Memory required for data: 3315185920
…
이런 특성들로 인해, wide한 (layer별 메모리 필요량이 많은) neural network보다는 deep한 (layer 개수가 많은) neural network이 LMS의 잇점을 훨씬 더 잘 살릴 수 있습니다.
LMS의 진정한 장점을 정리하면 아래와 같습니다.
1) width로는 10-30배 정도 더 큰 모델 사용 가능
2) depth로는 무한대의 큰 모델을 사용 가능
특성상 layer들이 많은 RNN에서 LMS가 특히 유용하게 쓰일 수 있다고 합니다. 그리고 요즘 신경망 발전 방향이 wide해지는 방향이 아니라 점점 deep해지는 방향이라고 합니다. 가령 몇년 전에 나온 Alexnet 같은 경우 이론상 7개 layer라고 하는데, 그로부터 4년 뒤에 나온 ResNet 같은 경우 1000개 layer라고 하지요. LMS의 적용 범위는 점점 넓어지고 있다고 할 수 있습니다.
2017년 8월 7일 월요일
POWER9 + Volta의 Cache Coherence : preview
아래 URL은 주로 엔터프라이즈 컴퓨팅 및 수퍼컴 이슈를 다루는 Nextplatform이라는 매체에서 IBM의 Vice President이자 수퍼컴 전문가인 David Turek과 인터뷰한 기사입니다. David Turek은 저도 실무 차원에서 두어번 teleconference를 한 적이 있는 분인데, 높은 곳에서 호령만 하는 임원이 아니라 진짜 실무 engineer입니다. 이 분은 현재 세계에서 가장 뛰어난 수퍼컴이 될 Sierra와 Summit을 구축하는 CORAL (Collaboration of Oak Ridge, Argonne, and Livermore) 프로젝트를 수행하고 있습니다.
https://www.nextplatform.com/2017/06/21/thinking-cognitive-hpc-nexus-big-blue/
여기서 눈에 띄는 부분은 아래 내용입니다.
TPM: No one else is going to have this coherence between the CPU and the GPU, although AMD might be able to do it now that it is delivering both Epyc processors and Radeon Instinct GPU accelerators. It certain has done some work on coherency in the past with its APUs and that technology could be applied to CPUs and discrete GPUs not on a single die or in a single package. But for now, only Power9 has NVLink and Intel is not offering something that looks like NVLink between its Xeons or Xeon Phis and other types of accelerators. The point is, no one has this yet except IBM and Nvidia.
Dave Turek: Correct. I was down in an exascale conference a couple of weeks ago in Princeton, and Jack Wells, one of the people at Oak Ridge National Laboratories, got up and was talking about progress on the CORAL systems and said that one of the biggest things is going to be this coherency. Forget flops and all of that, the big deal is the coherency. This is a bit under the radar because people are only talking about the technical features of Summit and Sierra machines and they have not realized the impact of this coherence.
이 대화 부분을 요약하면 이렇습니다.
"CORAL 수퍼컴에서는 세계 수퍼컴 최초로 CPU와 GPU간에 coherence가 구현되는데, 진짜 주목할 부분은 (흔히 수퍼컴 성능을 이야기할 때 사용되는) 테라플롭스(TFLOPS) 따위가 아니라 바로 coherence다. 업계 사람들조차도 아직 이 기술의 중요성에 대해 잘 모른다."
이렇게 중요한 기술이라는 coherence라는 것이 대체 무엇일까요 ? 일반적인 cache coherence라는 것은 여러 곳의 메모리/캐쉬에 저장된 data를 일관성있게 유지하는 것을 말합니다. 이는 여러개의 processor를 이용하는 경우 데이터 정합성을 위해 반드시 필요한 기능이며, 대형 SMP 서버의 성능은 CPU와 메모리 등의 성능 외에도, 이 cache coherence를 어떻게 유지하느냐에 달려 있습니다. 아래 그림을 보시면 아마 cache coherence의 개념을 쉽게 이해하실 수 있을 겁니다. (그림 소스 : https://en.wikipedia.org/wiki/Cache_coherence )
여기서 Turek이 이야기하는 coherence라는 것은 CPU와 GPU 간의 coherence를 이야기하는 것입니다. 즉, 원래 CPU는 서버 메모리를, GPU는 GPU 메모리를 각각 따로 가지고 있지만, POWER9과 Volta GPU에서는 CPU와 GPU가 그 각각의 메모리를 마치 한덩어리인 것처럼 사용할 수 있게 된다는 것입니다.
기존 GPU 컴퓨팅에서 매우 골치 아팠던 부분은 크게 2가지였습니다.
1) GPU 메모리 크기의 한계
2) GPU가 연결된 시스템 버스 (PCIe Gen3) 속도의 한계
모든 GPU 컴퓨팅에서, GPU가 뭔가 연산을 하려면 (그것이 전통적 HPC이건 Deep Learning이건) 해당 logic과 data를 CPU 메모리로부터 copy하여 GPU 메모리에 저장부터 해야 했습니다. 그런데 위의 2가지 문제가 항상 그 작업을 어렵게 했습니다. 즉, 보통 12GB ~ 24GB 정도인 GPU 메모리 크기 때문에 원하는 data를 다 집어 넣을 수도 없고, 또 PCIe를 통한 data copy 속도가 충분히 빠르지 않아서 문제였던 것입니다. Deep learning에 있어서도 이 문제는 마찬가지였습니다. 가령 이미지 데이터를 이용해 신경망을 training시킬 때, 한꺼번에 1024장의 이미지를 처리하면 (batch_size=1024) 좋을텐데 그럴 경우 GPU 메모리가 넘치므로 에러가 났습니다. 또 자율주행이나 자연어 처리 (NLP) 처럼 큰 모델을 사용해야 하는 경우엔 아예 GPU 메모리 상에 모델 자체가 들어가질 않아서 돌릴 수가 없었지요. 그런 경우를 해결하기 위해서 여러장의 GPU에 모델을 쪼개 넣는 model-parallelism을 구현하기도 합니다만, 그런 model-parallelism은 구현하기 쉽지 않은 것이 사실입니다.
이런 상황에서 NVIDIA와 IBM이 내놓은 하드웨어 기술 하나가 많은 것을 바꿔놓습니다. 바로 NVLink입니다. NVLink는 GPU 연결에 PCIe 대신 사용하는 시스템 버스 기술로서, 특히 IBM은 POWER8 프로세서에 NVLink port를 박아넣음으로써 CPU와 GPU가 40GB/sec X 2 = 80GB/sec로 통신하여 기존 PCIe 대비 2.5배의 대역폭을 낼 수 있도록 만들었습니다. 이는 NVLink가 달린 P100 GPU를 사용하더라도 Intel Xeon 프로세서와 GPU 간은 여전히 PCIe를 써야 하는 x86 서버에서는 불가능한 기술로서, 현재는 IBM Minsky 서버 (S822LC for HPC)에만 구현되어 있습니다.
Minsky 서버의 NVLink 기술은 비단 GPU-GPU, 그리고 CPU-GPU 간의 대역폭을 높였다는 것 외에도 CUDA 8과 Pascal 아키텍처와 함께 근본적인 변화를 가져왔습니다. 바로 Unified Memory입니다.
Unified Memory(UM 혹은 UVM)는 GPU가 서버 RAM을 마치 GPU 메모리인 것처럼 사용할 수 있도록 해주는 기술입니다. 이를 이용하면 GPU 메모리 크기로 인해서 오는 많은 불편함을 해결할 수 있습니다. 그러나 이 UM 기술이 CUDA 6.5부터 지원되었음에도 여태까지 그 활용도는 낮았습니다. 이유는 성능 저하였습니다. 아무래도 DDR3로 되어 있는 서버 메모리가 GDDR5인 GPU 메모리보다는 많이 느렸거든요. 그건 서버 메모리가 DDR4로 바뀌고 GPU 메모리가 HBM2로 바뀐 다음에도 마찬가지입니다. 메모리들이 빨리질 수록 그 연결 기술인 PCIe의 한계가 더 뚜렷이 드러날 뿐이었지요. 그런 상황에서 PCIe를 대체하는 NVLink 기술의 도입은 그 성능 저하 문제를 크게 해결해줄 수 있게 된 것입니다.
여전히 UM 사용은 일반화되어 있지 않습니다. 알고보면 일반 NVLink 1개 link의 대역폭은 40GB/sec로서, PCIe gen3의 32GB/sec보다 엄청나게 빠르다고 할 수도 없습니다. 게다가 대부분의 GPU 서버들이 x86 프로세서를 장착하고 있는데, NVLink P100 GPU를 탑재한 서버라고 해도 x86 프로세서와는 PCIe로 통신해야 합니다. 즉, UM 자체에는 여전히 PCIe를 써야 했습니다. 이에 비해, IBM POWER8 프로세서를 탑재한 Minsky 서버는 POWER8 프로세서와 P100 GPU 간을 NVLink 2개를 aggregation시켜 40+40=80GB/sec로 구현했습니다. 다른 NVLink P100 GPU 서버에 비해 2.5배의 대역폭인 셈이지요.
그렇다면 Minsky에서는 UM을 적극적으로 활용하고 있느냐 ? 예, 실은 이제 막 시작되었습니다. 바로 PowerAI의 Large Model Support (LMS)를 통해서입니다. 이는 바로 최근인 8월 5일 (문서에는 7월 25일이라고 되어 있지만 실제로는 더 늦었습니다) 발표된 새로운 기능으로서, UM 기능을 enable한 IBM 버전의 caffe (caffe-ibm)의 옵션 형태로 구현되었습니다. 이에 대해서는 아래 URL에 자세히 나와 있습니다.
https://developer.ibm.com/linuxonpower/deep-learning-powerai/releases/
그나마 클릭하셔서 자세히 보시기 귀찮으신 분들을 위해 핵심부분만 따오면 아래와 같습니다.
Large Model Support (LMS)
IBM caffe를 사용하실 때, -lms <size in KB> 라는 옵션이 추가되었습니다. 가령 -lms 409600 이라고 해놓으시면 400MB 이상의 메모리 chunk는 CPU에 유지하고, 필요할 때만 GPU 메모리로 가져옵니다. 만약 LMS를 disable하고 싶으시면 -lms 10000000000 처럼 엄청나게 큰 메모리 값을 주시면 됩니다. 또 -lms_frac <0에서 1.0 사이의 값>이라는 옵션을 주셔도 되는데, 가령 -lms_frac 0.4로 준면, 최소 40% 이상의 GPU 메모리를 사용할 때만 LMS 기능이 활성화됩니다. 작은 신경망을 training하실 때는 굳이 LMS를 쓰실 필요가 없으니 이 옵션을 쓰시는 것이 좋습니다.
이 LMS 기능은 이번에는 IBM caffe에만 적용되었습니다만, 점차 더 확대하여 tensorflow에도 적용할 예정입니다.
그런데 이 글 초반에 언급했던 David Turek의 인터뷰 내용을 보면 Cache Coherence라는 것은 POWER8 + Pascal GPU가 아닌, POWER9 + Volta GPU에서 처음으로 도입되는 것처럼 씌여 있습니다. 이건 왜 그럴까요 ? 분명히 Cache Coherence는 Unified Memory보다 더 진전된 기능 같은데, 구체적으로 어떤 점이 더 나아지는 것일까요 ?
이에 대해서는 다음 URL에 꽤 자세히 나와 있습니다.
http://on-demand.gputechconf.com/gtc/2017/presentation/s7285-nikolay-sakharnykh-unified-memory-on-pascal-and-volta.pdf
여기서는 간략하게 표로 정리해보았습니다.
Cache coherence에서 UM으로부터 더 향상된 점을 좀더 쉽게 표현하면 이렇습니다. Access counter 기능을 이용하여 이젠 access가 잦은 'hot page'들만 GPU로 migration하는 것이 가능해졌고, 또 GPU가 서버 메모리를 access하는 것 뿐만 아니라 CPU도 GPU 메모리를 CPU cache 레벨까지 써서 자유롭게 access하는 것이 가능해진 것입니다. 그 의미는 간단합니다. GPU 메모리 크기로 인해 제약받았던 기존 GPU 프로그래밍이 상식적인 수준의 성능 저하만 감내한다면 훨씬 더 간편해진다는 것입니다.
적정 수준의 성능 저하만 감내하면 편해진다는데 그 적정 수준이라는 것이 어느 정도이고 또 얼마나 편해지는 것일까요 ? 아직 POWER9 + Volta에 대해서는 자료가 나오지 않았으므로 지금은 POWER8 + Pascal의 UM의 경우를 통해서 짐작해보시지요.
전통적 HPC coding에서도 그렇겠습니다만, deep learning 관점에서도 UM 또는 cache coherence가 주는 혜택은 명백합니다. 한마디로, 과거에는 아예 training을 돌릴 수 없었던 큰 model도 training이 가능해집니다. 기존에는 여러장의 GPU에 걸쳐 복잡한 model-parallelism을 구현해야만 가능했던 training이 훨씬 쉽게 1장의 GPU에서도 가능해지는 것입니다. 또한 과거에는 한번에 (가령) 16장의 이미지만 training 시킬 수 있었다면, 이젠 그 24배인 384장을 한꺼번에 training 시킬 수 있게 됩니다.
다만 이런 편리함은 필연적으로 성능 저하를 불러오는 것이 사실입니다. 아무래도 서버의 DDR4 메모리가 GPU의 HBM2 메모리보다는 훨씬 느린데다, 그걸 PCIe(32GB/sec)가 아닌 NVLink * 2개(80GB/sec)로 연결한다고 해도 메모리 access 속도(115GB/sec)보다는 느리니까요.
아래는 x86 서버에서 NVIDIA Quadro GP100 (Pascal) GPU를 이용해서 Unified Memory로 oversubscription을 한 경우의 deep learning 속도입니다. 그냥 GPU 메모리만 사용할 때에 비해, 속도가 5~9배 느려진 것을 보실 수 있습니다. 이는 x86과 Quadro GP100 사이가 PCIe(32GB/sec)로 연결되었기 때문입니다.
그러나 NVLink *2개(80GB/sec)로 연결된 경우는 어떨까요 ? NVLink *2개는 PCIe보다 2.5배 더 대역폭이 크기 때문에, 산술적으로는 대략 2~2.5배 정도만 느려질 것으로 예상됩니다. 아직 PowerAI의 LMS를 이용한 deep learning training 성능 테스트 결과가 공식적으로 발표된 것은 없습니다. 그러나 아래 HPC의 일종인 AMR (adaptive mesh refinement technique)에 대해 NVIDIA가 POWER8 + Pascal의 oversubscription 기능을 이용해 테스트한 바를 보면 정말 2배 정도만 느려지는 것을 보실 수 있습니다. 과거에는 아예 돌릴 수 없었던 큰 working set을 POWER8 + Pascal의 oversubscription 기능을 이용하면 1장의 GPU로도 훌륭히 수행할 수 있는 것입니다.
2018년에 CORAL 프로젝트의 두 수퍼컴 클러스터인 Summit과 Sierra가 구축되고나면 cache coherence에 대한 좀더 많은 성능 결과치가 나올 것으로 기대합니다.
Source :
https://devblogs.nvidia.com/parallelforall/beyond-gpu-memory-limits-unified-memory-pascal/
http://on-demand.gputechconf.com/gtc/2016/presentation/s6224-mark-harris.pdf
http://cudacoe.m.gsic.titech.ac.jp/lecture/lecture-wiki/index.php?plugin=attach&refer=hpc2016&openfile=hpc2016_ito.pdf
http://on-demand.gputechconf.com/gtc/2017/presentation/s7285-nikolay-sakharnykh-unified-memory-on-pascal-and-volta.pdf
https://www.nextplatform.com/2017/06/21/thinking-cognitive-hpc-nexus-big-blue/
여기서 눈에 띄는 부분은 아래 내용입니다.
TPM: No one else is going to have this coherence between the CPU and the GPU, although AMD might be able to do it now that it is delivering both Epyc processors and Radeon Instinct GPU accelerators. It certain has done some work on coherency in the past with its APUs and that technology could be applied to CPUs and discrete GPUs not on a single die or in a single package. But for now, only Power9 has NVLink and Intel is not offering something that looks like NVLink between its Xeons or Xeon Phis and other types of accelerators. The point is, no one has this yet except IBM and Nvidia.
Dave Turek: Correct. I was down in an exascale conference a couple of weeks ago in Princeton, and Jack Wells, one of the people at Oak Ridge National Laboratories, got up and was talking about progress on the CORAL systems and said that one of the biggest things is going to be this coherency. Forget flops and all of that, the big deal is the coherency. This is a bit under the radar because people are only talking about the technical features of Summit and Sierra machines and they have not realized the impact of this coherence.
이 대화 부분을 요약하면 이렇습니다.
"CORAL 수퍼컴에서는 세계 수퍼컴 최초로 CPU와 GPU간에 coherence가 구현되는데, 진짜 주목할 부분은 (흔히 수퍼컴 성능을 이야기할 때 사용되는) 테라플롭스(TFLOPS) 따위가 아니라 바로 coherence다. 업계 사람들조차도 아직 이 기술의 중요성에 대해 잘 모른다."
이렇게 중요한 기술이라는 coherence라는 것이 대체 무엇일까요 ? 일반적인 cache coherence라는 것은 여러 곳의 메모리/캐쉬에 저장된 data를 일관성있게 유지하는 것을 말합니다. 이는 여러개의 processor를 이용하는 경우 데이터 정합성을 위해 반드시 필요한 기능이며, 대형 SMP 서버의 성능은 CPU와 메모리 등의 성능 외에도, 이 cache coherence를 어떻게 유지하느냐에 달려 있습니다. 아래 그림을 보시면 아마 cache coherence의 개념을 쉽게 이해하실 수 있을 겁니다. (그림 소스 : https://en.wikipedia.org/wiki/Cache_coherence )
(Cache coherence가 되는 경우)
(Cache coherence가 안 되는 경우)
여기서 Turek이 이야기하는 coherence라는 것은 CPU와 GPU 간의 coherence를 이야기하는 것입니다. 즉, 원래 CPU는 서버 메모리를, GPU는 GPU 메모리를 각각 따로 가지고 있지만, POWER9과 Volta GPU에서는 CPU와 GPU가 그 각각의 메모리를 마치 한덩어리인 것처럼 사용할 수 있게 된다는 것입니다.
기존 GPU 컴퓨팅에서 매우 골치 아팠던 부분은 크게 2가지였습니다.
1) GPU 메모리 크기의 한계
2) GPU가 연결된 시스템 버스 (PCIe Gen3) 속도의 한계
모든 GPU 컴퓨팅에서, GPU가 뭔가 연산을 하려면 (그것이 전통적 HPC이건 Deep Learning이건) 해당 logic과 data를 CPU 메모리로부터 copy하여 GPU 메모리에 저장부터 해야 했습니다. 그런데 위의 2가지 문제가 항상 그 작업을 어렵게 했습니다. 즉, 보통 12GB ~ 24GB 정도인 GPU 메모리 크기 때문에 원하는 data를 다 집어 넣을 수도 없고, 또 PCIe를 통한 data copy 속도가 충분히 빠르지 않아서 문제였던 것입니다. Deep learning에 있어서도 이 문제는 마찬가지였습니다. 가령 이미지 데이터를 이용해 신경망을 training시킬 때, 한꺼번에 1024장의 이미지를 처리하면 (batch_size=1024) 좋을텐데 그럴 경우 GPU 메모리가 넘치므로 에러가 났습니다. 또 자율주행이나 자연어 처리 (NLP) 처럼 큰 모델을 사용해야 하는 경우엔 아예 GPU 메모리 상에 모델 자체가 들어가질 않아서 돌릴 수가 없었지요. 그런 경우를 해결하기 위해서 여러장의 GPU에 모델을 쪼개 넣는 model-parallelism을 구현하기도 합니다만, 그런 model-parallelism은 구현하기 쉽지 않은 것이 사실입니다.
이런 상황에서 NVIDIA와 IBM이 내놓은 하드웨어 기술 하나가 많은 것을 바꿔놓습니다. 바로 NVLink입니다. NVLink는 GPU 연결에 PCIe 대신 사용하는 시스템 버스 기술로서, 특히 IBM은 POWER8 프로세서에 NVLink port를 박아넣음으로써 CPU와 GPU가 40GB/sec X 2 = 80GB/sec로 통신하여 기존 PCIe 대비 2.5배의 대역폭을 낼 수 있도록 만들었습니다. 이는 NVLink가 달린 P100 GPU를 사용하더라도 Intel Xeon 프로세서와 GPU 간은 여전히 PCIe를 써야 하는 x86 서버에서는 불가능한 기술로서, 현재는 IBM Minsky 서버 (S822LC for HPC)에만 구현되어 있습니다.
Minsky 서버의 NVLink 기술은 비단 GPU-GPU, 그리고 CPU-GPU 간의 대역폭을 높였다는 것 외에도 CUDA 8과 Pascal 아키텍처와 함께 근본적인 변화를 가져왔습니다. 바로 Unified Memory입니다.
Unified Memory(UM 혹은 UVM)는 GPU가 서버 RAM을 마치 GPU 메모리인 것처럼 사용할 수 있도록 해주는 기술입니다. 이를 이용하면 GPU 메모리 크기로 인해서 오는 많은 불편함을 해결할 수 있습니다. 그러나 이 UM 기술이 CUDA 6.5부터 지원되었음에도 여태까지 그 활용도는 낮았습니다. 이유는 성능 저하였습니다. 아무래도 DDR3로 되어 있는 서버 메모리가 GDDR5인 GPU 메모리보다는 많이 느렸거든요. 그건 서버 메모리가 DDR4로 바뀌고 GPU 메모리가 HBM2로 바뀐 다음에도 마찬가지입니다. 메모리들이 빨리질 수록 그 연결 기술인 PCIe의 한계가 더 뚜렷이 드러날 뿐이었지요. 그런 상황에서 PCIe를 대체하는 NVLink 기술의 도입은 그 성능 저하 문제를 크게 해결해줄 수 있게 된 것입니다.
여전히 UM 사용은 일반화되어 있지 않습니다. 알고보면 일반 NVLink 1개 link의 대역폭은 40GB/sec로서, PCIe gen3의 32GB/sec보다 엄청나게 빠르다고 할 수도 없습니다. 게다가 대부분의 GPU 서버들이 x86 프로세서를 장착하고 있는데, NVLink P100 GPU를 탑재한 서버라고 해도 x86 프로세서와는 PCIe로 통신해야 합니다. 즉, UM 자체에는 여전히 PCIe를 써야 했습니다. 이에 비해, IBM POWER8 프로세서를 탑재한 Minsky 서버는 POWER8 프로세서와 P100 GPU 간을 NVLink 2개를 aggregation시켜 40+40=80GB/sec로 구현했습니다. 다른 NVLink P100 GPU 서버에 비해 2.5배의 대역폭인 셈이지요.
그렇다면 Minsky에서는 UM을 적극적으로 활용하고 있느냐 ? 예, 실은 이제 막 시작되었습니다. 바로 PowerAI의 Large Model Support (LMS)를 통해서입니다. 이는 바로 최근인 8월 5일 (문서에는 7월 25일이라고 되어 있지만 실제로는 더 늦었습니다) 발표된 새로운 기능으로서, UM 기능을 enable한 IBM 버전의 caffe (caffe-ibm)의 옵션 형태로 구현되었습니다. 이에 대해서는 아래 URL에 자세히 나와 있습니다.
https://developer.ibm.com/linuxonpower/deep-learning-powerai/releases/
그나마 클릭하셔서 자세히 보시기 귀찮으신 분들을 위해 핵심부분만 따오면 아래와 같습니다.
Large Model Support (LMS)
IBM caffe를 사용하실 때, -lms <size in KB> 라는 옵션이 추가되었습니다. 가령 -lms 409600 이라고 해놓으시면 400MB 이상의 메모리 chunk는 CPU에 유지하고, 필요할 때만 GPU 메모리로 가져옵니다. 만약 LMS를 disable하고 싶으시면 -lms 10000000000 처럼 엄청나게 큰 메모리 값을 주시면 됩니다. 또 -lms_frac <0에서 1.0 사이의 값>이라는 옵션을 주셔도 되는데, 가령 -lms_frac 0.4로 준면, 최소 40% 이상의 GPU 메모리를 사용할 때만 LMS 기능이 활성화됩니다. 작은 신경망을 training하실 때는 굳이 LMS를 쓰실 필요가 없으니 이 옵션을 쓰시는 것이 좋습니다.
이 LMS 기능은 이번에는 IBM caffe에만 적용되었습니다만, 점차 더 확대하여 tensorflow에도 적용할 예정입니다.
그런데 이 글 초반에 언급했던 David Turek의 인터뷰 내용을 보면 Cache Coherence라는 것은 POWER8 + Pascal GPU가 아닌, POWER9 + Volta GPU에서 처음으로 도입되는 것처럼 씌여 있습니다. 이건 왜 그럴까요 ? 분명히 Cache Coherence는 Unified Memory보다 더 진전된 기능 같은데, 구체적으로 어떤 점이 더 나아지는 것일까요 ?
이에 대해서는 다음 URL에 꽤 자세히 나와 있습니다.
http://on-demand.gputechconf.com/gtc/2017/presentation/s7285-nikolay-sakharnykh-unified-memory-on-pascal-and-volta.pdf
여기서는 간략하게 표로 정리해보았습니다.
Cache coherence에서 UM으로부터 더 향상된 점을 좀더 쉽게 표현하면 이렇습니다. Access counter 기능을 이용하여 이젠 access가 잦은 'hot page'들만 GPU로 migration하는 것이 가능해졌고, 또 GPU가 서버 메모리를 access하는 것 뿐만 아니라 CPU도 GPU 메모리를 CPU cache 레벨까지 써서 자유롭게 access하는 것이 가능해진 것입니다. 그 의미는 간단합니다. GPU 메모리 크기로 인해 제약받았던 기존 GPU 프로그래밍이 상식적인 수준의 성능 저하만 감내한다면 훨씬 더 간편해진다는 것입니다.
적정 수준의 성능 저하만 감내하면 편해진다는데 그 적정 수준이라는 것이 어느 정도이고 또 얼마나 편해지는 것일까요 ? 아직 POWER9 + Volta에 대해서는 자료가 나오지 않았으므로 지금은 POWER8 + Pascal의 UM의 경우를 통해서 짐작해보시지요.
전통적 HPC coding에서도 그렇겠습니다만, deep learning 관점에서도 UM 또는 cache coherence가 주는 혜택은 명백합니다. 한마디로, 과거에는 아예 training을 돌릴 수 없었던 큰 model도 training이 가능해집니다. 기존에는 여러장의 GPU에 걸쳐 복잡한 model-parallelism을 구현해야만 가능했던 training이 훨씬 쉽게 1장의 GPU에서도 가능해지는 것입니다. 또한 과거에는 한번에 (가령) 16장의 이미지만 training 시킬 수 있었다면, 이젠 그 24배인 384장을 한꺼번에 training 시킬 수 있게 됩니다.
다만 이런 편리함은 필연적으로 성능 저하를 불러오는 것이 사실입니다. 아무래도 서버의 DDR4 메모리가 GPU의 HBM2 메모리보다는 훨씬 느린데다, 그걸 PCIe(32GB/sec)가 아닌 NVLink * 2개(80GB/sec)로 연결한다고 해도 메모리 access 속도(115GB/sec)보다는 느리니까요.
(x86 서버에서는 저 붉은색의 PCIe가 병목이 될 수 밖에 없습니다)
아래는 x86 서버에서 NVIDIA Quadro GP100 (Pascal) GPU를 이용해서 Unified Memory로 oversubscription을 한 경우의 deep learning 속도입니다. 그냥 GPU 메모리만 사용할 때에 비해, 속도가 5~9배 느려진 것을 보실 수 있습니다. 이는 x86과 Quadro GP100 사이가 PCIe(32GB/sec)로 연결되었기 때문입니다.
그러나 NVLink *2개(80GB/sec)로 연결된 경우는 어떨까요 ? NVLink *2개는 PCIe보다 2.5배 더 대역폭이 크기 때문에, 산술적으로는 대략 2~2.5배 정도만 느려질 것으로 예상됩니다. 아직 PowerAI의 LMS를 이용한 deep learning training 성능 테스트 결과가 공식적으로 발표된 것은 없습니다. 그러나 아래 HPC의 일종인 AMR (adaptive mesh refinement technique)에 대해 NVIDIA가 POWER8 + Pascal의 oversubscription 기능을 이용해 테스트한 바를 보면 정말 2배 정도만 느려지는 것을 보실 수 있습니다. 과거에는 아예 돌릴 수 없었던 큰 working set을 POWER8 + Pascal의 oversubscription 기능을 이용하면 1장의 GPU로도 훌륭히 수행할 수 있는 것입니다.
2018년에 CORAL 프로젝트의 두 수퍼컴 클러스터인 Summit과 Sierra가 구축되고나면 cache coherence에 대한 좀더 많은 성능 결과치가 나올 것으로 기대합니다.
Source :
https://devblogs.nvidia.com/parallelforall/beyond-gpu-memory-limits-unified-memory-pascal/
http://on-demand.gputechconf.com/gtc/2016/presentation/s6224-mark-harris.pdf
http://cudacoe.m.gsic.titech.ac.jp/lecture/lecture-wiki/index.php?plugin=attach&refer=hpc2016&openfile=hpc2016_ito.pdf
http://on-demand.gputechconf.com/gtc/2017/presentation/s7285-nikolay-sakharnykh-unified-memory-on-pascal-and-volta.pdf
피드 구독하기:
글 (Atom)

















