PyTorch의 기본 개념: Tensor, Autograd, Module
Tensor
PyTorch에서 가장 기본이 되는 데이터 구조는 텐서(Tensor)이다. 텐서는 수학에서의 다차원 배열을 의미하며, 이는 스칼라(0차원), 벡터(1차원), 행렬(2차원), 그리고 그 이상의 고차원 배열을 포함한다. 일반적으로 딥러닝 모델에서는 학습 데이터와 파라미터를 텐서로 표현하여 모델의 학습 및 추론을 수행한다.
텐서의 정의
수학적으로, 텐서는 $n$차원 배열로 정의할 수 있다. 예를 들어, $n=0$이면 스칼라, $n=1$이면 벡터, $n=2$이면 행렬이다. 이를 일반화하면 다음과 같이 표현할 수 있다.
스칼라: $x \in \mathbb{R}$
벡터: $\mathbf{x} \in \mathbb{R}^{n}$
행렬: $\mathbf{X} \in \mathbb{R}^{m \times n}$
3차원 이상의 텐서: $\mathbf{T} \in \mathbb{R}^{d_1 \times d_2 \times \cdots \times d_n}$
텐서 연산
PyTorch에서는 다양한 텐서 연산을 지원한다. 이러한 연산은 텐서의 기본적인 사칙연산에서부터 행렬 곱셈, 텐서 결합, 차원 변경 등 고급 연산을 포함한다. 예를 들어, 두 개의 벡터 $\mathbf{a}$, $\mathbf{b}$의 내적은 다음과 같이 표현할 수 있다.
[ \mathbf{a} \cdot \mathbf{b} = \sum_{i=1}^{n} a_i b_i ]
행렬 곱셈도 지원하며, 두 행렬 $\mathbf{A} \in \mathbb{R}^{m \times n}$, $\mathbf{B} \in \mathbb{R}^{n \times p}$에 대해 다음과 같이 정의된다.
[ \mathbf{C} = \mathbf{A} \mathbf{B}, \quad \mathbf{C} \in \mathbb{R}^{m \times p} ]
PyTorch에서는 이러한 연산이 직관적으로 구현 가능하며, GPU 가속을 통해 빠르게 수행할 수 있다.
텐서의 GPU 지원
PyTorch의 텐서는 CPU뿐만 아니라 GPU에서도 연산을 수행할 수 있다. torch.Tensor 객체를 .to(device) 메서드를 사용해 GPU로 전송하면, 대부분의 연산은 GPU에서 수행되며 이는 학습 속도를 크게 향상시킨다. 예를 들어, 텐서를 GPU로 이동시키는 코드는 다음과 같다.
Autograd
딥러닝에서 중요한 개념은 모델 학습 시의 자동 미분(Automatic Differentiation) 기능이다. PyTorch는 이를 위해 autograd 모듈을 제공한다. 이는 텐서의 연산을 기록하고, 연산 그래프를 생성하여 역전파(Backpropagation) 시 자동으로 미분값을 계산할 수 있도록 한다.
연산 그래프
딥러닝 모델의 학습은 보통 손실 함수의 미분을 구하고, 이 값을 통해 모델의 파라미터를 업데이트하는 방식으로 이루어진다. PyTorch의 autograd는 이를 위해 **동적 연산 그래프(Dynamic Computational Graph)**를 사용한다. 이 그래프는 연산이 수행될 때마다 생성되며, 이후 역전파를 통해 자동으로 미분이 계산된다.
수학적으로, 파라미터 $\theta$에 대한 손실 함수 $L(\theta)$의 기울기를 구하는 과정은 다음과 같다.
[ \frac{\partial L}{\partial \theta} ]
PyTorch는 이 과정을 자동으로 처리해주므로, 사용자는 직접 미분식을 계산할 필요가 없다. 예를 들어, 다음 코드는 손실 함수에 대한 파라미터의 미분값을 계산하는 방법을 보여준다.
이 코드에서 x는 requires_grad=True로 설정되었기 때문에, 이 변수로부터 생성되는 모든 연산은 그래프에 기록되며, y.backward()를 호출하면 $\frac{\partial y}{\partial x}$ 값이 자동으로 계산되어 x.grad에 저장된다.
Autograd의 기본 개념
PyTorch의 autograd는 텐서에 대해 자동으로 기울기(Gradient)를 계산하는 기능이다. 이 기능은 텐서가 생성될 때 requires_grad=True로 설정되면 활성화된다. requires_grad=True로 설정된 텐서는 모든 연산이 추적되며, 연산 그래프가 생성된다. 이후, 역전파(backward()) 메서드를 호출하면 연산 그래프를 따라 자동으로 기울기가 계산된다.
연산 그래프의 동작 원리
연산 그래프는 **그래디언트 전파(Gradient Propagation)**를 위해 만들어진다. 예를 들어, 다음과 같은 수식이 있을 때:
[ z = f(x, y) = x^2 + 2xy + y^2 ]
이 수식의 $x$와 $y$에 대한 기울기(편미분)를 계산해야 한다면, 다음과 같이 파라미터의 미분값을 구할 수 있다.
[ \frac{\partial z}{\partial x} = 2x + 2y, \quad \frac{\partial z}{\partial y} = 2x + 2y ]
이 연산은 역전파 과정에서 수행되며, PyTorch는 이를 자동으로 처리한다. 더 복잡한 다층 신경망에서도 autograd는 연산 그래프를 통해 각 레이어의 기울기를 계산하고, 이를 기반으로 학습 파라미터를 업데이트한다.
Module
딥러닝 모델의 구축에 있어 핵심적인 개념 중 하나는 **모듈(Module)**이다. 모듈은 모델의 레이어(Layer)와 같은 구성 요소로 생각할 수 있으며, 신경망에서 자주 사용되는 기본 연산 및 레이어를 정의하고 구성하는 데 사용된다. PyTorch에서는 torch.nn.Module 클래스를 상속하여 사용자 정의 모듈을 만들 수 있다.
Module의 정의
torch.nn.Module은 PyTorch에서 모든 네트워크 레이어와 모델의 기반이 되는 클래스이다. 사용자가 새로운 네트워크를 정의하고 싶다면, 이 클래스를 상속받아 새로운 클래스 내에서 모델의 구조를 정의하면 된다. 예를 들어, 단순한 다층 퍼셉트론(Multi-Layer Perceptron, MLP)은 다음과 같이 정의할 수 있다.
이 코드에서 SimpleMLP 클래스는 torch.nn.Module을 상속받아, 두 개의 선형 레이어를 포함하는 신경망을 정의한다. forward 메서드는 입력 데이터를 받아 네트워크의 출력을 계산하는 역할을 한다.
모듈의 재귀적 특성
PyTorch의 모듈은 재귀적으로 구성될 수 있다. 이는 큰 네트워크를 여러 개의 작은 모듈로 나누어 정의할 수 있게 해준다. 예를 들어, 각 레이어가 하나의 모듈로 정의된 더 큰 네트워크는 여러 모듈을 합쳐서 구성할 수 있다. 이를 통해 코드의 재사용성과 유지보수성을 높일 수 있다.
매개변수 관리
모듈은 내부에 정의된 모든 파라미터(Weights, Bias 등)를 자동으로 관리한다. 각 레이어의 파라미터는 parameters() 메서드를 통해 접근할 수 있으며, 학습 과정에서 이러한 파라미터들은 업데이트된다. 예를 들어, 모든 파라미터를 확인하고자 할 때는 다음과 같이 사용할 수 있다.
이를 통해 신경망의 파라미터를 쉽게 조작하거나 초기화할 수 있다.
Module의 매개변수 초기화
딥러닝 모델의 성능은 초기 파라미터 값에 큰 영향을 받을 수 있다. PyTorch에서는 torch.nn.init 모듈을 통해 다양한 초기화 방법을 제공한다. 모델의 각 레이어에 대해 직접 초기화를 수행하거나, 기본 초기화를 사용할 수도 있다. 예를 들어, 가중치를 정규분포로 초기화하려면 다음과 같은 방법을 사용할 수 있다.
이 코드에서는 layer1의 가중치는 평균 0, 표준편차 0.01인 정규분포에서 샘플링된 값으로 초기화되었고, layer2의 가중치는 Xavier Uniform 초기화 방법을 사용했다. 이처럼 다양한 초기화 방법을 사용하여 모델의 학습 성능을 높일 수 있다.
PyTorch의 모듈 간 상호작용
모델을 구축할 때, 여러 모듈이 상호작용하여 최종 출력을 생성한다. 이러한 상호작용은 PyTorch의 forward 메서드를 통해 정의되며, 모든 모듈은 입력 텐서를 받아 일련의 연산을 수행한 후 결과를 반환한다. 이 과정은 직관적이며, 신경망 구조를 간결하게 표현할 수 있도록 도와준다.
예를 들어, CNN 모델을 구성할 때는 여러 nn.Conv2d, nn.ReLU, nn.MaxPool2d와 같은 모듈이 연속적으로 연결되며, 모델의 forward 메서드에서 이들 모듈을 결합하여 데이터의 전처리 및 특징 추출을 수행한다.
Module의 장점
코드 재사용성
PyTorch의 모듈을 사용하면 복잡한 모델을 여러 개의 작은 단위로 나눌 수 있으므로 코드 재사용성이 높아진다. 이는 다양한 실험에서 빠르게 모델을 수정하고, 새로운 네트워크 아키텍처를 시도할 때 매우 유용하다.
확장성과 유연성
PyTorch의 모듈 시스템은 매우 유연하며, 새로운 연산이나 레이어를 손쉽게 추가할 수 있다. 예를 들어, 표준 레이어 외에도 사용자 정의 레이어를 만들고, 이를 기존 모델과 결합하여 복잡한 네트워크를 설계할 수 있다.
동적 계산 그래프
PyTorch는 동적 계산 그래프(Define-by-Run)를 사용하므로, 연산이 실행될 때 그래프가 동적으로 생성된다. 이로 인해 연산의 순서를 유연하게 변경할 수 있으며, RNN이나 트리 구조와 같은 복잡한 네트워크를 손쉽게 구현할 수 있다. 이러한 동적 특성은 모델의 디버깅을 용이하게 해주고, 다양한 데이터 형태에 대해 더 나은 처리를 가능하게 한다.
텐서와 모듈의 조합: 연산 흐름의 이해
딥러닝 모델의 학습 과정은 기본적으로 아래와 같은 단계로 이루어진다.
데이터 준비: 입력 데이터는 텐서 형태로 준비되며, GPU로 전송된다.
모델 정의: 사용자가 정의한 모듈이 입력 데이터를 받아 일련의 연산을 수행한다.
손실 계산: 모델의 출력과 실제 값을 비교하여 손실 함수를 통해 오차를 계산한다.
역전파(Backpropagation):
autograd를 사용해 손실 함수에 대한 파라미터의 기울기를 계산한다.파라미터 업데이트: 옵티마이저를 통해 모델의 파라미터를 업데이트한다.
이 과정을 반복하면서 모델은 입력 데이터에 적합한 파라미터를 학습하게 된다. PyTorch는 이 모든 과정을 단순화하고, 코드로 구현하기 쉽게 설계되어 있어 학습 과정의 이해와 조작이 용이하다.
Last updated