앞선 포스팅에서 함수를 시각화하는 것을 했습니다. 이와 동일한 함수를 사용할 예정이고, 데이터 시각화하는 과정을 보고싶다면 아래 링크에서 참고하실 수 있습니다.
목표는 다음 그림1의 함수를 경사하강법을 사용하여 수학적인 계산 없이 최소값을 찾는 것입니다. 경사 하강법이란, 간단하게 설명드리면
그림2와 같은 함수가 있을 때 먄약 극대점이 아니라면, x, y 값을 더 값이 낮은 곳으로 이동시켜 최종적으로 극대점(즉, 기울기가 0인 편평한 지점)에 도달 했을 때 최적화를 멈추고 그 값을 반환하는 방법을 의미합니다.
예를 들면 평지를 찾는 등산객에 비유할 수 있겠습니다. 등산객을 등산을 시키다. 평평한 지점(산의 정상 또는 제일 낮은 계곡은 평평할 것입니다.)에 도달하면 멈추게 하고 그 위치를 알려주는 방법과 정확히 같습니다.
함수는 다음과 같은 코드를 통해 제작했습니다.
float fxy(float x, float y) {
return (x - 3) * (x - 3) + (y - 4) * (y - 4);
}
또 앞서 경사하강법이 기울기를 통해서 행해지는 것으로 말씀을 드렸습니다. 고로 미분을 해주는 함수를 제작해 각 지점에서 기울기를 알 수 있어야합니다.
float dfxydx(float x,float y, float dx) {
return (fxy(x + dx,y) - fxy(x,y)) / dx;
}
float dfxydy(float x, float y, float dy) {
return (fxy(x, y + dy) - fxy(x, y)) / dy;
}
마지막으로 학습이 너무 길게 늘어지지 않게 우리가 원하는 임계치에 도달하면 종료하도록 Error를 계산하는 함수를 제작한다. (이 방법 이외에도 여러 에러 계산법이 존재합니다. 이는 다른 포스트에서 다루도록 하겠습니다.)
float EE(float x0, float x1, float y0, float y1) {
return sqrt((x0 - x1) * (x0 - x1));
}
이렇게 4개의 함수를 만들면 준비가 모드 끝났다. 이제 main 함수로 들어갑니다.
int main() {
float dx = 0.01;
float dy = 0.01;
float psi = 0.1;
float x0 = 2;
float x1 = 1;
float y0 = 2;
float y1 = 1;
int iteration = 0;
float acu = 0.01;
while (EE(x0, x1, y0, y1) > 0.01 && iteration < 100) {
x0 = x1;
y0 = y1;
x1 -= psi * dfxydx(x0,y0, dx);
y1 -= psi * dfxydy(x0, y0, dy);
cout << x0 <<" "<< y0 << " " << fxy(x0,y0) << endl;
}
return 0;
}
몇가지 중요한 파라미터 또는 변수들이 main에 포함됩니다. 먼저 미분을 할 때 적당한 dx, dy 값을 정해주고 학습률 psi를 정합니다. 그리고 시작 지점 x1, y1을 정해줘야하는데 저는 임의로 1,1로 지정했습니다. x0와 y0는 적당히 EE 값이 나올 수 있도록 아무 값이나 설정해주시면 됩니다.(너무 x1, y1과 비슷하다면, 학습은 시작도 못해보고 종료됩니다.) 그리고 iteration과 acu(accuracy)를 지정해주었는데 while문 안에서 iteration이 100을 넘으면 학습을 종료하도록 세팅했습니다. 그리고 EE의 경우 0.01보다 정확해지면 학습이 종료됩니다.
이제 모든 세팅이 끝났습니다. 매 반복문에서 x1값에 기울기와 psi를 곱한 값을 빼줌으로서 더 낮은 값으로 이동하도록 코딩되어있고. 만약 이를 += 기호를 써주게 된다면 극대값을 찾도록 움직일 것이다.
실행결과 계산으로 얻을 수 있는 fxy(3,4) = 0와 매우 가까운 값을 찾을 수 있었습니다. 만약 지역 최소 값이 있어서 빠질 것이 우려된다면 시작점을 여러개로 두어 여러번 학습시키면 쉽게 최소값을 찾을 수 있습니다.
이 예제의 경우 그림4와 같이 컴퓨터가 함수 위에서 학습을 한 것을 이미지를 통해 확인할 수 있었습니다. 어떤가요? 최저점으로 dot이 이동하는게 보이시나요? 최저점에 다가갈 수록 기울기가 완만해지니 학습률이 떨어져 움직임이 느려진것 또한 관찰 할 수 있습니다. 경사하강법 포스팅을 마무리 하겠습니다.
'C && C++ > C++ X 머신러닝' 카테고리의 다른 글
다항회귀 예제(C++ with eigen library) (0) | 2020.10.17 |
---|---|
1차 선형 회귀 예제 경사하강법 사용(C++) (0) | 2020.10.13 |
임의의 함수 시각화 하기 예제(C++) (0) | 2020.10.12 |