[neural-network] Pytorch, 그래디언트 인수는 무엇입니까

나는 PyTorch의 문서를 읽고 있고 그들이 쓰는 예제를 찾았습니다.

gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(x.grad)

여기서 x는 y가 생성 된 초기 변수입니다 (3- 벡터). 문제는 그래디언트 텐서의 0.1, 1.0 및 0.0001 인수는 무엇입니까? 문서는 그것에 대해 명확하지 않습니다.



답변

PyTorch 웹 사이트에서 더 이상 찾지 못한 원래 코드.

gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(x.grad)

위 코드의 문제는 그라디언트를 계산할 기능이 없습니다. 이것은 우리가 얼마나 많은 매개 변수 (함수가 취하는 인자)와 매개 변수의 차원을 모른다는 것을 의미합니다.

이것을 완전히 이해하기 위해 원본에 가까운 예제를 만들었습니다.

예 1 :

a = torch.tensor([1.0, 2.0, 3.0], requires_grad = True)
b = torch.tensor([3.0, 4.0, 5.0], requires_grad = True)
c = torch.tensor([6.0, 7.0, 8.0], requires_grad = True)

y=3*a + 2*b*b + torch.log(c)
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients,retain_graph=True)

print(a.grad) # tensor([3.0000e-01, 3.0000e+00, 3.0000e-04])
print(b.grad) # tensor([1.2000e+00, 1.6000e+01, 2.0000e-03])
print(c.grad) # tensor([1.6667e-02, 1.4286e-01, 1.2500e-05])

나는 우리의 함수를 다음 y=3*a + 2*b*b + torch.log(c)과 같이 가정 했고 매개 변수는 내부에 3 개의 요소가있는 텐서입니다.

gradients = torch.FloatTensor([0.1, 1.0, 0.0001])이것이 누산기 라고 생각할 수 있습니다 .

PyTorch autograd 시스템 계산은 Jacobian 곱과 동일합니다.

야 코비안

우리가 한 것처럼 함수가있는 경우 :

y=3*a + 2*b*b + torch.log(c)

Jacobian은 [3, 4*b, 1/c]. 그러나이 Jacobian 은 PyTorch가 특정 지점에서 그라디언트를 계산하는 방식이 아닙니다.

PyTorch는 순방향 패스 및 역방향 모드 자동 미분 (AD)을 함께 사용합니다.

관련된 상징적 수학과 수치 적 미분이 없습니다.

수치 차별화 계산하는 것입니다 δy/δb위해, b=1그리고 b=1+εε 작은입니다.

에서 그라디언트를 사용하지 않는 경우 y.backward():

예 2

a = torch.tensor(0.1, requires_grad = True)
b = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(0.1, requires_grad = True)
y=3*a + 2*b*b + torch.log(c)

y.backward()

print(a.grad) # tensor(3.)
print(b.grad) # tensor(4.)
print(c.grad) # tensor(10.)

당신은 간단하게 당신이 당신의 설정 방법에 따라, 지점에서 결과를 얻을 것이다 a, b, c처음 텐서를.

당신이 당신의 초기화 방법 조심 a, b, c:

예 3 :

a = torch.empty(1, requires_grad = True, pin_memory=True)
b = torch.empty(1, requires_grad = True, pin_memory=True)
c = torch.empty(1, requires_grad = True, pin_memory=True)

y=3*a + 2*b*b + torch.log(c)

gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)

print(a.grad) # tensor([3.3003])
print(b.grad) # tensor([0.])
print(c.grad) # tensor([inf])

사용 torch.empty()하고 사용 하지 않으면 pin_memory=True매번 다른 결과가 나타날 수 있습니다.

또한 음표 그래디언트는 누산기와 같으므로 필요할 때 0으로 만듭니다.

예 4 :

a = torch.tensor(1.0, requires_grad = True)
b = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(1.0, requires_grad = True)
y=3*a + 2*b*b + torch.log(c)

y.backward(retain_graph=True)
y.backward()

print(a.grad) # tensor(6.)
print(b.grad) # tensor(8.)
print(c.grad) # tensor(2.)

마지막으로 PyTorch가 사용하는 용어에 대한 몇 가지 팁 :

PyTorch 는 순방향 패스에서 기울기를 계산할 때 동적 계산 그래프를 생성합니다 . 이것은 나무처럼 보입니다.

따라서이 나무 의 입력 텐서 이고 루트출력 텐서 라는 소리를 자주 듣게 될 것 입니다.

그라디언트는 루트에서 잎까지 그래프를 추적하고 체인 규칙을 사용하는 방식으로 모든 그라디언트를 곱하여 계산됩니다 . 이 곱셈은 역방향 패스에서 발생합니다.


답변

설명

신경망의 경우 일반적으로 loss네트워크가 입력 이미지 (또는 기타 작업)를 분류하는 방법을 얼마나 잘 학습했는지 평가하는 데 사용 합니다. 이 loss용어는 일반적으로 스칼라 값입니다. 네트워크의 매개 변수를 업데이트하려면 loss실제로 leaf node계산 그래프에있는 매개 변수에 대한 wrt 의 기울기를 계산해야합니다 (그런데 이러한 매개 변수는 대부분 Convolution, Linear 및 곧).

