티스토리 뷰

1. Autograd & Variable

Autograd는 자동 미분을 수행하는 torch의 핵심 패키지로, 자동 미분을 위해 테잎(tape) 기반 시스템을 사용합니다.

순전파(foward) 단계에서 autograd 테잎은 수행하는 모든 연산을 기억합니다. 그리고, 역전파(backward) 단계에서 

연산들을 재생(replay)합니다.

Autograd를 사용하면 backprop을 위한 미분 값을 자동으로 계산해줍니다.

자동 계산위해서는 사용하는 변수는 torch.autograd에 있는 Variable이라는 것을 사용해야합니다.


Variable 모습을 구현하면 다음과 같습니다.


import torch

from torch.autograd import Variable

a = torch.rand(5)

a = Variable(a)

[코드 1]


Variable은 data, grad, grad_fn 3가지 형태로 이루어집니다.


data는 a의 tensor 형태의 데이터가 담기고 위 소스 코드상의 a = torch.rand(5)에 해당합니다.


grad는 data가 거쳐온 layer에 대한 미분값이 축적되는 것


grad_fn는 미분값을 계산한 함수에 대한 정보


아래 [코드 2]를 보며 상세히 보겠습니다.

import torch

from torch.autograd import Variable

a = torch.ones(2,2)

print(a)


#옆에 requires_grad=True는 a값이 필요하다라는 것 

#위의 tensor를 생성했는데 연산을 추적하기 위해 requires_grad=True 설정

a = Variable(a, requires_grad=True)

print(a)


print("---a.data---")

print(a.data)

#아무런 연산을 진행하지 않아서 None

print("---a.grad---")

print(a.grad)

print("---a.grad_fn---")

print(a.grad_fn)


#+연산

b = a+2

print(b)


#b의 제곱 연산

c = b ** 2

print(c)


out = c.sum()

print(out)


out.backward()

print(a.grad)


결과값

---a.data---

tensor([[1., 1.],

        [1., 1.]])

---a.grad---

None

---a.grad_fn---

None

[코드 2]


마지막의 backward 함수의 의미는

지금까지 a -> b -> c -> out를 만들었습니다.


a를 구하려면 아래의 식을 사용해야 합니다.

즉, 역전파(backprop)를 하고 변화도 를 아래 식으로 해서 출력합니다.



위의 미분 된 값이 담기는 장소가 a.grad 인데 위의 코드에서 a.grad는 None입니다.

None 부분을 채워줄때 사용하는 함수가 out.backward() 함수입니다.



#out.backward() 수행 

print("---a.data---")

print(a.data)

print("---a.grad---")

print(a.grad)

print("---a.grad_fn---")

print(a.grad_fn)


---a.data---

tensor([[1., 1.],

        [1., 1.]])

---a.grad---

tensor([[6., 6.],

        [6., 6.]])

---a.grad_fn---

None

[코드 3]

[코드 3]을 보면 out.backward() 수행하되어서 a.grad의 값이 채워지게 됩니다.

또한a.grad_fn는 여전히 None인데 None인 이유는 a가 직접적으로 수행한 연산이 없기때문에 None입니다.



print("---b.data---")

print(b.data)

print("---b.grad---")

print(b.grad)

print("---b.grad_fn---")

print(b.grad_fn)


---b.data---

tensor([[3., 3.],

        [3., 3.]])

---b.grad---

None

---b.grad_fn---

<AddBackward0 object at 0x0000000F070BA550>

[코드 4]

[코드 4] 식은 a+2를 수행해서 b.grad_fn이 값이 있는것이고 AddBackward0의 의미는 b = a+ 2 연산을 했으니 이런내용이 담겨져있다라고 보면 됩니다.


print("---c.data---")

print(c.data)

print("---c.grad---")

print(c.grad)

print("---c.grad_fn---")

print(c.grad_fn)


---c.data---

tensor([[9., 9.],

        [9., 9.]])

---c.grad---

None

---c.grad_fn---

<PowBackward0 object at 0x0000000F070BA4E0>

[코드 5]

[코드 5] c의 대한 내용을 보면 c = b ** 2 이었는데 이 부분이 Pow 연산을 해서 PowBackward0라고 되어있습니다.


print("---out.data---")

print(out.data)

print("---out.grad---")

print(out.grad)

print("---out.grad_fn---")

print(out.grad_fn)


---out.data---

tensor(36.)

---out.grad---

None

---out.grad_fn---

<SumBackward0 object at 0x0000000F070BA160>

[코드 6]

[코드 6]의 out 연산을 보면 out = c.sum() 이어서 Sum에대한 백워드 진행했으니 SumBackward0 담겨져 있습니다.


import torch

from torch.autograd import Variable

x = torch.ones(3)

x = Variable(x, requires_grad = True)

y = (x ** 2)

z = y * 3

print(z)


grad = torch.Tensor([0.1, 1, 10])

z.backward(grad)



print("---x.data---")

print(x.data)

print("---x.grad---")

print(x.grad)

print("---x.grad_fn---")

print(x.grad_fn)


tensor([3., 3., 3.], grad_fn=<MulBackward0>)

---a.data---

tensor([1., 1., 1.])

---a.grad---

tensor([ 0.6000,  6.0000, 60.0000])

---a.grad_fn---

None

[코드 7]


[코드 7]에서 z = 3 * x*2 이니 아래 식으로 나타낼 수 있습니다.

x = 1이니깐 편미분 한 값은 6이 되는것이죠


그렇다면 backword 된 값이 6이어야 되는데 값이 다 틀립니다.

이유는 Tensor를 backword 하는 것에 넣어주면 backword 되는 값에 grad 부분이 곱해져서 채워지게 됩니다.



참고한 유튜브

https://www.youtube.com/watch?v=E0R9Xf_GyUc&t=207s

'딥러닝 > PyTorch' 카테고리의 다른 글

PyTorch - 01. 사용법 및 설명  (0) 2019.02.07
댓글
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31