텐서 조작하기: Reshape, Squeeze, Unsqueeze
텐서의 Reshape
Reshape는 텐서의 크기(shape)를 변경하는 연산이다. 크기를 변경할 때 텐서의 원소 개수는 변경되지 않으며, 변경 전과 후의 원소 개수는 같아야 한다. 예를 들어, 크기가 ((2, 3))인 텐서를 ((3, 2))로 바꾸거나, ((6,))으로 변경할 수 있다.
수학적으로, 텐서 (\mathbf{A})의 크기가 ((m, n))일 때, Reshape 연산을 통해 (\mathbf{A})를 ((p, q))로 변환할 수 있다. 이때 (m \cdot n = p \cdot q)가 성립해야 한다. 만약 (\mathbf{A})가 다음과 같다고 하자.
[ \mathbf{A} = \begin{bmatrix} a_{11} & a_{12} & a_{13} \ a_{21} & a_{22} & a_{23} \end{bmatrix} ]
이 텐서를 ((3, 2)) 크기로 변환하면 다음과 같이 표현된다.
[ \mathbf{B} = \begin{bmatrix} a_{11} & a_{12} \ a_{13} & a_{21} \ a_{22} & a_{23} \end{bmatrix} ]
코드 예시:
import torch
A = torch.tensor([[1, 2, 3], [4, 5, 6]])
B = A.reshape(3, 2)텐서의 Squeeze
Squeeze는 텐서에서 크기가 1인 차원(dimension)을 제거하는 연산이다. 예를 들어, 크기가 ((1, 3, 1, 5))인 텐서가 있을 때, Squeeze 연산을 적용하면 ((3, 5)) 크기의 텐서로 바뀐다.
수학적으로, 텐서 (\mathbf{C})의 크기가 ((d_1, d_2, \ldots, d_n))이고, (d_i = 1)인 차원이 있을 때 Squeeze 연산은 해당 차원을 제거하여 ((d_1, \ldots, d_{i-1}, d_{i+1}, \ldots, d_n)) 크기의 텐서로 변환한다. 예를 들어, 텐서 (\mathbf{D})의 크기가 ((1, 3, 1, 4))라면, Squeeze 연산 후에는 ((3, 4))가 된다.
코드 예시:
C = torch.tensor([[[[1, 2, 3, 4]]], [[[5, 6, 7, 8]]]])
D = C.squeeze()텐서의 Unsqueeze
Unsqueeze는 기존 텐서에 크기가 1인 차원을 추가하는 연산이다. 예를 들어, 크기가 ((3, 5))인 텐서가 있을 때, Unsqueeze 연산을 통해 ((1, 3, 5)) 또는 ((3, 1, 5))와 같이 차원을 확장할 수 있다.
수학적으로, 텐서 (\mathbf{E})의 크기가 ((d_1, d_2, \ldots, d_n))일 때, Unsqueeze 연산을 통해 ((d_1, \ldots, d_i, 1, d_{i+1}, \ldots, d_n)) 크기의 텐서를 얻을 수 있다. 예를 들어, (\mathbf{E})의 크기가 ((4, 6))이라면, ((1, 4, 6)) 또는 ((4, 1, 6))와 같은 텐서로 확장할 수 있다.
코드 예시:
Reshape, Squeeze, Unsqueeze의 활용 예시와 특징
Reshape, Squeeze, Unsqueeze는 주로 텐서의 차원을 조작하여 모델의 입력 형태를 맞추거나, 데이터 전처리 과정에서 자주 사용된다. 예를 들어, 딥러닝 모델의 입력으로 이미지 데이터를 넣을 때, 각 배치(batch)의 크기를 맞추기 위해 차원을 조작할 필요가 있다.
Reshape의 주의점
Reshape 연산을 사용할 때 텐서의 원소 개수가 동일해야 하며, 변경하고자 하는 크기의 곱이 원래 텐서의 원소 개수와 일치해야 한다. 이를 수식으로 표현하면, 원래 텐서 (\mathbf{X})의 크기가 ((m_1, m_2, \ldots, m_k))일 때, Reshape 후의 텐서 크기 ((n_1, n_2, \ldots, n_l))에 대해 다음이 성립해야 한다.
[ m_1 \cdot m_2 \cdot \ldots \cdot m_k = n_1 \cdot n_2 \cdot \ldots \cdot n_l ]
Reshape는 텐서의 메모리 구조를 변경하지 않고 크기만 바꾸기 때문에, 연산 속도가 빠르다는 장점이 있다. 다만, 데이터를 일렬로 나열한 후 재구성하기 때문에, 원래의 구조와 다른 형태로 데이터를 참조할 때 주의가 필요하다.
Squeeze와 Unsqueeze의 차원 조작
Squeeze와 Unsqueeze는 주로 딥러닝 모델의 출력 결과를 해석할 때 유용하다. 예를 들어, 모델의 출력을 처리할 때 필요 없는 차원을 제거하거나(예: Squeeze), 특정 연산을 수행하기 위해 차원을 추가해야 할 때(예: Unsqueeze) 사용된다.
Squeeze의 경우, 크기가 1인 차원만 제거할 수 있기 때문에, 전체 텐서의 크기를 바꾸는 데 한계가 있다. Unsqueeze는 특정 위치에 차원을 추가할 수 있어, 추가된 차원을 기준으로 다른 연산을 수행하기 용이하다.
예시: 이미지 데이터 처리
이미지 데이터의 경우, 일반적으로 크기가 ((Height, Width, Channels)) 형식으로 구성된다. 이 데이터를 딥러닝 모델에 입력하기 위해 배치 차원을 추가할 때, Unsqueeze 연산이 필요하다. 예를 들어, 단일 이미지를 모델에 입력할 때는 크기를 ((1, Height, Width, Channels))로 변환해야 한다.
또한, 모델의 최종 출력이 ((1, 1))과 같은 형태일 때, Squeeze를 사용하여 ((1,))로 차원을 줄일 수 있다.
이와 같이, Squeeze와 Unsqueeze는 데이터의 형태를 유연하게 조작하여, 모델 학습 및 추론 과정에서 텐서 조작을 단순화할 수 있다.
Reshape, Squeeze, Unsqueeze의 비교 및 차이점
Reshape, Squeeze, Unsqueeze 연산은 모두 텐서의 차원 구조를 변경하는 데 사용되지만, 각각의 역할과 적용 방식이 다르다. 이들을 비교해보면 다음과 같은 차이점을 확인할 수 있다.
Reshape
텐서의 크기를 원하는 형태로 변경합니다. 단, 원소의 개수가 동일해야 합니다.
텐서의 원소 개수는 그대로 유지되고, 변경 전후의 데이터 메모리 위치는 영향을 받지 않습니다. 원소 개수에 맞게만 자유롭게 조작 가능.
Squeeze
크기가 1인 차원을 제거합니다.
불필요한 차원을 줄여 데이터를 간소화합니다. 단, 크기가 1이 아닌 차원은 제거되지 않습니다.
Unsqueeze
지정한 위치에 크기가 1인 차원을 추가합니다.
특정 연산을 위해 차원을 추가하여 데이터의 구조를 조작합니다. 차원의 순서와 위치를 지정할 수 있어 유연한 데이터 변환이 가능합니다.
Reshape 연산의 유용성: 데이터 정규화 및 배치 처리
Reshape 연산은 데이터 전처리 과정에서 특히 유용합니다. 예를 들어, 대량의 이미지 데이터를 다룰 때, 각 이미지를 일렬로 변환하여 신경망의 입력으로 사용할 수 있습니다. 이를 벡터화(vectorization)이라고 하며, 데이터셋의 모든 이미지가 동일한 크기라면 간편하게 처리할 수 있습니다.
수학적으로 설명하면, 이미지 데이터가 ((28, 28)) 크기의 행렬 형태로 주어진다고 할 때, 각 이미지를 벡터 (\mathbf{x}_i \in \mathbb{R}^{784})로 변환할 수 있습니다. 이는 다음과 같이 표현할 수 있습니다.
[ \mathbf{X} = \begin{bmatrix} \mathbf{x}_1 \ \mathbf{x}_2 \ \vdots \ \mathbf{x}_N \end{bmatrix}, \quad \mathbf{x}_i \in \mathbb{R}^{784} ]
여기서 (\mathbf{X})는 (N)개의 이미지 벡터가 쌓인 형태로, Reshape 연산을 통해 각 이미지를 벡터로 변환하여 신경망의 입력으로 사용할 수 있게 합니다.
코드 예시:
Squeeze와 Unsqueeze의 유용성: 차원 정렬 및 유지
특히 Squeeze와 Unsqueeze는 딥러닝 모델의 출력 형태를 맞출 때 자주 사용된다. 예를 들어, 모델의 출력이 예측 결과 ((batch_size, 1)) 형태로 나타나고, 특정 연산을 위해 ((batch_size,))로 줄여야 하는 경우 Squeeze를 사용할 수 있다.
마찬가지로, 모델의 입력에 추가적인 배치 차원을 넣기 위해 Unsqueeze를 사용하여 차원을 확장할 수 있다. 이는 다양한 신경망 연산에서 차원의 일치를 강제하거나, 데이터의 구성을 유연하게 조정하는 데 필수적이다.
이처럼, 텐서의 차원 조작은 모델 구조의 요구사항을 맞추고, 다양한 연산을 효율적으로 수행하는 데 중요한 역할을 한다.
Last updated