nVidia GPU 아키텍처 변천사 (Ampere)
지난 글에서 살펴본 Turing에 이어 Ampere 아키텍처에 대해 살펴봅니다. 이전 글들과 마찬가지로 각 GPU 아키텍처마다 발표된 모든 기능들을 다루기 보다는 성능에 제일 큰 영향을 끼치는 Streaming Multiprocessor (SM) 구조 위주로 아키텍처 변화를 살펴보려 합니다.
이전 글 : nVidia GPU 아키텍처 변천사 (Turing)
Pascal 아키텍처 이후 High Performance Computing (HPC)용 아키텍처는 Volta, 3D 그래픽용 아키텍처는 Turing으로 줄기가 갈라졌지만 Ampere에서 다시 아키텍처의 이름이 하나로 합쳐졌습니다. 다만 동일한 아키텍처로 HPC와 3D 그래픽용 시장을 모두 대응하는 것은 아니고 Pascal 때와 마찬가지로 Ampere라는 하나의 이름 아래 HPC용과 3D 그래픽용으로 용도를 달리한 두 종류의 SM이 발표됐습니다. 가장 큰 GPU칩을 기준으로 HPC용으로 A100, 3D 그래픽용으로는 GA102 GPU가 발표되었는데 A100 GPU는 nVidia의 AI 가속용 서버인 DGX A100 제품군에 탑재되고 GA102 GPU는 GeForce RTX 30 시리즈 그래픽 카드에 사용됩니다.
GA100에 기반한 A100 GPU
먼저 HPC용의 GA100 GPU의 SM 구조를 살펴보겠습니다. A100 GPU white paper의 내용을 위주로 설명하려 하는데 헷갈리지 않도록 먼저 GA100과 A100을 구분할 필요가 있습니다. GA100은 nVidia가 문서상으로 정의한 가장 큰 GPU 아키텍처이고 A100은 GA100을 바탕으로 nVidia가 실제 칩으로 만들어낸 가장 큰 GPU인데, GA100에는 128개의 SM을 포함하는 구조를 정의했지만 실리콘 면적의 한계 때문인지 A100은 108개의 SM 만을 탑재하고 있습니다. 그럼에도 불구하고 A100의 칩면적은 826mm2로 Volta 아키텍처의 GV100 GPU의 815mm2 보다 살짝 커졌습니다. 2017년 GV100 발표 당시에 nVidia의 젠슨황 CEO가 당시 기술로 생산할 수 있는 가장 큰 칩이라고 자랑스러워하던 기억이 있는데, A100 GPU도 비슷한 크기입니다. GV100은 TSMC 12nm FinFET 공정을 사용했지만 A100은 7nm FinFET으로 미세화된 공정을 사용했기 때문에 GV100에서 211억개이던 트랜지스터 수는 A100에서 542억개로 2.5배 가량 늘어났습니다.
Ampere GA100 SM (Streaming Multiprocessor)
Ampere GA100 SM의 전체적인 구조는 Volta SM과 비교하여 크게 변하지는 않았습니다. 하나의 SM이 4개의 서브코어로 나뉘어진 구조가 그대로 유지됐으며 서브 코어마다 각각 16개씩의 INT32, FP32 코어와 8개씩의 FP64코어를 탑재한 점과 LD/ST 유닛의 개수도 동일합니다. 달라진 부분은 서브코어마다 2개씩 탑재되던 Tensor 코어가 1개로 줄었다는 점인데 이는 Volta의 1세대 Tensor 코어에 비해 Ampere의 3세대 Tensor 코어의 성능이 크게 늘었기 때문입니다. Tensor 코어의 성능향상에 맞추어 SM내의 L1 cache의 크기도 128KB에 192KB로 1.5배 늘어났습니다.
GA100의 3세대 Tensor 코어는 GV100의 1세대 Tensor 코어에 비해 FP16 precision 행렬 두개를 곱한 결과를 FP32 precision 행렬에 누적하는 계산을 기준으로 성능이 4배가 좋아졌습니다. 1세대 Tensor 코어는 1싸이클에 4×4 행렬 두개를 곱해서 누적할 수 있는데 반해, 3세대 Tensor 코어는 1싸이클에 8×4 행렬과 4×8 행렬을 곱해서 누적할 수 있게 되었습니다. 4×4 행렬 두개에 대한 계산을 환산하면 4x4x4=64 FP16 FMA(Fused Multply-Add) 연산이 되고 8×4 행렬과 4×8 행렬에 대한 계산을 환산하면 8x4x8=256 FP16 FMA연산이 되므로 3세대 Tensor 코어는 1세대 Tensor 코어대비 4배의 계산성능을 가지게 됩니다. SM 단위로 봤을 때 Volta에서 8개가 탑재되던 Tensor 코어가 Ampere에서 4개로 줄었기 때문에 FP16 행렬 곱셈 성능은 2배가 늘었다고 볼 수 있습니다.
Ampere GA100 Tensor 코어
지원되는 데이터 precision 관점에서, Volta의 1세대 Tensor 코어대비 Turing의 2세대 Tensor코어에는 AI 추론(inference) 성능 향상을 위해 INT8/INT4/INT1 precision에 대한 지원이 추가 됐습니다. 인공지능 학습(training)을 염두에 두고 개발된 Ampere의 3세대 Tensor 코어는 AI 학습 성능 향상을 위해 IEEE 표준인 FP16, FP32이외에도 AI분야에서 많이 사용되는 BF16, TF32 포맷에 대한 지원까지도 추가 했습니다. 부동소수점은 표현할 수 있는 범위와 관련된 지수(exponent)와 표현할 수 있는 유효숫자와 관련된 가수(mantissa) 부분으로 나눌 수 있는데, BF16은 FP16포맷에서 유효숫자를 희생하여 표현가능한 범위를 FP32와 동등하게 늘린 포맷이고 TF32는 지수부분은 FP32와 동일하게 두고 가수 부분을 FP16과 동일하게 줄인 포맷입니다. 각 포맷별로 32-bit/16-bit을 어떻게 지수와 가수에 분배해서 쓰는지는 아래그림 왼쪽에 정리되어 있습니다.
윗 그림의 오른쪽은 곱하는 행렬(Input Operands)과 결과를 누적하는 행렬(Accumulator)의 데이터 포맷에 따른 상대적인 성능을 TOPS로 비교하고 있는데, 곱하는 행렬의 데이터 포맷으로 FP32 대신에 TF32나 BF16 포맷을 사용하면 훨씬 많은 연산을 수행할 수 있음을 알 수 있습니다. 예를 들어 곱하는 행렬에 FP32포맷 대신 TF32포맷을 사용하면 8배의 성능 향상을 얻을 수 있습니다. (19.5 TOPS -> 156 TOPS) AI 학습과 추론의 경우 데이터의 유효숫자 보다는 범위가 중요한 경우가 많아 굳이 FP32 포맷을 쓰는 대신 TF32/BF16 포맷 만으로도 충분하기 때문에 이를 통해 큰 성능향상을 달성 할 수 있었습니다.
FP64 포맷과 관련된 개선도 있었는데, Volta의 Tensor 코어는 FP64 포맷을 지원하지 않아 SM마다 탑재된 32개의 FP64 코어를 사용하여 FP64 계산을 수행해야 했지만 Ampere GA100의 Tensor 코어는 FP64 포맷도 지원하기 때문에 FP64 코어나 Tensor 코어중에 원하는 연산에 맞는 코어를 사용할 수 있습니다. Tensor 코어의 FP64 포맷 지원을 통해 Volta 대비 Ampere의 FP64 연산 성능은 2.5배가 향상되었습니다.
Fine-Grained Structure Sparsity
Tensor 코어에 BF16/TF32 포맷 지원을 추가하는 것 이외에도 GA100의 Tensor 코어에는 AI 추론 성능향상을 위해 계산의 정확도와 성능을 trade-off 할 수 있는 기능이 추가 됐습니다. 학습된 Neural Network의 노드 값들이 0에 가까운 값들을 가지는 경우가 많다는 사실에 착안해 행렬의 4개 entry 마다 값이 작은 2개의 entry는 0으로 만들어 버린 후 계산하지 않는 것입니다. 계산해야할 행렬의 크기가 반으로 줄어들기 때문에 계산 속도가 두배로 올라가는 효과가 있지만 계산의 정확성은 희생하게 됩니다. A100 GPU white paper에 따르면 다양한 Neural Network에 대해서 실험했을 때 결과의 정확성에 차이가 거의 없었다고 하는데, 실제로 이 기능이 많이 사용되는지는 제가 AI 분야에서 일하지 않아 잘 모르겠습니다.
GA102 GPU
Ampere 아키텍처의 3D 그래픽용 GPU는 GA102인데, HPC 서버용인 A100 GPU와는 다른 공정으로 만들어졌습니다. nVidia에 특화된 삼성 8nm 공정으로 제작 되었으며 628.4mm2의 면적에 트랜지스터 수는 283억개로 A100 GPU의 542억개에 배히 절반 정도 입니다. GA102 GPU는 84개의 SM을 포함한 구조를 가지고 있으며 각 SM마다 RT 코어를 탑재하고 있다는 점이 A100 GPU와의 가장 큰 차이점입니다. Turing 아키텍처의 TU102 GPU와 비교하면 탑재된 SM의 개수는 72개에서 84개로 늘었습니다.
Ampere GA102 SM (Streaming Multiprocessor)
GA102 GPU의 SM 구조를 Turing SM의 구조와 비교할 때 가장 눈에띄는 차이점은 FP32 코어의 개수가 두배로 늘어난 점 입니다. Turing에 탑재되었던 INT32코어가 INT32 또는 FP32 연산도 할 수 있는 코어로 개선되어 Turing 에서는 싸이클당 16 INT32 + 16 FP32 연산이 가능했는데 Ampere GA102에서는 16 INT32 + 16 FP32 또는 32 FP32 연산이 가능해 졌습니다. INT32 연산이 필요하지 않을 때는 싸이클당 두배의 FP32 연산을 실행할 수 있게 된 것이지요. Turing에서 탑재되었던 96KB의 L1 cache는 Ampere GA102에서 128KB로 늘어났습니다. 앞에서 설명한 GA100과 마찬가지로 3세대 Tensor 코어를 탑재하여 Tensor 코어의 개수는 반으로 줄었지만 SM당 계산 성능은 두배가 되었고, BF16/TF32 포맷에 대한 지원 및 행렬의 sparsity를 이용해 추론의 정확성과 계산 속도를 trade-off 할 수 있는 기능도 동일하게 추가 되었습니다.
2세대 RT 코어
RT코어의 역할은BVH(Bounding Volume Hierarchy) tree node를 search한 후에 광선과 물체를 이루는 삼각형의 교차점을 계산하는 것입니다. (자세한 내용은 이전글 참조) Ampere의 2세대 RT 코어는 Turing의 1세대 RT 코어대비 tree search에 대한 caching을 개선하여 시간당 처리할 수 있는 광선의(Ray)수가 최대 두배까지 늘어날 수 있다고 합니다. 함께 SM 내에서 스케줄링을 개선시켜 효율을 높였는데, Turing의 경우에는 RT 코어에서 계산이 진행되는 동안 shader (INT32/FP32) 코어들이 계산을 멈추고 RT 코어의 결과를 기다렸지만 Ampere 에서는 RT 코어가 동작하는 동안 INT32/FP32 코어도 병렬처리가 가능하도록 변경 되었습니다.
아래 그림은 Turing 아키텍처의 TU102 GPU 대비 GA102 GPU의 성능향상을 각 구성요소 별로 정리한 것인데 RT 코어의 성능은 BVH tree의 구조와 cache latency의 영향을 받기 때문에 전체 GPU를 기준으로 따졌을 때 RT 코어의 성능향상은 SM이 72개에서 84개로 늘었음에도 1.7배 정도로 계산되었음에 주의할 필요가 있습니다.
마무리
Ampere 아키텍처는 Tensor 코어를 처음으로 탑재한 Volta나 RT 코어를 처음으로 탑재한 Turing 아키텍처들 처럼 새로운 코어를 도입하는 일 없이 기존 코어들의 성능을 향상시키고 공정미세화를 바탕으로 탑재된 SM의 개수를 늘리는 방향으로 발전 했습니다. HPC와 AI 시장을 대응하는 A100 GPU의 경우는 AI 필드에서 많이 쓰이는 BF16/TF32 포맷을 채용하고 자주 사용되는 Neural Net들을 분석해 sparsity를 통해 성능과 정확도를 trade-off 할 수 있는 기능을 넣은 점이 주목할 부분이라고 생각합니다. 그래픽용의 GA102 GPU의 경우 탑재된 코어들의 성능이 고르게 증가하면서 Ray Tracing의 지원을 대세로 만들었습니다. Ampere의 다음 아키텍처에서는 새로운 종류의 코어가 도입될지, 그리고 HPC용과 3D 그래픽용 아키텍처가 다시 한 번 갈라질지 아니면 하나의 아키텍처 이름이 그대로 유지될지가 관전 포인트라고 생각됩니다.