https://mari970.tistory.com/83
이번 포스팅은 Software stack 1 (1) 글의 첫번째 그림에서 Acceleration libraries 를 배워보자.
이번 포스팅에서 배울 것은 아래와 같다.
- TensorRT
- inference 시에 모델 배포 등에 사용하는 optimization 구현
- CuBLAS, CuDNN, NCCL 등의 계산 라이브러리 보다 상위에 존재한다.
- CuBLAS
- BLAS(Basic Linear Algebra Subprogram) api 와 GAMM api 의 선형대수 계산을 cuda 로 구현한 라이브러리이다. 예를 들면 matrix multiplication 이나 transpose 등
- 백엔드 라이브러리
- CuDNN
- conv, attn 등의 딥러닝에서 많이 사용되는 primitive 연산을 cuda 로 구현하였다. ( = Deep learning specific 라이브러리)
- 백엔드 라이브러리
- NCCL
- NVIDIA Collective Communication Library (니클이라 읽는다)
- multi- gpu 나 node 머신 사용시 communication premitive operator 들을 구현했다.
- 백엔드 라이브러리
- CUDA
- Compute Unified Device Architecture
- gpu 에서 사용할 수 있는 general-purpose processing 을 accelerate 할 수 있도록 구현한 api
- thread-level parallelism 을 구현한 C 언어의 extension
- CUDA semantics in PyTorch
** 그리고 OpenAI Triton : 위 nvidia 의 라이브러리 들이 c 언어 기반이라면, Triton 은 하드웨어 지식 기반 요구등의 문제를 해결하는 파이썬 기반 라이브러리.
TensorRT
TensorRT 는 계산 라이브러리는 아니고 Software Development Kit(SDK) 이다
딥러닝 inference 를 하기 위한 SW 플랫폼이라고 할 수 있다.
CPU 대비 40배 빠르고, application 의 디바이스마다 다르게 최적화되어있기 때문에 배포할 때 편리하다.
TensorRT 는 아래 5가지 기능을 가진다.
1. Layer Fusion + Tensor Fusion
TensorRT 에서는 Layer & Tensor Fusion 을 사용한다.
GPU 는 CPU 의 co-processor 이다. 즉, GPU 는 단독으로 동작하지 않고, 병렬연산이 필요할 때 CPU 의 명령을 받는다.
이때 GPU 에 data 를 복사해 보내줘야하고 GPU 는 연산한 결과를 다시 CPU 로 보내야한다.
-> 이 때 생기는 data copy 는 많은 시간과 에너지가 필요한 비효율적인 작업이다.
그래서 위 그림의 "Un-Optimized Network" 를 예를 들면, 모델에서 layer (그리고 tensor 연산나 kernel) 하나하나를 수행할 때 위의 data copy 통신과정이 필요한다.
TensorRT 에서는 이를 더 효율적으로 하기위해 각 연산들 중 동시에 계산할 수 있는 연산들을 합쳐서 (fusion) 같이 통신해준다.
그러면 ResNet-152 네트워크를 예로 들때, fusion 을 하지 않은 네트워크의 (아마 data copy 를 해야하는) 레이어 개수가 670개라면 최적화 이후에는 159개로 줄어들 수 있다.
2. Auto-Tuning
Target device 에 맞는 커널을 자동으로 설정한다.
kernel 에 들어가는 파라미터인 batch size, input data size, tensor layout, input dimension, memory 등을 자동으로 튜닝한다.
3. Multi-stream execution
독립적인 batch 나 inference 에 대한 cuda stream (=process 와 비슷한 개념) 을 동시에 여러개 실행할 수 있다.
1개 gpu 안에서 multi-stream 을 병렬적으로 사용할 수 있도록 한다.
GPU 하드웨어가 multi-stream 을 할 수 있어야 한다.
4. Dynamic Tensor memory
activation 텐서 재사용을 최대화하기 위한 메모리 관리 기법이다.
메모리 footprint 를 줄인다 : tensor 가 실제로 사용될 때만 allocation 함으로서 allocation 하는 시간을 줄인다.
5. Precision calibration
Bit Quantization(이하 그냥 Quantization) 에서 사용하는 low precision (FP16, INT8 등) 을 자동으로 calibration 한다.
GPU 아키텍처는 (NVIDIA) Volta(v100 은 volta 아키텍처의 서버형) →Ampere(a6000 등)→Hopper→Balckwell 이 있는데 Volta 에서부터 tensor core 라는 구조가 생겼다.
이 구조는 기본적으로 FP16 으로 동작하고, 행렬 multiplication 을 전문적으로 해준다.
이 tensor core 가 없던 기존 GPU 연산기능은 general prupose 에 초점이 맞춰져있다. 이는 딥러닝 뿐 아니라 다른 사용에 초점이 맞춰져있다는 것이다.
** FP32 를 사용하면 tensor core 를 사용못함
예를 들면 INT8 로 변환할 때: 실수 → 정수 mapping 해야한다.
weight 는 알고있기 때문에 quant 를 그냥 계산할 수 있는데, activation 은 실시간으로 들어오기 때문에 data 분포를 알아야 quant 할 수 있다.
하지만 그렇게하면 계이 매우 느려지기 때문에
application task 의 대표 dataset (calibration dataset)을 넣어 얻은 activation 을 사용한다. 그래서 기존 fp32 의 calibration dataset activation 와 int8의 그것과 kl-divergence minimize 를 해준다.
TensorRT deployment Workflow
optimizer : optimized plans 를 runtime engine 에 넘기면 optimize된 모델이 돌아간다.
타겟 디바이스가 NVIDIA 여야하고 타겟 gpu 안에 tensorRT runtime 엔진이 깔려 있어야한다.
tensorflow 모델 기준 그림
Torch-TensorRT workflow
는 아래와 같다.
import torch
import torch_tensorrt # 모듈 임포트 필요
import torchvision.models as models
# initialization model with half precision
model = models.resnet18(pretrained = True),half().eval().to('cuda')
inputs = [torch.randn((1,3,224,224)).to('cuda').half()] # batch size=1
enables_precisions = {torch.half} # fp16
debug = True # log print 여부
workspace_size = 20 << 30
min_block_size = 7 # TRT 엔진의 최대개수
torch_executed_ops = {} # tensorrt 에서 돌아가지않고 torch native 동작할 연산들 넣음.
# tensorrt 에서 지원하는 연산이 한정적이다. 지원을 안하는 레이어 타입등이 있음.
optimized_model = torch_tensorrt.compile( # 컴파일하면 최적화된 모델 생성
model,
ir = "torch_compile",
inputs=inputs,
enabled_precisions=enabled_precisions,
debug=debug,
workspace_size=workspace_size,
min_block_size=min_block_size,
torch_executed_ops=torch_executed_ops,
)
outputs = optimized_model(*inputs) # inference
# batch_size 가 달라지면 compile 을 다시해야한다.
new_inputs = [torch.randn((8,3,224,224)).to('cuda').half()] # batch size=8
new_outputs = optimized_model(*new_inputs)
# clean up = memory allocation 을 푼다.
torch._dynamo.reset()
BLAS : Basic Linear Algebra Subprogram
이름과 같이 선형대수 routine 들을 구현해놓은 라이브러리.
CuBLAS 는 Cuda 로 구현되어 GPU 에서 선형대수 동작이 가능하다.
함수 예시는 cublasIsmax(), cublasSgemm(), cublasDtrmm() 등이 있다.
** cublasSgemm =’S’ 는 single precision 이라는 뜻, gemm 은 generalized matrix multiplication 이다.
cublas 의 장점은 여러 개 kernel 을 stream 을 통해 batching 할 때 빨리 동작한다는 것이다.
선형대수가 많이 사용되는 application 에서 사용된다.
함수에는 S, D, C, Z 4가지 버전이 있다.
S 는 single precision, D 는 double precision.
C Z 는 S D 와 똑같은데 complex 값에 사용된다.
cuBLAS 와 torch 는 어떻게 연결되어있는가.
pytorch/aten/src/ATen/cuda/CUDABlas.cpp : 이 파일에는 gemm operation wrapper 가 있다. 이는 파이토치 frontend 와 연결된다.
아래 코드 캡처를 보면 gemm 안에서 cublasSgemm 을 호출하고 있는 것을 확인할 수 있다.
cublasSgemm은 so 라이브러리 file ( /usr/local/cuda-10.0/lib64/libcublas.so )에 구현되어있다.
cuDNN
** opensource 공개는 되어있지 않다. (cuBLAS 도 마찬가)
CUDA Deep Neural Network 라이브러리로, dnn 에서 사용하는 GPU-accelerated preimitive 연산이 구현된 라이브러리이다.
나머지 CUDA 와 NCCL 은 다음 포스팅에서,,
'머신러닝 이모저모' 카테고리의 다른 글
Peft save_pretrained() 에러 : UnboundLocalError: local variable 'active_adapters' referenced before assignment (0) | 2024.10.20 |
---|---|
[이화여대 강의] 2. Deep Learning Software Stack 1 (3) (3) | 2024.09.21 |
[이화여대 강의] 2. Deep Learning Software Stack 1 (1) (0) | 2024.09.20 |
[이화여대 강의] Orientation (0) | 2024.09.20 |
Precision 개념 (0) | 2024.02.18 |