실습파일은 깃허브에 올려두었다
: https://github.com/CNU-Jiho-Jeong/jjh98/tree/main/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4%20%EA%B3%BC%EC%A0%9C
매개변수 α를 v에 곱해서 αv 항은 물체가 아무 힘도 받지 않을 때도 서서히 하강시키는 역할을 하게 된다. 물리에서의 마찰력이라고 생각하면 편하다.
모멘텀 파이썬 코드
import numpy as np
class Momentum:
def __init__(self, lr=0.01, momentum=0.9):
self.lr = lr #η
self.momentum = momentum #α
self.v = None
def update(self, params, grads):
# update()가 처음 호출될 때 v에 매개변수와 같은 구조의 데이터를 딕셔너리 변수로 저장
if self.v is None:
self.v = {}
for key, val in params.items():
self.v[key] = np.zeros_like(val)
for key in params.keys():
self.v[key] = self.momentum*self.v[key] - self.lr*grads[key]
params[key] += self.v[key]
=> SGD와 비교했을 때 더 효율적인 경로로 최적해를 찾는 것을 확인할 수 있다.
class AdaGrad:
def __init__(self, lr=0.01):
self.lr = lr
self.h = None
def update(self, params, grads):
if self.h is None:
self.h = {}
for key, val in params.items():
self.h[key] = np.zeros_like(val)
for key in params.keys():
self.h[key] += grads[key] * grads[key]
params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)
# 0으로 나누는 일이 없도록 1e-7을 더해줍니다. 이 값은 임의로 지정 가능합니다.
class Adam:
"""Adam (http://arxiv.org/abs/1412.6980v8)"""
def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):
self.lr = lr
self.beta1 = beta1
self.beta2 = beta2
self.iter = 0
self.m = None
self.v = None
def update(self, params, grads):
if self.m is None:
self.m, self.v = {}, {}
for key, val in params.items():
self.m[key] = np.zeros_like(val)
self.v[key] = np.zeros_like(val)
self.iter += 1
lr_t = self.lr * np.sqrt(1.0 - self.beta2**self.iter) / (1.0 - self.beta1**self.iter)
for key in params.keys():
#self.m[key] = self.beta1*self.m[key] + (1-self.beta1)*grads[key]
#self.v[key] = self.beta2*self.v[key] + (1-self.beta2)*(grads[key]**2)
self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key])
self.v[key] += (1 - self.beta2) * (grads[key]**2 - self.v[key])
params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)
#unbias_m += (1 - self.beta1) * (grads[key] - self.m[key]) # correct bias
#unbisa_b += (1 - self.beta2) * (grads[key]*grads[key] - self.v[key]) # correct bias
#params[key] += self.lr * unbias_m / (np.sqrt(unbisa_b) + 1e-7)
=> 학습의 갱신 강도를 적응적으로 조정해서 얻었기 때문에 모멘텀 방법과 비교해서 좌우 흔들림이 적음
=> 풀어야할 문제에 따라, 하이퍼파라미터를 어떻게 설정하느냐에 따라 결과가 바뀌므로, 넷 중 무엇이 가장 뛰어나다 말할 수는 없다
=> SGD의 학습 진도가 가장 느리고 나머지 세 기법의 진도는 비슷하지만 AdaGrad가 조금 더 빠르다는 걸 알 수 있다. (일반적으로 SGD 보다 다른 세 기법이 빠르게 학습하고, 때로는 최종 정확도도 높게 나타난다. 이번 과제에서도 그랬다. SGD 대신 Adam을 쓰니 최종 정확도가 91%에서 97%까지 올랐다.)
(++ 최적화기법들을 아래 그림을 보고 참고하자)
pytorch tensor를 GPU에 올리기
- device: 해당 tensor가 CPU, GPU 중 어디에 있는지 확인할 때 사용한다.
ex1> CPU에 있는 경우
print(a.device)
-> cpu
ex2> GPU에 있는 경우
print(a.device)
-> cuda:0
- cuda.is_available(): GPU(cuda)를 사용할 수 있는지 확인할 때 사용한다.
- to('cuda'): tensor를 GPU에 올릴 때 사용한다.
- to('cpu'): tensor를 다시 CPU에서 계산할 때 사용한다.
ex>
a = torch.tensor([1, 2, 3, 4])
print(a.device)
->cpu
a = a.to('cuda') # a 라는 tensor를 GPU에 올린다
print(a.device) # a가 GPU에 올라갔으므로 해당 tensor가 어디에 있는지 확인하면
-> cuda:0 # GPU에 있다.
a = a.to('cpu') # a라는 tensor를 CPU에 올린다.
print(a.device) # a가 CPU에 올라갔으므로 해당 tensor가 어디에 있는지 확인하면
-> cpu # CPU에 있다.
- requires_grad: True로 설정 시 모든 연산들을 기억
- retain_grad(): 해당 변수에 대한 gradient 연산을 기억 -> 이것을 하지 않으면 중간 변수에 대한 gradient는 저장 안됨
- backward(): 기억한 연산들에 대해서 gradient 계산 -> grad attribute(속성)에 gradient 정보 축적
- detach(): 계산 정보를 더 이상 기억하지 않음(stop tracking history)
- torch.no_grad(): torch.no_grad()를 사용하면 연산을 하는 동안 그 history를 기억하지 않는다. 그러므로 memory를 덜 사용한다. 때문에 gradient 계산이 필요없는 경우 즉, training이 아닌 inference를 하는 경우 사용한다. 더 적은 memory를 사용하기 때문에 더 빠른 계산이 가능해진다.
참고 사이트들
https://huangdi.tistory.com/7
https://m.blog.naver.com/gladiator67/222068617022
https://easy-going-programming.tistory.com/8
https://velog.io/@clayryu328/Weekly%EC%8B%A4%EC%8A%B55-multilayer-perceptron-with-mnist
https://qlsenddl-lab.tistory.com/28
https://m.blog.naver.com/fbfbf1/222480437930
https://m.blog.naver.com/gladiator67/222068617022
https://sdc-james.gitbook.io/onebook/2.-1/1./1.1.1.-cpu-gpu
https://championprogram.tistory.com/273
https://wandb.ai/wandb_fc/korean/reports/---VmlldzoxNDI4NzEy
https://jimmy-ai.tistory.com/101
https://www.delftstack.com/ko/api/numpy/python-numpy-mean/