체인 규칙에 따르면, losswrt의 잎 노드에 대한 기울기를 계산하기 위해 , 우리는 loss어떤 중간 변수에 대한 wrt의 도함수 와 잎 변수에 대한 중간 변수 wrt의 기울기를 계산 하고 내적을 수행하고이 모든 것을 합산 할 수 있습니다.

의 메서드 의 gradient인수 리프 변수 wrt 변수의 각 요소에 대한 가중 합계계산하는 데 사용됩니다 . 이 가중치는 중간 변수의 각 요소에 대한 최종 wrt 의 파생물 일뿐 입니다.Variablebackward()loss

구체적인 예

이것을 이해하기 위해 구체적이고 간단한 예를 들어 봅시다.

from torch.autograd import Variable
import torch
x = Variable(torch.FloatTensor([[1, 2, 3, 4]]), requires_grad=True)
z = 2*x
loss = z.sum(dim=1)

# do backward for first element of z
z.backward(torch.FloatTensor([[1, 0, 0, 0]]), retain_graph=True)
print(x.grad.data)
x.grad.data.zero_() #remove gradient in x.grad, or it will be accumulated

# do backward for second element of z
z.backward(torch.FloatTensor([[0, 1, 0, 0]]), retain_graph=True)
print(x.grad.data)
x.grad.data.zero_()

# do backward for all elements of z, with weight equal to the derivative of
# loss w.r.t z_1, z_2, z_3 and z_4
z.backward(torch.FloatTensor([[1, 1, 1, 1]]), retain_graph=True)
print(x.grad.data)
x.grad.data.zero_()

# or we can directly backprop using loss
loss.backward() # equivalent to loss.backward(torch.FloatTensor([1.0]))
print(x.grad.data)    

위의 예에서 first의 결과 print는 다음과 같습니다.

2 0 0 0
[torch.FloatTensor of size 1×4]

이것은 정확히 z_1 wrt를 x로 미분 한 것입니다.

두 번째 결과 print는 다음과 같습니다.

0 2 0 0
[torch.FloatTensor of size 1×4]

이것은 z_2 wrt에서 x 로의 미분입니다.

이제 [1, 1, 1, 1]의 가중치를 사용하여 z wrt와 x의 미분을 계산하면 결과는 1*dz_1/dx + 1*dz_2/dx + 1*dz_3/dx + 1*dz_4/dx입니다. 따라서 3rd의 출력 print은 다음과 같습니다.

2 2 2 2
[torch.FloatTensor of size 1×4]

가중치 벡터 [1, 1, 1, 1]는 losswrt에서 z_1, z_2, z_3 및 z_4 로 정확히 파생된다는 점에 유의해야합니다 . losswrt 의 도함수 x는 다음과 같이 계산됩니다.

d(loss)/dx = d(loss)/dz_1 * dz_1/dx + d(loss)/dz_2 * dz_2/dx + d(loss)/dz_3 * dz_3/dx + d(loss)/dz_4 * dz_4/dx

따라서 4th의 출력은 print3rd와 동일합니다 print.

2 2 2 2
[torch.FloatTensor of size 1×4]


답변

일반적으로 계산 그래프에는 다음과 같은 스칼라 출력이 하나 loss있습니다. 그런 다음 loss가중치 ( w)에 의해 wrt의 기울기를 계산할 수 있습니다 loss.backward(). 의 기본 인수는 backward()입니다 1.0.

출력에 여러 값이있는 경우 (예 loss=[loss1, loss2, loss3]🙂 가중치에 대한 손실의 기울기를 loss.backward(torch.FloatTensor([1.0, 1.0, 1.0])).

또한 다른 손실에 가중치 또는 중요도를 추가하려면을 사용할 수 있습니다 loss.backward(torch.FloatTensor([-0.1, 1.0, 0.0001])).

이것은 -0.1*d(loss1)/dw, d(loss2)/dw, 0.0001*d(loss3)/dw동시에 계산 하는 것을 의미합니다 .


답변

여기서 forward ()의 출력, 즉 y는 3- 벡터입니다.

세 가지 값은 네트워크 출력의 기울기입니다. 일반적으로 y가 최종 출력 인 경우 1.0으로 설정되지만 특히 y가 더 큰 네트워크의 일부인 경우 다른 값도 가질 수 있습니다.

예를 들어. x가 입력이면 y = [y1, y2, y3]은 최종 출력 z를 계산하는 데 사용되는 중간 출력입니다.

그때,

dz/dx = dz/dy1 * dy1/dx + dz/dy2 * dy2/dx + dz/dy3 * dy3/dx

그래서 여기에서 거꾸로 할 세 가지 값은

[dz/dy1, dz/dy2, dz/dy3]

그런 다음 backward ()은 dz / dx를 계산합니다.


답변