Gihak111 Navbar

개념

지금까지, Deep 알고리즘들을 정리하면서, 참 많은 개념들이 나왔다.
지수, 가수, 텐서코어, 쿠다코어, FP, 테라플롭스 등 너무 많은 개념들이 나왔다.
오늘은, 이런 개념들을 간단하게 정리하고 넘어가는 시간을 갖도록 하자.

1. 지수, 가수

이는, FP에서 사용되는 개념이다.
FP32, FP 16, FP8 등에서 사용되며,
데이터를 표현할 수 있는 량 정도로 생각하자.
간단하게, FP8을 예시로 설명하겠다. E5M2 일 경우, 부호 1, 지수 5, 가수 2 이다.
부호 1은 양수 음수를,
지수 5느 ㄴ최대 2^5의값 까지를,
가수 2는 지수에 곱해지는 1.xxx의 값을 나타낸다.
여기서 가수가 2비트면, 출력될 수 있는 경우의 수가 4가지 이므로,
1.0, 1.25, 1.5, 1.75 로 나오게 된다.
위 값과 앞선 지수 값을 곱한 값이 가중치와 입력값이 곱한 값이 되며,
만일, 값이 일치할 수 없으면 근사값으로 대체되며 오차가 발생한다.

FP8 같은 경우에는 특히 이런 오차가 더욱 심해서, 원래 사용하지 않았지만, DeepGEMM으로 해결되어 이제는 사용된다.

한번 더 정리하자면,
부호 : 양수 음수 결정 지수 : 숫자의 크기 결정 (2의 몇 배로 키울기) 가수 : 숫자의 모양 결정 (실제 숫자가 몇인지. 보통 1 + 소수로 표현) 이렇게 된다.

2. FP 부동소숫점

행렬곱셈에 사용된다.

1. FP32

FP32는 32비트로, 부호 1, 지수 8, 가수 23이다다. 정밀도가 높아서 64×784 입력과 784×256 가중치를 곱할 때 오차가 거의 없다.
하지만, 메모리 200KB나 먹고, Hopper에서 30~50 TFLOPS로 느리다.

2. FP16

FP16은 16비트, 부호 1, 지수 5, 가수 10이다. 메모리는 절반(100KB)이고 속도는 100 TFLOPS 정도로 빨라졌다.
784×256×2바이트조건에서도 401KB로 FP32보다 상대적으로 적다.
혼합 정밀도 훈련에서 많이 쓰이는데, 정밀도가 낮아서 작은 기울기가 사라질 수도 있다.

3. FP8

8비트, E5M2 포맷(지수 5, 가수 2), E4M3(지수 4, 가수 3)으로 메모리는 50KB밖에 안 되고, Hopper에서 200+ TFLOPS로 엄청 빠르다.
하지만, 정밀도가 너무 낮아서 오차가 쌓이는 게 문제이다.
이것을 어떻게 해결했는지는, 내 딥시크 DeepGEMM 글을 확인해 주길 바란다.

3. TFLOPS

TFLOPS는 “Tera Floating-point Operations Per Second”의 약자로, 초당 테라(1조) 번의 부동소수점 연산을 의미한다.
딥러닝에서 행렬곱셈 같은 연산이 엄청 많이 필요하니까, 이 수치가 높을수록 GPU나 TPU 같은 하드웨어가 더 빨리 계산을 끝낸다는 뜻이다.
예를 들어, Hopper H100 GPU는 FP32로 30~50 TFLOPS, FP16으로 100 TFLOPS, FP8로 200+ TFLOPS를 낸다.
즉, TFLOPS가 높으면 더 많은 데이터를 더 빨리 처리할 수 있어서, 대규모 모델 학습이나 추론(inference)에 유리하다.
하지만, TFLOPS만 보면 안 되고, 메모리 대역폭이나 정밀도 같은 것도 같이 봐야 전체 성능이 결정된다.

4. Hopper

Hopper는 NVIDIA의 최신 GPU 아키텍처 이름이다. H100 같은 GPU가 여기 속한다.
딥러닝에서 엄청난 성능을 내도록 설계됐는데, 특히 Tensor Core와 CUDA Core를 잘 활용해서 연산 속도를 높였다.
예를 들어, FP8 연산에서 200+ TFLOPS를 뽑아내면서도 메모리 사용량을 줄여서 대규모 모델(트랜스포머 같은)을 더 효율적으로 돌릴 수 있다.
Hopper의 강점은 혼합 정밀도 연산을 최적화한 점인데, FP8 같은 저정밀 연산에서도 오차를 줄이는 기술(DeepGEMM 같은)이 들어가서 실용성이 높아졌다.

1. Tensor Core

