contiguous는 왜 자꾸 등장할까

많은 PyTorch 연산은 non-contiguous tensor도 처리할 수 있다. 하지만 처리 방식은 연산마다 다르다.

  • 어떤 연산은 stride를 따라 직접 접근한다
  • 어떤 연산은 내부에서 contiguous copy를 만든다
  • 어떤 custom kernel은 아예 contiguous만 가정한다

즉 contiguous 여부는 correctness뿐 아니라 성능과 메모리에도 영향을 준다.

memory format은 단순한 flag가 아니다

이미지 연산에서는 channels_last 같은 format이 있고, 일반 dense tensor에서는 전통적인 row-major contiguous layout이 흔하다. 중요한 것은 operator가 어떤 layout에서 더 잘 동작하는지, 그리고 layout 변환 비용이 연산 이득보다 작은지다.

hidden copy가 위험한 이유

숨은 복사는 다음 문제를 만든다.

  • 예상보다 메모리를 더 많이 쓴다
  • operator 자체보다 layout 변환이 더 비싸진다
  • profiling에서 "왜 여기서 시간이 많이 들지?"라는 혼란을 준다

특히 custom op를 만들 때 입력을 무조건 contiguous로 바꾸면 구현은 쉬워도 상위 시스템에서는 불필요한 비용이 누적될 수 있다.

좋은 습관

  • 입력 tensor의 stride와 is_contiguous를 먼저 본다
  • kernel이 어떤 layout을 기대하는지 분명히 한다
  • 변환이 필요하면 어디서 한 번만 할지 결정한다

다음 글에서는 dispatcher를 본다. PyTorch가 같은 연산 이름에 대해 CPU, CUDA, Autograd, Meta 같은 여러 구현을 어떻게 고르는지가 그 층에서 결정된다.