[PyTorch] Autograd-03 : Practice

[PyTorch] Autograd-01 : 기초사용법
[PyTorch] Autograd-02 : With Jacobian




PyTorch.Autograd

이놈의 Autograd...
DeepLearning에서 중요한 부분인 Backpropagation을 컴퓨터(PyTorch)가 어떻게 연산하는지 정확히 이해하기 위해서는 필수로 알아야되는 부분인 것 같다.
다소 어려운 부분이 많아 끙끙거리던 중 오태호님의 블로그 [PyTorch Autograd - Dable Tech Blog] 를 찾았고 해당 블로그의 글을 참고하여 해당 글을 작성하면서 PyTorch.Autograd를 보다 명확하게 이해하려고 한다.

앞서 작성한 [PyTorch] Autograd 글에서

  • Autograd의 기초적인 사용법(.requries_grad(True/False), .backward() .grad 등)
  • Loss, Loss Function, Jacobian Matrix, Jacobian Vector Product, DCG(Dynamic Computation Graph), leaf & root 개념

을 학습하였다. 밍밍한 설명들이지만 조금씩 참고하자!







01. 속성값 호출

x = torch.tensor(5.0)
y = x ** 3
z = torch.log(y)

먼저 아래와 같은 세 개의 Tensor를 생성
x=5x=5





print(x.requires_grad)
print(x.is_leaf)
print(x.grad_fn)
print(x.grad)

>>>>
False
True
None
None

각 Tensor에 대한 Autograd 기본정보를 출력 (귀찮으니 Tensor 1개만...)





03. 함수로 속성값 호출

[!] 이 함수 get_tensor_info는 쭉 사용예정!

def get_tensor_info(tensor):

	for name in ['requires_grad', 'is_leaf', 'retains_grad', 'grad_fn', 'grad']:
		info.append(f'{name} ( {getattr(tensor, name)} )')

	info.append(f'tensor({str(tensor)})')
    
    return ' '.join(info)
    
print('x', get_tensor_info(x))
print('y', get_tensor_info(y))
print('z', get_tensor_info(z))

>>>
x requires_grad(False) is_leaf(True) retains_grad(False) grad_fn(None) grad(None) tensor(tensor(5.))
y requires_grad(False) is_leaf(True) retains_grad(False) grad_fn(None) grad(None) tensor(tensor(125.))
z requires_grad(False) is_leaf(True) retains_grad(False) grad_fn(None) grad(None) tensor(tensor(4.8283))

Tensor의 (Autograd 관련) 기본정보를 출력하는 함수를 만들어서 출력
requires_gradretains_grad는 모두 False이고
is_leaf는 모두 True이다.
grad_fngrad에는 None값만이 할당되어있다.




04. requires_grad

x = torch.tensor(5.0, requires_grad=True)   #requires_grad 활성화
y = x ** 3
z = torch.log(y)

print('x', get_tensor_info(x))
print('y', get_tensor_info(y))
print('z', get_tensor_info(z))

>>>
x requires_grad(True) is_leaf(True) retains_grad(False) grad_fn(None) grad(None) tensor(tensor(5., requires_grad=True))
y requires_grad(True) is_leaf(False) retains_grad(False) grad_fn(<PowBackward0 object at 0x000001D4832934C0>) grad(None) tensor(tensor(125., grad_fn=<PowBackward0>))
z requires_grad(True) is_leaf(False) retains_grad(False) grad_fn(<LogBackward0 object at 0x000001D483293940>) grad(None) tensor(tensor(4.8283, grad_fn=<LogBackward0>))

xx
y=f(x)y=f(x)

z=g(y)=g(f(x))\therefore z=g(y)=g(f(x))

지금 x,y,zx,y,z

# x 하나만 requires_grad=True해줬는데 y,z까지 requires_grad=True됨!
x requires_grad(False) -> x requires_grad(True)
y requires_grad(False) -> y requires_grad(True)
z requires_grad(False) -> z requires_grad(True)

# is_leaf는 원래는 다 True였는데 x 제외 y,z는 False됐네. x만 '잎'이라는 거구나
x is_leaf(True) -> x is_leaf(True)
y is_leaf(True) -> y is_leaf(False)
y is_leaf(True) -> y is_leaf(False)

# 얘는 변화없음
x retains_grad(False) -> x retains_grad(False)
y retains_grad(False) -> y retains_grad(False)
z retains_grad(False) -> z retains_grad(False)

# y,z에 ~Backward라는게 생겼네
x grad_fn(None) -> x grad_fn(None)
y grad_fn(None) -> y grad_fn(<PowBackward0 object at 0x000001D4832934C0>)
z grad_fn(None) -> z grad_fn(<LogBackward0 object at 0x000001D483293940>)

# 얘도 변화없음
x grad(None) -> x grad(None)
y grad(None) -> y grad(None)
z grad(None) -> z grad(None)

Keypoint
before requires_grad=False / after requires_grad=True
[!] 연결된 Tensor들, 맨 처음 Tensor에 requires_grad=True
1. 맨처음 Tensor에 requires_grad 켜주면 연결된 Tensor도 모두 켜짐!
2. is_leaf는 기본 True로 설정되나, 맨처음 Tensor에 requires_grad가 켜지면 이후 연산되는 Tensor들은 is_leafFalse로 변함.
3. 연결된 Tensor들의 grad_fn에 Backward function이 할당됨

어느 Tensor AA의 requires_grad가 True인것의 의미는...
해당 Tensor에 대한 어떤 변수의 Gradient (?A\frac{\partial ?}{\partial A}

위 Code에서처럼 Tensor x로부터 파생된 Tensor y, Tensor z에서
x에 대한 z gradient를 즉, zx\frac{\partial z}{\partial x}

따라서 Tensor AA로부터 파생된 즉, 연산된 Tensor들도 requires_grad가 True가 된다.




05. backward()

x = torch.tensor(5.0, requires_grad=True)  # backward() 호출을 위해 requries_grad를 켜준다.
y = x ** 3
z = torch.log(y)

print('x', get_tensor_info(x))
print('y', get_tensor_info(y))
print('z', get_tensor_info(z))

z.backward()

print('x_after_backward', get_tensor_info(x))
print('y_after_backward', get_tensor_info(y))
print('z_after_backward', get_tensor_info(z))

>>>
x requires_grad(True) is_leaf(True) retains_grad(None) grad_fn(None) grad(None) tensor(tensor(5., requires_grad=True))
y requires_grad(True) is_leaf(False) retains_grad(None) grad_fn(<PowBackward0 object at 0x7f7822fe19e8>) grad(None) tensor(tensor(125., grad_fn=<PowBackward0>))
z requires_grad(True) is_leaf(False) retains_grad(None) grad_fn(<LogBackward object at 0x7f7822fe19e8>) grad(None) tensor(tensor(4.8283, grad_fn=<LogBackward>))
x_after_backward requires_grad(True) is_leaf(True) retains_grad(None) grad_fn(None) grad(0.6000000238418579) tensor(tensor(5., requires_grad=True))
y_after_backward requires_grad(True) is_leaf(False) retains_grad(None) grad_fn(<PowBackward0 object at 0x7f7822fe19e8>) grad(None) tensor(tensor(125., grad_fn=<PowBackward0>))
z_after_backward requires_grad(True) is_leaf(False) retains_grad(None) grad_fn(<LogBackward object at 0x7f7822fe19e8>) grad(None) tensor(tensor(4.8283, grad_fn=<LogBackward>))

좋은 웹페이지 즐겨찾기