이상한 파이토치2: 함수를 미분해보자!

ddang ddang ball·2022년 9월 16일
0

파이토치

목록 보기
2/6
post-thumbnail

Physics Informed Neural Network를 보다가 한가지 의문이 들었다.

Physics Informed Neural Network란 공학과 편미분 방정식과 초기조건, 경계조건이 주어졌을 때 인공신경망을 활용하여 이 편미분 방정식을 풀려는 접근법이다.

파이토치를 공부해본 사람들은 알겠지만
loss.backward()로 loss가 미분이 되서 오차역전파가 되는 것을 간접적으로나마 알 수 있을 것이다.

한가지 의문이 들었다.

파이토치로 어떤 식을 직접적으로 미분하라고 하면 할 수있는가?

어떤식이 주어졌다고 가정하자!

단순 x^2 +1이다.
이걸 x에 대해 미분하면 2x가 나온다.

어떻게 하면 좋을까?
이때 사용하는 것이

torch.autograd.grad()

이다!!

한번 사용해보자!
입력은 [1, 2, 3, 4]로 구성되어있는 어떤 텐서라고 생각하자.

x = torch.tensor([1, 2, 3, 4], requires_grad = True, dtype = torch.float64)

torch.Tensor()가 아닌 torch.tensor()로 정의해야 requires_grad를 편하게 정의할 수 있다.

x = torch.Tensor([1, 2, 3])
x.requires_grad_(True)

대문자로 하면 이렇게 정의해야 한다!

암튼 y도 정의해보자.

y = x**2 + 1

y를 출력하면 뭐가 나올지 감이 올것이다.(그렇다고 암산하지는 말고)

1^2+1= 2, 2^2+1 = 5, 3^2+1 = 10, 4^2+1 = 17 해서

tensor([ 2., 5., 10., 17.], dtype=torch.float64...)이 나온다.

자 이제 미분을 하고 x를 넣어보자!

d_x = torch.autograd.grad(y.sum(), x, create_graph=True)[0]

이렇게하면 된다!

y를 x에 대하여 미분한 다음 x를 집어 넣겠다는 뜻이다!
중요한 점은 y.sum()을 해야 된다!
저렇게 안하면 오류가 난다!

출처) https://rooney-song.tistory.com/5

d_x를 출력하면

tensor([2., 4., 6., 8.], dtype=torch.float64...)이 나온다!

x^2가 2x로 미분이 된다음 1, 2, 3, 4가 들어간것을 알 수 있다.

참고로 y.mean()을 하면 들어가는 인자가 4개라서 위의 값에서 각각 4로 나눠진 값이 나온다.
tensor([0.5, 1., 1.5, 4.], dtype=torch.float64...)가 나온다!

재밌는건 y.max()와 y.min()도 가능하다.
y.max()를 하면 tensor([0., 0., 0., 8.], dtype=torch.float64...)
y.min()를 하면 tensor([0.5, 0., 0., 0.], dtype=torch.float64...)이 나온다.

참도로 d_x를 한번더 미분할 수 있다!

d_xx =  torch.autograd.grad(d_x.sum(), a, create_graph=True)[0]

이걸 출력하면 2x를 미분한 2만 나온다.(이때는 뭘넣어도 2만 나온다...)
tensor([2., 2., 2., 2.], dtype=torch.float64, ...)

결론) 파이토치가 자동으로 미분하는 것을 알기만 하지말고 직접 미분해보자!

+이런식으로도 미분값을 볼 수 있다.

a = torch.ones((2, 2), requires_grad = True) #미분이 가능한 경우
b = a+1
print(b)
b.sum().backward()
print(a.grad)

'''
b_x = torch.autograd.grad(b.sum(), a, create_graph=True)[0]
print(b_x)
'''

backward를 사용하면 미분이 가능해진다!
그다음 .grad를 통해 미분 값을 볼 수 있다.

a = torch.ones((2, 2), requires_grad = True) #미분이 가능한 경우
t = torch.ones((2, 2), requires_grad = True) #미분이 가능한 경우
b = a**2+t
print(b)
b.sum().backward()
print(a.grad)
print(t.grad)

다변수에 대해서도 할 수 있다!
a^2 + t라는 식이 있을 때
먼저 2라는 값이 나오는 것을 알 수 있다.

그 다음 backward로 미분을 수행한다.

마지막에 .grad를 출력하면 a에 대해서 미분, t에 대해서 미분한 값을 따로따로 볼 수 있다!

a에대한 미분 값은 2a라서 모두 2가 되며, t에대한 미분 값은 1이기 때문에 모두 1이 되는 것을 볼 수 있었다!

backward()의 기능을 알 수 있다!

loss.backward로 오차 역전파를 만들어서
파라미터에 따른 오차의 gradient를 구한 다음, optimizer.step으로
각각의 파라미터에 대해
parameter = parameter - learning_rate * parameter.grad를 해주는 걸로 보인다.

profile
배우고 싶은것은 많으나 용두사미인 사람.

0개의 댓글