28.5 텐서의 형상(Shape)과 축(Axis)의 기하학적 해석
1. 형상의 정의
텐서의 형상(shape)은 각 모드(차원)의 크기를 순서대로 나열한 정수 튜플이다. d차 텐서 \mathcal{T} \in \mathbb{R}^{n_1 \times n_2 \times \cdots \times n_d}의 형상은 (n_1, n_2, \ldots, n_d)이다.
형상은 텐서의 구조적 정체성을 결정하는 핵심 속성이다. 동일한 원소 수를 가지더라도 형상이 다르면 서로 다른 텐서이다. 예를 들어, 12개의 원소를 가진 텐서는 (12,), (3, 4), (4, 3), (2, 2, 3), (2, 3, 2), (3, 2, 2), (2, 2, 3, 1) 등 다양한 형상을 가질 수 있으며, 각 형상은 서로 다른 인덱싱 구조와 의미론적 해석을 가진다.
딥러닝 프레임워크에서 형상은 tensor.shape 또는 tensor.size() 속성으로 접근한다. 형상 정보는 연산의 호환성 검사, 메모리 할당, 브로드캐스팅 규칙 적용 등에 사용되며, 잘못된 형상으로 인한 오류는 딥러닝 구현에서 가장 빈번하게 발생하는 문제 유형이다.
2. 축(Axis)의 개념
축(axis)은 텐서의 각 모드에 부여된 순서 번호이다. d차 텐서에서 축은 0, 1, \ldots, d-1로 번호가 매겨진다(0-인덱싱 기준). 각 축은 텐서의 한 방향을 나타내며, 해당 방향으로의 인덱싱 범위가 형상의 해당 원소이다.
(B, C, H, W) 형상의 4차 텐서에서:
- 축 0: 배치 방향, 크기 B
- 축 1: 채널 방향, 크기 C
- 축 2: 높이 방향, 크기 H
- 축 3: 너비 방향, 크기 W
축의 선택은 여러 텐서 연산에서 핵심적 매개변수이다. 축소(reduction) 연산에서 어떤 축을 따라 합산하는지에 따라 결과의 형상과 의미가 달라진다.
3. 축 기반 연산의 기하학적 의미
축을 따른 연산은 해당 방향으로 텐서를 “접는(folding)” 과정으로 이해할 수 있다.
축 기반 합산: \mathcal{T} \in \mathbb{R}^{n_1 \times n_2 \times n_3}에서 축 k를 따른 합산은 해당 모드를 소거하여 차수를 1 줄인다.
\text{축 0 합산:} \quad S_{jk} = \sum_{i=1}^{n_1} \mathcal{T}_{ijk}, \quad \mathbf{S} \in \mathbb{R}^{n_2 \times n_3}
\text{축 1 합산:} \quad S_{ik} = \sum_{j=1}^{n_2} \mathcal{T}_{ijk}, \quad \mathbf{S} \in \mathbb{R}^{n_1 \times n_3}
\text{축 2 합산:} \quad S_{ij} = \sum_{k=1}^{n_3} \mathcal{T}_{ijk}, \quad \mathbf{S} \in \mathbb{R}^{n_1 \times n_2}
기하학적으로 이는 3차원 직육면체를 특정 방향으로 눌러서 2차원 직사각형으로 만드는 것과 유사하다.
축 기반 평균: 합산 후 해당 축의 크기로 나눈 것이다.
\bar{T}_{jk} = \frac{1}{n_1}\sum_{i=1}^{n_1}\mathcal{T}_{ijk}
배치 정규화(batch normalization)에서 배치 축(axis 0)을 따른 평균과 분산 계산이 이 연산의 대표적 사례이다. 미니 배치 \mathbf{X} \in \mathbb{R}^{B \times d}에서 각 특성의 평균 \mu_j = \frac{1}{B}\sum_{i=1}^{B}x_{ij}는 축 0에 대한 평균이다.
축 기반 최댓값/최솟값: argmax와 함께 사용하면 해당 축을 따라 최대 원소의 인덱스를 반환한다. 분류 문제에서 torch.argmax(logits, dim=-1)은 마지막 축(클래스 축)을 따라 가장 큰 로짓의 인덱스, 즉 예측 클래스를 반환한다.
4. 형상의 호환성과 연산 규칙
텐서 연산에서 형상의 호환성은 연산 가능 여부를 결정한다.
원소별 연산: 두 텐서의 형상이 동일하거나 브로드캐스팅 가능해야 한다.
행렬 곱셈: \mathbf{A} \in \mathbb{R}^{m \times p}, \mathbf{B} \in \mathbb{R}^{p \times n}에서 \mathbf{A}의 마지막 축 크기와 \mathbf{B}의 첫 번째 축 크기가 일치해야 한다(p). 결과 형상은 (m, n)이다.
배치 행렬 곱셈: \mathcal{A} \in \mathbb{R}^{B \times m \times p}, \mathcal{B} \in \mathbb{R}^{B \times p \times n}에서 배치 축(축 0)은 일치하고, 나머지 두 축은 행렬 곱셈 규칙을 따른다. 결과 형상은 (B, m, n)이다.
축약(Contraction): einsum을 사용한 일반적 텐서 축약에서, 축약되는 인덱스의 크기가 관련 텐서들에서 일치해야 한다.
5. 형상 조작 연산
딥러닝에서 형상 조작은 매우 빈번하게 사용된다.
재형성(Reshape): 텐서의 원소 배열을 변경하지 않고 형상만 바꾼다. 원소 수가 보존되어야 한다. (B, C, H, W) 텐서를 (B, C \cdot H \cdot W)로 재형성하면, 각 이미지의 모든 픽셀 값을 하나의 벡터로 펼치는 효과이다. 이 연산은 합성곱 계층의 출력을 완전 연결 계층에 전달할 때 사용된다.
전치(Transpose)와 축 치환(Permute): 축의 순서를 재배열한다. (B, C, H, W) 텐서를 (B, H, W, C)로 변환하면 채널 축이 마지막으로 이동한다. 이는 채널 마지막(channels-last) 형식과 채널 먼저(channels-first) 형식 사이의 변환에 해당한다.
축 추가/제거: unsqueeze는 크기 1인 새 축을 삽입하여 차수를 1 높이고, squeeze는 크기 1인 축을 제거하여 차수를 1 낮춘다. (n,) 형상의 벡터를 (n, 1) 형상의 열벡터로 변환하려면 축 1에 unsqueeze를 적용한다.
6. 형상 설계와 딥러닝 아키텍처
딥러닝 모델의 설계에서 텐서의 형상은 아키텍처의 구조와 직접적으로 대응한다.
합성곱 신경망: 각 합성곱 계층은 입력 텐서 (B, C_{\text{in}}, H, W)를 출력 텐서 (B, C_{\text{out}}, H', W')로 변환한다. 형상의 변화는 커널 크기, 스트라이드, 패딩에 의해 결정된다. 출력의 공간 크기는 다음 공식으로 계산된다.
H' = \left\lfloor\frac{H + 2p - k}{s}\right\rfloor + 1
여기서 k는 커널 크기, s는 스트라이드, p는 패딩이다.
트랜스포머: 자기 어텐션(self-attention)에서 입력 (B, L, d_{\text{model}})이 쿼리, 키, 값 텐서 (B, L, d_k)로 사영되고, 어텐션 가중치 (B, L, L)이 계산되어 출력 (B, L, d_v)가 생성된다. 다중 헤드 어텐션에서는 헤드 축이 추가되어 (B, h, L, d_k) 형상의 텐서가 사용된다. 이 형상의 변화를 정확히 추적하는 것이 트랜스포머 구현의 핵심이다.
형상 불일치(shape mismatch)는 구현 오류의 가장 흔한 원인이며, einops 같은 라이브러리는 형상 조작을 명시적이고 가독성 높게 표현하여 이러한 오류를 방지하는 데 도움을 준다.