안녕하세요!
파이썬에서 tensorflow의 keras로 object detection, mnist를 이용하여 손글씨 학습하기, 등등 softmax층과 relu층을 이용한 다양한 실습을 하면서 흥미를 찾아가는 머신러닝 입문자입니다.
최근에 경사하강법에 관하여 c++에서도 갑자기 구현해보고 싶어서 방금 만들어봤는데,
진짜로 이론대로 그대로 하니까 되더라구요..!!!ㅋㅋㅋㅋㅋ
신기해서 직접 쓴 경사하강법 코드 올립니다.
코드를 즉석으로 짜고 올려서 코드는 매우 더럽습니다. (ㅈㅅ합니다..ㅎㅎ..!)
// 아래 코드는 10번째까지의 값을 바탕으로 11번째의 값을 예측하는 선형회귀 코드입니다.
#include <iostream>
#include <vector>
#include <cmath>
constexpr double learning_rate = 1e-2;
double GradientDescent(std::vector<double>& X, std::vector<double>& Y, double& W){
const int m = Y.size();
double cost = 0, loss = 0;
if(m != X.size()) throw std::runtime_error("The sizes of X and Y are not right");
// cost function
for(int i=0;i<m;++i){
// Hypothesis
double H = W * X[i];
cost += (H - Y[i]) * X[i];
}
cost = cost / m;
// W assignment
W = W - (learning_rate * cost);
// loss function
for(int i=0;i<m;++i){
// Hypothesis
double H = W * X[i];
loss += std::pow(H - Y[i], 2);
}
return loss;
}
double predict(double& W, double X){
return (W * X);
}
int main() {
std::vector<double> X =
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std::vector<double> Y =
{ 1110, 2220, 3330, 4440, 5550, 6660, 7770, 8880, 9990, 11100 };
double W = 1; // random value
// train 30 times
for(int i=0;i<30;++i) std::cout << "loss: " << GradientDescent(X, Y, W) << ", weight: " << W << '\n';
// prediction
const int predictionX = 11;
std::cout << "prediction: " << predict(W, predictionX);
}
와우~! 12210이 나왔습니다!
우선 아래그림은 위 소스코드에서 사용한 cost function을 미분한 공식입니다.
좀 기초적인 이야기지만, 미분한 공식을 사용한 이유는 특정위치에서의 기울기를 구하기위해서입니다.
우선 a는 learning rate입니다.
경사하강법은 cost를 줄여나감으로써 최적의 W(그림에서는 오메가)를 찾는 알고리즘입니다.
이때 a는 그 cost의 기울기를 얼마만큼씩 줄여나갈것이냐를 정하는 값입니다. 저는 위코드에서는 1e-2를 줬습니다.
보통 머신러닝을 하다보면은 1e-2에서 1e-5사이로 줍니다.
이게 값을 적게 주면 W가 정교해지지만, 그만큼 학습해야될 횟수가 많아지죠.
반대로 값을 크게주면 학습은 적게해도 되지만, 그만큼 정확성(Accuracy)이 떨어집니다.
h는 hypothesis라고 해가지고, W와 Xi를 곱한값입니다.
bias는 편의성을 위해서 위 소스코드에는 포함하지 않았습니다.
위 식을 여러번씩 실행하는 과정을 우리는 "학습시킨다" 라고합니다.
그렇게 학습되서 나온 W(weight)를 바탕으로 내가 알고자하는 Xi와 곱해주면,
그것이 LinearRegression(선형회귀)이/가 되는겁니다.
loss function은 일반적으로 미분되지않은 경사하강법공식에서 m을 나누지않은 공식입니다.
마지막으로 저기서 W(제일 위 그림에서는 오메가)를 빼는 이유를 수학적으로 설명하자면, 기울기를 조금씩 줄여나가기위함입니다.
그냥 쉽게생각하시면되는데, 만약 a와 cost function의 곱한 결과가 음수(W - (a cost))라면 저기서 W는 최종적으로 양수(W + (a cost))의 방향으로 갑니다.
반대로, a와 cost function의 곱한 결과가 양수(W - (a cost))라면 저기서 W는 최종적으로 음수(W - (a cost))의 방향으로 갑니다.
그러면 그 기울기는 점점 그래프의 중심점에 모이겠죠??
다음에는 로지스틱회귀도 구현해보겠습니다! 오예!
궁금한 부분있으시면 댓글로 질문 부탁드립니다.