torch.compile의 무조건적 최적화라는 오해

많은 엔지니어는 `torch.compile`을 적용하면 무조건 GPU 연산이 최적화될 것이라고 믿는 경향이 있다. 분석가는 이러한 믿음을 검증하기 위해 NVIDIA A100-SXM4-80GB GPU 환경에서 `02_linear.py`, `03_simple_mlp.py`, `03_kernels_mlp.py` 스크립트를 실행했다. 실험 설정은 `wait=1`, `warmup=1`, `active=3`으로 구성하여 프로파일링 단계의 일관성을 확보했다. 사용자는 Hugging Face 인프라의 Dev Mode나 Jobs pipeline을 통해 동일한 GPU 환경을 설정하고 해당 스크립트를 실험할 수 있다. 단일 선형 연산 구조에서는 컴파일러가 퓨전(Fusion)할 대상이 부족하여 기대만큼의 GPU 성능 향상이 나타나지 않는 지점이 존재한다.

nn.Linear의 바이어스 합산과 GEMM 에필로그

`nn.Linear` 모듈은 내부적으로 `torch.nn.functional.linear`를 거쳐 `aten::linear`를 호출하며, 최종적으로 `aten::addmm`을 통해 행렬 곱셈과 바이어스 합산을 처리한다. `aten::addmm`은 바이어스 합산 작업을 GEMM(General Matrix Multiply) 커널 내부의 에필로그(Epilogue)로 처리하여 별도의 `aten::add` 커널을 생성하지 않는다. 에필로그는 GEMM 커널이 연산 결과를 HBM(High Bandwidth Memory)에 쓰기 직전에 수행하는 작은 계산 단계다. 이 방식은 연산 결과를 메모리에 썼다가 다시 읽어오는 HBM 재접근 과정을 생략하여 메모리 트래픽 비용을 낮춘다. cuBLAS GEMM 커널은 바이어스 합산 기능이 내장된 변형 커널을 보유하고 있으며, `aten::addmm`은 이 전용 커널을 선택해 실행한다.

aten::t 연산의 CPU 메타데이터 수정 원리

프로파일러 트레이스에서 `aten::addmm` 이전에 나타나는 `aten::t`(전치) 연산은 GPU 커널을 실행하지 않고 CPU에서 텐서 메타데이터만 변경한다. 텐서는 메모리에 평탄한 연속 배열로 저장되며, CPU는 shape과 스트라이드(Stride, 데이터 간격)라는 메타데이터를 수정해 전치된 행렬의 뷰(View)를 생성한다. 스트라이드 값의 변경은 실제 데이터를 복사하거나 물리적으로 재배치하지 않고도 데이터를 전치된 순서로 읽게 만든다. 분석가는 GPU 레인에 `aten::t`를 위한 커널 런칭 기록이 없음을 확인하여 이 작업이 CPU 수준의 가벼운 메타데이터 수정임을 증명했다. 결과적으로 `aten::t`는 GPU 자원을 소모하지 않는 CPU 디스패치 체인의 일부로 작동한다.

Eager 모드와 Compiled 모드의 CPU 오버헤드 차이

`torch.compile`을 적용한 Compiled 모드는 Eager 모드와 동일한 GPU 커널을 실행하지만, CPU의 디스패치 오버헤드를 제거한다. Eager 모드에서는 `aten::t`를 통해 뷰를 생성하고 `aten::addmm`을 호출하는 CPU 디스패치 과정이 매번 반복된다. 반면 Inductor(PyTorch 컴파일러 백엔드)는 컴파일 타임에 스트라이드를 미리 계산하여 `aten::t` 호출을 생략하고 `aten::addmm`을 직접 호출하는 코드를 생성한다. 이 과정에서 GPU가 수행하는 수학적 연산은 동일하지만, 뷰 생성과 연산 디스패치에 소요되던 수 마이크로초 단위의 CPU 작업이 사라진다. 따라서 단일 GEMM-with-bias 구조에서 `torch.compile`의 실질적인 이득은 GPU 연산 최적화가 아닌 CPU 명령 하달 시간의 단축에서 발생한다.

커널 해시 분석을 통한 GPU 작업 일치 판단 기준

분석가는 프로파일러 트레이스에 기록된 커널 이름의 해시 덤프를 통해 GPU가 실제로 수행한 작업의 동일 여부를 판단한다. cuBLAS와 CUTLASS는 입력 레이아웃 조합(전치 여부 등)에 따라 사전 컴파일된 별도의 커널 바이너리를 제공하며, 이는 커널 이름 끝의 `_tn_` 또는 `_nn_`과 같은 접미사로 구분된다. 여기서 `t`는 전치(Transposed), `n`은 비전치(Non-transposed) 상태를 의미하며, bf16이나 fp16 같은 데이터 타입 차이 역시 해시값에 반영된다. 두 실행 결과의 커널 이름 해시가 완전히 일치한다면, CPU 디스패치 경로가 다르더라도 GPU는 물리적으로 동일한 바이너리를 실행한 것이다. 실무자는 이 해시값을 대조함으로써 단일 연산 최적화와 연산 체인 퓨전의 차이를 구분하고, 실제 GPU 작업의 일치 여부를 결정하는 객관적 기준으로 삼을 수 있다.

bash
python 03_simple_mlp.py