Tensor Core는 행렬곱셈을 전문으로 하는 하드웨어 유닛이다.
딥러닝에서 행렬곱셈(예: 입력 × 가중치)은 거의 모든 연산의 핵심인데, 이걸 일반 CUDA Core로 하면 느리다.
Tensor Core는 특히 FP16, FP8 같은 저정밀 연산을 빠르게 처리하도록 설계돼서, 예를 들어 64×784와 784×256 행렬곱을 몇 배 빠르게 끝낸다.
Hopper의 Tensor Core는 FP8까지 지원하면서도 DeepGEMM 같은 알고리즘으로 오차를 줄여서, 속도와 정확도를 둘 다 잡았다.

2. CUDA Core

CUDA Core는 NVIDIA GPU의 기본 연산 유닛이다.
Tensor Core가 행렬곱 같은 대규모 병렬 연산에 특화됐다면, CUDA Core는 더 일반적인 연산(예: 스칼라 연산이나 조건문 처리)을 맡는다.
딥러닝에서는 주로 Tensor Core가 핵심 역할을 하지만, 전처리나 후처리 같은 세부 작업은 CUDA Core가 돕는다.
Hopper에서도 여전히 CUDA Core가 포함돼 있어서, 유연한 연산이 가능하다.

5. DeepGEMM

DeepGEMM은 FP8 같은 저정밀 연산에서 오차를 줄이기 위해 개발된 알고리즘이다.
FP8은 메모리(50KB)와 속도(200+ TFLOPS) 면에서 엄청난 장점이 있지만, 정밀도가 낮아서 가중치나 기울기 값이 근사치로 바뀌면서 오차가 쌓인다.
DeepGEMM은 이런 문제를 해결하기 위해, 연산 과정에서 오차를 보정하거나 효율적으로 분배하는 방법을 쓴다.
예를 들어, E5M2 포맷(지수 5, 가수 2)에서 1.0, 1.25, 1.5, 1.75만 표현 가능할 때, 원래 값이 1.3이라면 1.25로 근사되는데, DeepGEMM은 이 오차를 나중에 보정해서 결과가 더 정확해지도록 돕는다.
Hopper 같은 GPU에서 FP8 연산이 실용화된 건 DeepGEMM 덕분이라고 보면 된다.

6. 혼합 정밀도 훈련

혼합 정밀도 훈련(Mixed Precision Training)은 FP32와 FP16(또는 FP8)을 섞어서 모델을 학습시키는 방법이다.
FP32는 정밀도가 높지만 느리고 메모리를 많이 먹고, FP16은 빠르고 메모리를 적게 먹지만 정밀도가 낮다.
그래서 중요한 부분(가중치 업데이트 같은)은 FP32로 하고, 덜 민감한 부분(행렬곱 같은)은 FP16으로 해서 속도와 정확도를 둘 다 잡는다.
예를 들어, 784×256 가중치 행렬을 FP16으로 계산하면 401KB만 먹지만, 기울기가 너무 작아질 때는 FP32로 보정한다.
Hopper 같은 GPU는 이런 혼합 정밀도를 하드웨어 수준에서 최적화해서 더 효율적이다.

7. 메모리 대역폭

메모리 대역폭은 GPU가 메모리에서 데이터를 얼마나 빨리 읽고 쓸 수 있는지를 나타낸다. 단위는 GB/s(초당 기가바이트)로 표현된다.
딥러닝에서는 행렬곱셈할 때 입력과 가중치를 계속 메모리에서 불러와야 하니까, 대역폭이 낮으면 병목현상이 생겨서 연산 속도가 아무리 빨라도 소용없다.
Hopper H100은 대역폭이 3TB/s 수준으로 엄청 높아서, FP8 연산처럼 메모리 사용량이 적은 경우에도 데이터를 빠르게 처리한다.

8. 배치 크기 (Batch Size)

배치 크기는 한 번에 학습시키는 데이터 샘플 수다.
예를 들어, 64×784 입력 행렬이 있으면 배치 크기가 64인 셈이다.
배치 크기가 크면 GPU의 병렬 연산을 더 잘 활용해서 속도가 빨라지지만, 메모리를 더 많이 먹는다.
FP32로 64×784×256 행렬곱을 하면 200KB쯤 되는데, 배치 크기를 128로 늘리면 두 배로 뛰어서 메모리 부족 문제가 생길 수 있다.
FP8이나 FP16을 쓰면 메모리 부담이 줄어서 더 큰 배치 크기를 쓸 수 있다.

9. 활성화 함수 (Activation Function)

