"""
attribute = 속성. class의 맴버함수 but ()이 필요 없음
<tensor class>
1. .requires_grad : 이 attribute를 True 로 설정하면, 그 tensor에서 이뤄진 모든 연산들을 추적(track)하기 시작
2. .backward() : 호출하여 모든 변화도(gradient)를 자동으로 계산
3. .grad 속성: 이 Tensor의 변화도가 누적됨.
4. .detach() : Tensor가 기록을 추적하는 것을 중단하게 하려면
5. with torch.no_grad(): gradient는 필요없고, 메모리는 절약하고 싶고, 학습가능한 매개변수로 찾고 싶을때.
<Function class>
부호화(encode)하여 순환하지 않는 그래프(acyclic graph)를 생성
1. .grad_fn : Tensor 를 생성한 Function 을 참조
"""pass
x=torch.ones(2,2,requires_grad=True)y=x+4print(y)# AddBackward0 : track all operations
print(y.grad_fn)# 사용자가 마지막으로 이 변수를 만들 때 사용하는 Function을 참조한다. (기억해 놓는다.)
tensor([[5., 5.],
[5., 5.]], grad_fn=<AddBackward0>)
<AddBackward0 object at 0x000001B1F842D2C8>
# tensor에서 * / 는 행렬의 곱이 아니라, 같은 위치 원소의 연산이다.
k=torch.tensor([[1,2],[3,4]],requires_grad=True,dtype=torch.double)print(k*k)
x1=torch.ones(2,2,requires_grad=True)x2=x1+3x3=3*(x2**2)out=torch.mean(x3)# 1/4 처리가 된다. 4개 원소 평균이므로
# ()에 아무것도 넣지 않으면, torch.tensor(1.). 이 값이 Backpropa의 가장 첫번째 upstream gradient이다.
# 그래서 out이 스칼라여야 하는 것이다. mean을 안하고 x3 = out으로 하고 backward하면, 계산 불가.
out.backward()# d_out/d_x1 = 3*2/4 ... = 3/2(x+3)|x = 1 = [[6,6],[6,6]]
print(x1.grad)# x1.grad는 # d_<backward한것> / d_<.grad 한것> 의 값이 나온다.
# 생각해보면 d_Loss/d_x1를 이용해 x1을 갱신해야하므로, x1과 똑같은 size의 tensor가 print된다
''' 위에꺼 주석하고 이것도 해보기.
x3.backward(torch.tensor([[1,1],[1,1]],dtype=torch.double)) # d_out/d_x1 = 3*2/4 ... = 3/2(x+3)|x = 1 = [[6,6],[6,6]]
print(x1.grad) # 생각해보면 d_Loss/d_x1를 이용해 x1을 갱신해야하므로, x1과 똑같은 size의 tensor가 print된다
'''pass
tensor([[6., 6.],
[6., 6.]])
# 이 with 내부에 작성한 모든 연산들은 gradient tracking을 하지 않는다.
withtorch.no_grad():print((x1**2).requires_grad)
False
# .detach() 를 호출하여 내용물(content)은 같지만 require_grad가 다른 새로운 Tensor를 가져옵니다
print(x3.requires_grad)y3=x3.detach()print(y3.requires_grad)print(x3.eq(y3).all())# https://pytorch.org/docs/stable/tensors.html#torch.BoolTensor