24년 1월 30일에 새로이 update된 Pytorch 2.2는 여러 변경사항이 존재한다.
📌 목차
1. TorchRL
2. TorchVision - Transform v2
3. TorchVision - torch.compile()
🧐 Summary
Pytorch 2.2는 여러 도메인에서 아래와 같은 Update가 있었다:
1. TorchRL
2. TorchVision - Transform v2
torchvision.transform.v2
transform v2가 드디어 오픈되었다.
간단한 소개?정도와 내용을 조금만 알아보려 한다.
∙ V2 API Reference
Examples
∙ Classification
import torch from torchvision.transforms import v2 H, W = 32, 32 img = torch.randint(0, 256, size=(3, H, W), dtype=torch.uint8) transforms = v2.Compose([ v2.RandomResizedCrop(size=(224, 224), antialias=True), v2.RandomHorizontalFlip(p=0.5), v2.ToDtype(torch.float32, scale=True), v2.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ]) img = transforms(img)
∙ Detection
# Detection (re-using imports and transforms from above) from torchvision import tv_tensors img = torch.randint(0, 256, size=(3, H, W), dtype=torch.uint8) boxes = torch.randint(0, H // 2, size=(3, 4)) boxes[:, 2:] += boxes[:, :2] boxes = tv_tensors.BoundingBoxes(boxes, format="XYXY", canvas_size=(H, W)) transforms = v2.Compose( [ v2.ToImage(), v2.RandomPhotometricDistort(p=1), v2.RandomZoomOut(fill={tv_tensors.Image: (123, 117, 104), "others": 0}), v2.RandomIoUCrop(), v2.RandomHorizontalFlip(p=1), v2.SanitizeBoundingBoxes(), v2.ToDtype(torch.float32, scale=True), ] ) # The same transforms can be used! img, boxes = transforms(img, boxes) # And you can pass arbitrary input structures output_dict = transforms({"image": img, "boxes": boxes})
아래 Reference Code참고) Pytorch Starting with Transform V2
3. TorchVision - torch.compile( )
torch.compile()
torch.compile()의 update는 점점 그래프나누기를 줄이고 동적형태를 허용한다.
transform측면에서 대부분 저수준커널(ex. resize, crop, 등)은
그래프 중단없이 동적으로 compile되어야한다.
사용목적:
∙ Tensorflow의 model.compile:
함수 인자로 Optimizer, Loss, Metric을 사용한다.
model.compile(optimizer="Adam", loss="mse", metrics=["mae"])
∙ Pytorch의 torch.compile:
기존 학습코드자체는 그대로 유지.
Pytorch가 기존에 작동하던 C++베이스→Python상에서 구동되게 함.
[적용되는 기술들]:
위의 그래프는 pytorch개발자들이 진행한 실험의 결과그래프이다.
- TorchDynamo : Python frame evaluation hooks를 사용해 pytorch 안정성에 기여.
정확히는 아직 잘 모르겠지만 역전파 같은 graph capture에서 도움이 된다.- AOTAutograd : 기존 pytorch의 Autograd 엔진을 오버로딩한다.
미리 연산된 역연산 trace를 생성하기 위해 자동미분을 예측한다.- PrimTorch : 완벽한 PyTorch 백엔드를 구축하기 위해 개에 달하는
pytorch 연산들을 개의 기본 연산들로 canonicalize한다.- TorchInductor : 여러 액셀러레이터 및 백엔드용 고속 코드를 생성하는 딥러닝 컴파일러.
NVIDIA GPU의 경우 OpenAI Triton을 주요 구성 요소로 사용함.
(구체적으로 46개의 HuggingFace Transformer 모델들, 61개의 TIMM model들 그리고 56개의 TorchBench 모델들)로 실험을 진행.
[결과]:
단순히 torch.compile으로 wrapping해준 것만으로 모델 Training이 43%빠른속도로 동작했다.
(다만, 이는 A100으로 측정된 결과이고, 3090같은 시리즈는 잘 동작하지 않고 심지어 더 느릴 수 있다 언급:
Caveats: On a desktop-class GPU such as a NVIDIA 3090, we’ve measured that speedups are lower than on server-class GPUs such as A100. As of today, our default backend TorchInductor supports CPUs and NVIDIA Volta and Ampere GPUs. It does not (yet) support other GPUs, xPUs or older NVIDIA GPUs.)
이를 2.2버전에서는 좀 더 완성시킨 것이다!
pytorch개발자분들은 버전이 2.x로 넘어가면서 compile함수에 좀 더 집중한다하였다.
아마 점점 학습속도를 빠르게하는 면을 강화하고, 이를 점차 확대할 것 같다.
(이번에 저수준커널에도 적용한 걸 보면 거의 확실시 되는듯하다.)
개발동기:
17년 시작된 이후, Eager Execution성능향상을 위해 코드 대부분을 C++로 옮기게 되었다.
(Pytorch 대부분의 소스코드가 C++기반임을 근거로 알 수 있다.)
(eager execution: 그래프생성없이 연산을 즉시실행하는 환경)
이런 방식을 사용자들의 코드기여도(hackability)를 낮추는 진입장벽이 되어버렸다.
이런 eager execution의 성능향상에 한계가 있다 판단하여 compiler를 만들게 되었다.
목적은 속도는 빠르게하나 pytorch experience를 해치지 않는다는 것이다.
🤔 How to use?
torch.compile()은 기존 모델에 한줄만 추가하면 된다.
import torch import torchvision.models as models model = models.resnet18().cuda() optimizer = torch.optim.SGD(model.parameters(), lr=0.01) compiled_model = torch.compile(model) x = torch.randn(16, 3, 224, 224).cuda() optimizer.zero_grad() out = compiled_model(x) out.sum().backward() optimizer.step()
compiled_model은 신경망의 forward를 좀 더 최적화시켜 속도를 빠르게 한다.
def torch.compile(model: Callable, *, mode: Optional[str] = "default", dynamic: bool = False, fullgraph:bool = False, backend: Union[str, Callable] = "inductor", # advanced backend options go here as kwargs **kwargs ) -> torch._dynamo.NNOptimizedModule
∙ mode:
[default]:torch.compile(model) torch.compile(model, mode="reduce-overhaed") torch.compile(model, mode="max-autotune")
너무 오래걸리지 않으면서 메모리를 많이 사용하지 않는 선에서 효율적인 컴파일 진행
[reduce-overhead]:
메모리를 좀 더 사용, overhead를 줄여줌
[max-autotune]:
가장 빠른 모델생성을 위해 최적화되어있다.
다만, 컴파일에 매우 오랜시간이 걸린다.
∙ dynamic:
dynamic shape에 대해 code path를 enabling할 지 결정하는 boolean 변수이다. Compiler 최적화 과정이 프로그램을 dynamic shape 프로그램에 적용될 수 없게 만드는 경우가 있는데, 이를 조절함으로써 본인이 원하는 방향대로 컴파일을 할 수 있게 해준다. 이 부분은 아직 완벽히 이해가 되지는 않지만 데이터 shape가 변하는 상황에서 graph를 유동적으로 컴파일할 수 있게끔 하는 것과 관련이 있을 것 같다.∙ fullgraph:
Numba의 nopython과 유사하다. 전체 프로그램을 하나의 그래프로 컴파일하고, 만약 실패한다면 왜 불가능한지 설명해주는 error 메세지를 띄운다. 굳이 쓰지 않아도 상관없는 옵션.∙ backend:
어떤 compiler backend를 적용할 지 결정하게 된다. 디폴트로 정해진 값은 앞서 설명했던 TorchInductor가 사용되지만, 다른 옵션들도 존재한다고 한다(제대로 알아보진 않았다).
❗️ 유의점:
compile된 모델 저장 시, state_dict만 저장가능하다.
∙ 아래는 가능!torch.save(opt_model.state_dict(), "best.pt")
torch.save(model.state_dict(), "best.pt")
torch.save(model, "best.pt")
∙ 아래는 불가능!torch.save(opt_model, "best.pt")
Compile 이후 사용가능한 기능:
∙ TorchDynamo
Eager Mode의 가장 용이한 점:
학습도중 model_weight에 접근하거나 값을 그대로 읽어올 수 있다.model.conv1.weight
TorchDynamo는 이를 인지하고 만약 attribute가 변한것을 감지하면
자동으로 해당부분에 대한 변화를 다시 컴파일해준다.
∙ Inference
compile함수로 compiled_model을 생성한 후 warm-up step은 초반 latency를 줄여준다.
다만, 이부분도 차차 개선시킨다 하였다.exported_model = torch._dynamo.export(model, input) torch.save(exported_model, "foo.pt")
'Deep Learning : Vision System > Pytorch & MLOps' 카테고리의 다른 글
[WandB] Step 3. WandB 시각화 방법. (0) | 2024.01.09 |
---|---|
[WandB] Step 2. WandB Sweeps (2) | 2024.01.09 |
[WandB] Step 1. WandB Experiments. with MNIST (2) | 2024.01.09 |