예제 함수
\(n\) 개의 데이터 \(x_1,..., x_n\)이 주어졌다고 할 때, 우리는 다음의 함수 \(f\)를 정의 할 수 있다.
\[ y = f(\beta) = \frac{1}{n}\sum_{i=1}^{n}(x_i - \beta)^2 \]
위의 함수는 통계학에서는 유명한 함수인데, 왜냐하면 데이터의 평균, 즉 표본 평균이 위의 함숫값을 최소화시키는 함수이기 때문이다. 오늘은 이 함수를 통하여 파이 토치의 auto.grad 기능에 대하여 알아보고자 한다.
데이터 생성
파이토치를 불러 데이터를 생성한다.
import torch
# set seed
torch.random.manual_seed(1234)
## <torch._C.Generator object at 0x7f8146cf0910>
data = torch.rand(10) * 10
data
## tensor([0.2898, 4.0190, 2.5984, 3.6664, 0.5830, 7.0064, 0.5180, 4.6814, 6.7381,
## 3.3146])
코드에서 쓰인 함수 두 개를 알아보자.
torch.rand()
: R에서runif()
함수와 같다. Uniform 분포에서 원하는 수만큼 숫자를 뽑는다..manual_seed()
: R에서set.seed()
함수와 같다. 시뮬레이션할 때 시드를 고정하는 역할을 한다.
함수 설정
우리가 선언하고자하는 함수는 베타의 함수이고, 우리는 이 베타값에 대응하는 기울기 값 (gradient)을 알고자 한다. 파이 토치에는 기울기 값을 자동으로 계산해주는 기능이 있는데, 뉴럴 넷의 학습이 백 프랍 (backpropagation)을 이용하여 구현되기 때문에 딥러닝 라이브러리의 핵심 패키지 중 하나라고 할 수 있다.
기울기 값을 추적할 텐서를 선언할 때 requires_grad = True
옵션을 붙여줘서 선언하면 끝이다. 우리는 베타에 대한 그레이디언트를 구하고 싶으므로, 다음과 같이 선언한다.
beta = torch.rand(1, requires_grad=True)
beta
## tensor([0.7837], requires_grad=True)
베타 텐서가 기울기 추적 옵션을 달고 있어서, 이와 관련되어 생성되는 모든 텐서에 기울기 추적 옵션 grad_fn
태그가 달려서 생성된다. 다음과 같이 y
를 정의를 하면, y
에도 역시 grad_fn
이 붙어서 생성되는 것을 알 수 있다.
y = torch.mean((data - beta)**2)
y
## tensor(11.8199, grad_fn=<MeanBackward0>)
기울기 값 계산 - w/o Autograd
먼저 파이토치를 사용해서 기울기 값 계산을 하기에 앞서, 계산 결과를 구해보자. \(y\)를 \(\beta\)에 대하여 미분하면 다음과 같다.
\[ \begin{align*} f'(\beta) & =\frac{d}{d\beta}\left(\frac{1}{n}\sum_{i=1}^{n}\left(x_{i}-\beta\right)^{2}\right)\\ & =\frac{1}{n}\sum_{i=1}^{n}\frac{d}{d\beta}\left(x_{i}-\beta\right)^{2}\\ & =-\frac{1}{n}\sum_{i=1}^{n}2\left(x_{i}-\beta\right) \end{align*} \]
현재 주어진 베타값은 다음과 같다.
beta.item()
## 0.7837080359458923
따라서 우리가 구하는 정답은 다음과 같을 것이다.
answer = -torch.mean(2 * (data - beta))
answer.item()
## -5.1156110763549805
기울기값 계산 - w/ Autograd
파이 토치는 우리가 계산한 위의 과정들을 자동으로 해준다. 기울기 값 계산을 위해서 해야 할 일은 기울기 계산을 activate 해주는 함수를 실행시켜주기만 하면 된다. y
에 대한 베타의 기울기값을 구하는 것이므로, 다음과 같이 .backward()
를 이용하여 backward prop. 을 시켜준다.
y.backward()
이 함수를 실행시키면, 중간 과정에 생성된 모든 텐서에 대하여 기울기 벡터 값들을 구할 수 있다. auto grad가 구한 베타의 기울기 값이 우리가 구한 값과 동일한지 확인해보자.
beta.grad.item()
## -5.1156110763549805
Auto grad 패키지 관련 알아두어야할 함수들
기울기 자동 추적기능을 사용한다는 것은 메모리를 많이 차지한다는 이야기이다. 따라서 우리가 생각하는 변수에 대한 것에만 옵션을 붙여야 하고, 더 이상 필요가 없어지면 기능을 꺼주기도 해야 할 것이다.
.detach_()
현재 y
는 기울기 자동추적 기능이 붙어있다. 우리가 y
를 사용해서 텐서를 생성하면 그 역시 옵션이 딸려 생성이 될 테지만, y
텐서 이후부터는 추적 기능을 사용하고 싶지 않을때, .detach()
를 사용하자.
z = y ** 2
z
## tensor(139.7109, grad_fn=<PowBackward0>)
z.detach_()
## tensor(139.7109)
.requires_grad_()
자동 추적 기능이 없이 생성된 텐서에 추적 기능을 붙일 때에는. requires_grad_() 함수를 사용한다.
a = torch.randn(2, 2)
a
## tensor([[-1.2923, -0.0366],
## [-0.7331, 0.2195]])
a.requires_grad
## False
a.requires_grad_(True)
## tensor([[-1.2923, -0.0366],
## [-0.7331, 0.2195]], requires_grad=True)
a.requires_grad
## True
z = y * y * 3
out = z.mean()
z
## tensor(419.1328, grad_fn=<MulBackward0>)
out
## tensor(419.1328, grad_fn=<MeanBackward0>)
.requires_grad()
기능
a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
a
## tensor([[-5.0913, 1.3896],
## [ 5.5178, -2.8634]])
a.requires_grad
## False
a.requires_grad_(True)
## tensor([[-5.0913, 1.3896],
## [ 5.5178, -2.8634]], requires_grad=True)
a.requires_grad
## True
b = (a * a).sum()
b.grad_fn
## <SumBackward0 object at 0x7f81979ea400>
with torch.no_grad()
y
계산을 할 경우, 기울기 추적 기능이 붙어있기 때문에 메모리가 그냥 계산을 할 경우보다 더 소모된다. 지금이야 함수가 작아서 문제가 없지만, 뉴럴 넷의 크기가 큰 경우에는 문제가 달라진다. 만약 특정 코드를 실행함에 있어서 추적 기능을 떼고 계산하고 싶은 경우, with torch.no_grad()
가 유용하다.
y
## tensor(11.8199, grad_fn=<MeanBackward0>)
y**2
## tensor(139.7109, grad_fn=<PowBackward0>)
with torch.no_grad():
y**2
## tensor(139.7109)
아래는 현재 검색 가능한 파이토치 딥러닝 책 광고입니다! 파트너스 활동을 통해서 일정액의 수수료를 받을 수 있다고 하네요.ㅎㅎ 언젠가 제가 쓰는 이 블로그도 저 자리에 끼어있었으면 좋겠네요ㅎㅎ 밑에 책들은 한번 사서 읽어보고, 리뷰를 올려보도록 하겠습니다. =]
'Python' 카테고리의 다른 글
신경망과 회귀분석 비교하기 (Neural Net vs. Regression) (0) | 2020.07.22 |
---|---|
파이토치, 신경망 정의 (Custom nn Modules) (0) | 2020.07.20 |
R과 파이토치, 텐서의 변환 (Bridge) (2) | 2020.07.15 |
파이토치, 텐서 (Tensor) 의 연산 (0) | 2020.07.15 |
파이토치, 텐서 (Tensor) 만들기 (0) | 2020.07.15 |
댓글