활성화 함수는 뉴런의 출력값을 비선형으로 바꿔주는 함수다.
딥러닝에서 행렬곱셈(입력 × 가중치) 결과에 활성화 함수를 적용해서 모델이 복잡한 패턴을 학습할 수 있게 한다.
예를 들어, ReLU(Rectified Linear Unit)는 음수를 0으로 만들고 양수는 그대로 두는데, 계산이 단순해서 속도가 빠르다.
FP8 연산에서는 활성화 함수 값이 근사치로 떨어질 수 있어서, 오차가 쌓이지 않도록 주의해야 한다.

10. 그래디언트 (Gradient)

그래디언트는 모델을 학습시킬 때 가중치를 업데이트하는 방향을 알려주는 값이다.
행렬곱셈 결과와 손실 함수를 미분해서 구하는데, FP16이나 FP8에서는 정밀도가 낮아서 작은 그래디언트가 0으로 사라질 수 있다(Gradient Vanishing).
혼합 정밀도 훈련에서는 이런 문제를 FP32로 보정해서 해결한다.
Hopper의 Tensor Core는 그래디언트 계산도 빠르게 처리해서 학습 속도를 높인다.

11. 스케줄링 (Scheduling)

스케줄링은 GPU에서 연산 작업을 어떤 순서로, 어떻게 배분할지를 결정하는 과정이다.
딥러닝에서는 행렬곱셈, 그래디언트 계산, 가중치 업데이트 같은 작업이 동시에 여러 개 돌아가는데, 이걸 효율적으로 관리해야 성능이 최적화된다.
예를 들어, 64×784×256 행렬곱을 할 때, Tensor Core와 CUDA Core에 작업을 나눠주고, 메모리에서 데이터를 언제 불러올지 순서를 정하는 게 스케줄링이다.
Hopper 같은 GPU는 하드웨어 수준에서 스케줄링을 최적화해서 병렬 연산 효율을 극대화한다.

12. 타일 스케줄링 (Tile Scheduling)

타일 스케줄링은 큰 행렬곱셈을 작은 조각(타일)으로 나눠서 계산하는 스케줄링 기법이다.
예를 들어, 784×256 행렬을 한 번에 계산하려면 메모리와 연산 부담이 크니까, 32×32 크기의 작은 타일로 쪼개서 순차적으로 처리한다.
이렇게 하면 메모리 사용량이 줄고, Tensor Core 같은 유닛이 더 효율적으로 작동한다.
Hopper의 Tensor Core는 타일 단위로 연산을 최적화해서, FP8 같은 저정밀 연산에서도 속도와 정확도를 유지한다.

13. 캐시 (Cache)

캐시는 GPU 안에 있는 초고속 메모리로, 자주 쓰이는 데이터를 저장해서 메모리 대역폭 부담을 줄인다.
딥러닝에서 입력이나 가중치 같은 데이터를 메모리에서 계속 불러오면 느려지니까, 캐시에 미리 저장해두고 재사용한다.
예를 들어, 64×784 입력 행렬의 일부를 캐시에 올려두면, 반복 연산할 때 빠르게 접근할 수 있다.
Hopper는 캐시 설계를 개선해서 타일 스케줄링과 함께 연산 속도를 더 끌어올렸다.

14. 병렬 처리 (Parallel Processing)

병렬 처리는 여러 연산을 동시에 실행하는 걸 의미한다.
딥러닝에서는 행렬곱셈이나 그래디언트 계산을 수천 개의 스레드로 나눠서 GPU에서 동시에 돌린다.
Tensor Core는 행렬곱을 병렬로 처리하고, CUDA Core는 세부 작업을 병렬로 돕는다.
예를 들어, 64×784×256 연산을 64개 배치로 쪼개서 병렬로 계산하면 시간이 훨씬 단축된다.
Hopper는 병렬 처리 성능이 극대화돼서 대규모 모델을 빠르게 학습시킬 수 있다.

15. 오버피팅 (Overfitting)

오버피팅은 모델이 학습 데이터에 너무 잘 맞춰져서 새로운 데이터에 대해선 성능이 떨어지는 현상이다.
딥러닝에서 행렬곱셈으로 가중치를 계속 업데이트하다 보면, 데이터의 노이즈까지 학습해버릴 수 있다.
예를 들어, 784×256 가중치가 학습 데이터의 특정 패턴만 과도하게 반영하면 테스트 데이터에서 오차가 커진다.
이를 막기 위해 드롭아웃(Dropout)이나 정규화(Regularization) 같은 기법을 쓰는데, FP8 같은 저정밀 연산에서는 오차 자체가 자연스러운 정규화 효과를 줄 때도 있다.

결론

위와 같은 내용을 이해하고 있으면, 딥러닝을 더욱 깊게 이해할 수 있다.