TORCH.AUTOGRAD 를 사용한 자동 미분
- 신경망 학습 시 가장 자주 사용되는 "역전파"라는 알고리즘에서, 매개변수(모델 가중치)는 주어진 매개변수에 대한 손실 함수의 변화도(gradient)에 따라 조정된다.
- 여기서 변화도(gradient)를 계산하기 위해 PyTorch에는 torch.autograd 라는 자동 미분 엔진이 내장되어 있다.
- 이로써, 모든 계산 그래프에 대한 변화도의 자동 계산을 지원한다.
- 입력 x, 매개변수 w와 b, 그리고 일부 손실 함수가 있는 가장 간단한 단일 계층 신경망을 가정할 때, PyTorch에서는 다음과 같이 정의할 수 있다.
import torch
x = torch.ones(5) # input tensor
y = torch.zeros(3) # expected output
w = torch.randn(5, 3, requires_grad=True)
b = torch.randn(3, requires_grad=True)
z = torch.matmul(x, w)+b
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, y)
print("X:", x)
print("y:", y)
print("w:", w)
print("b:", b)
print("z:", z)
print("loss:", loss)
Out:
X: tensor([1., 1., 1., 1., 1.])
y: tensor([0., 0., 0.])
w: tensor([[ 0.1081, -1.0940, 0.3583],
[ 0.6131, -0.3263, 1.6309],
[ 0.2312, 1.1370, -0.9083],
[-0.0188, 1.3566, 1.5132],
[-1.8813, -0.1044, -1.2451]], requires_grad=True)
b: tensor([0.0715, 1.3322, 0.4170], requires_grad=True)
z: tensor([-0.8761, 2.3011, 1.7661], grad_fn=<AddBackward0>)
loss: tensor(1.5562, grad_fn=<BinaryCrossEntropyWithLogitsBackward0>)
Tensor, Function과 연산그래프(Computational graph)
- w와 b는 최적화를 해야 하는 매개변수이므로, 이러한 변수들에 대한 손실 함수의 변화도(gradient)를 계산할 수 있어야 한다.
- 이를 위해, 해당 텐서에 requires_grad 속성을 설정한다.
- 텐서를 생성할 때: requires_grad
- 나중에 설정할 때: x.requires_grad_(True)
- 이를 위해, 해당 텐서에 requires_grad 속성을 설정한다.
- 연산 그래프를 구성하기 위해 텐서에 적용하는 함수는 Function 클래스의 객체로, 이 객체는 순전파 방향으로 함수를 계산하는 방법과, 역방향 전파 단계에서 도함수(derivative)를 계산하는 방법을 알고 있다.
- 역전파 함수에 대한 참조(reference)는 텐서의 grad_fn 속성에 저장된다.
print(f"Gradient function for z = {z.grad_fn}")
print(f"Gradient function for loss = {loss.grad_fn}")
Out:
Gradient function for z = <AddBackward0 object at 0x783fcfad38b0>
Gradient function for loss = <BinaryCrossEntropyWithLogitsBackward0 object at 0x783fcfad3a30>
변화도(Gradient) 계산하기
- 신경망에서 매개변수의 가중치를 최적화하려면 매개변수에 대한 손실함수의 도함수(derivative)를 계산해야 한다.
- 즉, x와 y의 일부 고정값에서 와 ∂𝑙𝑜𝑠𝑠 / ∂𝑏 가 필요하다.
loss.backward()
print(w.grad)
print(b.grad)
Out:
tensor([[0.0980, 0.3030, 0.2847],
[0.0980, 0.3030, 0.2847],
[0.0980, 0.3030, 0.2847],
[0.0980, 0.3030, 0.2847],
[0.0980, 0.3030, 0.2847]])
tensor([0.0980, 0.3030, 0.2847])
- 연산 그래프의 잎(leaf) 노드들 중, requires_grad 속성이 True로 설정된 노드들의 grad 속성만 구할 수 있다.
- 성능 상 이유로, 주어진 그래프에서의 backward를 사용한 변화도 계산은 한 번만 수행할 수 있다.
- 만약, 동일한 그래프에서 여러번의 backward 호출이 필요하면, backward 호출 시 retain_graph=True를 전달해야 한다.
변화도 추적 멈추기
- 기본적으로, requires_grad=True인 모든 텐서들은 연산 기록을 추적하고 변화도 계산을 지원한다.
- 그러나, 모델을 학습한 뒤 입력 데이터를 단순히 적용하기만 하는 경우와 같이 순전파 연산만 필요한 경우에는, 추적이 불필요할 수 있다.
- 이 경우 연산 코드를 torch.no_grad() 블록으로 둘러싸서 연산 추적을 멈출 수 있다.
z = torch.matmul(x, w)+b
print(z.requires_grad)
with torch.no_grad():
z = torch.matmul(x, w)+b
print(z.requires_grad)
Out:
True
False
- 또 다른 방법은 텐서에 detach() 메소드를 사용하는 것이다.
z = torch.matmul(x, w)+b
z_det = z.detach()
print(z_det.requires_grad)
Out:
False
- 변화도 추적을 멈춰야 하는 이유?
- 신경망의 일부 매개변수를 "고정된 매개변수(frozen parameter)"로 표시한다.
- 변화도를 추적하지 않는 텐서의 연산이 더 효율적이기 때문에, 순전파 단계만 수행할 때 연산 속도가 향상된다.
선택적으로 읽기(Optional Reading): 텐서 변화도와 야코비안 곱(Jacobian Product)
- 대부분 스칼라 손실 함수를 가지고 일부 매개변수와 관련한 변화도를 계산해야 하지만, 출력 함수가 임의의 텐서인 경우
- PyTorch는 실제 변화도가 아닌 야코비안 곱을 계산한다.
https://tutorials.pytorch.kr/beginner/basics/autogradqs_tutorial.html
torch.autograd를 사용한 자동 미분
파이토치(PyTorch) 기본 익히기|| 빠른 시작|| 텐서(Tensor)|| Dataset과 Dataloader|| 변형(Transform)|| 신경망 모델 구성하기|| Autograd|| 최적화(Optimization)|| 모델 저장하고 불러오기 신경망을 학습할 때 가장
tutorials.pytorch.kr
'Deep Learning & Machine Learning > PyTorch' 카테고리의 다른 글
[인프런 데이터과학 Part3]섹션1. 딥러닝 기본 배경지식(이론) (0) | 2024.05.20 |
---|---|
[PyTorch] tutorial, 6.최적화(Optimization) (0) | 2024.05.19 |
[PyTorch] tutorial, 4.신경망 모델 구성하기 (0) | 2024.05.19 |
[PyTorch] tutorial, 3.변형(Transform) (0) | 2024.05.19 |
[PyTorch] tutorial, 2.Dataset과 DataLoader (0) | 2024.05.19 |