정리가 잘되어있기에 남겨놓는 부분
: 신경망 학습의 가장 기본적인 방식.
오차역전파법을 이용하여, 갱신시킬 파라미터들의 현 기울기 값인 그래디언트를 구해내고, 그것에 일정한 학습률을 곱하고, 기존 파라미터에 적용시키는 방식으로 갱신시킵니다.
class SGD:
def init(self, lr=0.01):
self.lr = lr
def update(self, params, grads):
for key in params.keys():
params[key] -= self.lr * grads[key]
위 코드는, 멤버변수로 학습률(Learning rate)를 저장하고, 갱신할 params와, 그것을 grads를 받아와서, 내부 원소를 차례로 돌며, 학습률과 기울기를 곱한 값으로 파라미터를 갱신시키는 것입니다.
기본 경사하강법(GD)와 다른점은, GD의 경우, 그냥 개념이라고 생각하셔도 됩니다.
SGD나 다른 옵티마이저들 전부 손실함수를 기준으로 경사를 하강하며 오차를 수정해나가니, 엄밀히 말하자면, Grad를 사용하는 머신러닝 학습 옵티마이저는 GD라는 기본 개념을 근간으로 삼고 있습니다.
위의 코드도 그냥 GD의 작용 그대로입니다.
GD 옵티마이저를 이용하는 여러 방식에 대해 알아봅시다.
1.1 Batch GD
Batch GD는, 기존 GD를 그대로 사용하는 것인데,
다만, Grads를 구하는 시점에서, 데이터의 묶음으로 Grads를 구하는 것입니다.
데이터셋을, 하나의 무더기인 batch 단위로 묶어서,
하나하나 순전파를 시켜서, 그 모든 것들의 손실함수를 구합니다.
손실함수의 값은 모두 다를 것입니다.
왜냐면 아직 파라미터가 제대로 학습되지 않았고, 데이터 자체의 노이즈도 있을 것이기에...
일단 손실함수는 데이터셋의 rows 개수 대로 존재할텐데,
예를들어 10행 3열의, 3특징, 10개 데이터라면, 값이 손실함수 코스트 하나인 10행 1열의 데이터가 나올 것입니다.
존재하는 파라미터값이 이에 미치는 영향력을 미분하기 위해서, 이 모든 손실함수에 작용하는 방향으로 갱신을 해야하는데, 그러기 위해서 손실함수값을 모두 더하거나, 혹은 평균을 내어, 그 계산에 대한 오차역전파를 실행하여 각 파라미터의 편미분 기울기, 즉 grads를 구하면 됩니다.
일단 grads를 구했다면, 이후로는 그냥 GD와 다를것이 전혀 없습니다.
즉, 옵티마이저 작용은 전혀 달라질 것이 없습니다.
요약하자면, BGD = GD + batch
로, 과정을 다시 요약하자면,
입력 -> 순전파 -> 손실함수 계산 -> 입력 -> 순전파 -> 손실함수 계산 .... -> 배치 내 데이터에 대한 손실함수 값 모두 더하기 -> 역전파 -> grads 값 구하기 -> 값 갱신
이라는 과정을 거칩니다.
Grads를 구하기 전에, 모든 데이터에 대한 손실함수 값부터 구해서 저장해두고,
그렇게 구해진 손실함수 값을 모두 더하거나 평균을 냅니다.(두 방식 모두, 극단적으로 보았을 때, 손실함수값이 0이 되는 시점에서 0이 나오고, 또한 애초에 0이 나올수 없더라도, 최소값을 향해 탐색이 가능한 지표가 됩니다.)
그리고 그 합쳐진 값에 대해, 파라미터 w들의 각각의 편미분을 구한 후,
이를 GD를 사용하여 갱신하는 것입니다.
장점을 요약하자면,
일단 GD중에서는 안정적이게 학습을 수행해내며, 데이터 배치에 대해서는, 순전파만 여러번 실행하고, 역전파는 전체 손실함수 값에 대해 단 한번만 수행하므로, 연산횟수가 적다는 장점이 있습니다.
게다가 순전파의 경우에는, 각각의 연산이 서로에게 영향을 미치지 않으니, 이는 병렬처리가 가능합니다. (100명이, 한 데이터씩, 해당 모델의 파라미터를 사용해서 순전파에서부터 손실함수 값까지의 연산을 나눠서 처리하면 빠르겠죠?)
단점이란,
개별적인 학습 시간이 너무 오래걸리며, 배치단위로 손실함수의 값을 저장해야하기에 메모리가 많이 필요하며, 무엇보다, 꽤나 정적인 탐색, 즉 전체 데이터에 비해 실제 학습 갱신 횟수는 적기 때문에 기울기 소실에 빠질 우려가 큽니다.
1.2 SGD
BGD의 경우에는, 배치 단위가 큽니다.
즉, 배치 내 데이터들을 모두 사용해야만 학습이 이뤄지는 것이죠.
이미지 데이터 학습같은, 순전파에 시간이 걸리는 데이터의 경우에는, 한번 학습에 드는 시간이 오래 걸린다는 단점이 있습니다.
SGD는, 위에서 설명한 그냥 GD의 개념이라 생각하시면 됩니다.
데이터를 묶음으로 사용하지 않고,
한 데이터가 들어오면, 그에대한 순전파와 역전파를 한번에 하기를 반복하는 것입니다.
과정을 말하자면,
입력데이터 -> 순전파 -> 손실함수 계산 -> Grad 계산 -> 갱신
의 과정을, 데이터당 한번씩 수행하는 것입니다.
이 경우에는, BGD보다 난폭하게 가중치가 갱신되며, 언뜻 불안정해보이기는 하겠지만,
결국 GD 알고리즘에 따라서 최적화를 향해 나아가고,
그 과정에서 기울기가 크게 변화하며, 지역 소실점을 탈출하기 쉬워집니다.(골짜기를 타고 흐르는 물이, 조용히 흐르면, 중간에 고일수 있지만, 이리저리 방향을 바꾸며 내려오면, 중간 지점을 지나쳐서 아래로 튀어 내려갈수 있다고 생각하세요.)
이렇게, BGD에 비해 학습이 상당히 다이나믹하게 가중치를 갱신하므로, 이를 stochastic하다, 확률적이다. 라는 이름이 붙은 것입니다.
이에 대비하여 BGD는 Deterministic하다, 결정론적이다 라고 합니다.
SGD의 장점은,
일단 개별 데이터를 사용하므로, 실시간 학습이 가능하다는 것이고,
다이나믹한 갱신으로 인하여 기울기 소실에 BGD보다 강하며,
BGD보다 빠르게 최적점에 도달할수 있습니다.
왜냐면, BGD가 필요 이상으로 순전파를 통해 Grads의 재료들을 모아야 하는 것과는 반대로,
이리저리 튀며, 연산량도 많아지기는 하겠지만, 일단 최적점에 도달하는 시기만큼은 BGD보다 빨리 도달할 가능성이 크기 때문입니다.(BGD는, 해당 데이터셋의 최적의 위치에 도달하기 까지, 정확한 방향을 알고 한칸한칸 이동할테지만, BGD가 1걸음을 갈때, SGD는 100걸음을, 조금 틀린 방향일지라도 나아갑니다.)
반면 단점은,
일단 데이터 하나하나에 대해 연산을 실행하고, 그렇게 갱신된 데이터를 활용해야 하기에, 병렬처리에도 강점이 사라지며, 전체 데이터에서 얻어야 하는 정보에 대해 모르니, 오히려 이상한 방향으로 학습을 진행할 가능성이 있습니다.(지도를 보고 길을 찾아야 하는데, 지도 없이 일단 달려나가다가 길을 잃는 경우와 비슷한데, 대부분은 많은 시도로 이를 해결합니다.)
1.3 MiniBatch Stochastic GD (MSGD)
위와 같은 두 종류의 장점을 가져오고, 단점을 보완하는 방향으로,
미니배치라는 개념이 생겨납니다.
이름 그대로, 배치를 작게 두는 것입니다.
예를들면, 마트에서 100개 들이 라면박스를 사가는 사람은 아마 그다지 없을 것입니다.
하지만, 간단하게 5개 단위로 부담없는 단위로 나누어서 팔면, 개별 판매나 대량 판매보다 큰 장점이 있겠죠.
미니배치는, 배치 단위를 작게 만들어서, BGD의 장점인 병렬처리나 안정성 등의 장점과, SGD의 다이나믹함과 빠른 적용과 시도라는 장점을 가져오며, 나머지 단점들을 잘 무마시키는 방법이라 할수있네요.
과정은, 그냥 BGD를 생각하시면 될텐데,
배치단위로 순전파를 시키고, 그 손실함수들을 이용하여 한번씩 갱신을 해주는 것인데,
이 Batch 단위가 제법 부담없이 줄어들게 만들었다라고 생각하면 됩니다.
배치 단위야, 위에서 나열한 BGD와 SGD의 내용을 숙지한 상태로, 이리저리 시도하며 사용자가 정하면 되는 것입니다.
장점과 단점 모두,
BGD와 SGD를 적절히 혼용한 것인데, 그냥 GD는 미니배치를 사용하는 것이 좋다고 생각합니다.
단점을 굳이 뽑자면, 기본이 그냥 GD라는 것에서, 바닐라 GD의 근본적인 문제점을 그대로 가지고 있다는 것이고,
미니배치를 얼마만큼 떼어내어 사용할것인지, 그 단위를 정하는 미니배치 사이즈를,
하이퍼 파라미터로써 설정해줘야 한다는 것입니다.
실습시에는 직접 각각 다른 lr을 적용해보며,
최적이 되는 수치를 찾아낸다면 될 것입니다.
이것이 딥러닝 학습의 가장 근간이 되고 기본이 되는 옵티마이저로,
다른 옵티마이저들 역시 이를 기본으로 하여, 하나하나 성능을 높이는 방향으로 진화했다고 생각하시면 됩니다.
GD 자체에 대한 장단점에 대해서는, GD를 개선하기 위해 발전한, 아래의 옵티마이저들을 살펴보며 알아봅시다.