🤖머신러닝/직접 구현하기

머신러닝 | 선형회귀(Linear Regression) 이론및 실습 [ 단일클래스, 단일분류 ]

Mawile 2021. 10. 9.
728x90

안녕하세요!

파이썬에서 tensorflow의 keras로 object detection, mnist를 이용하여 손글씨 학습하기, 등등 softmax층과 relu층을 이용한 다양한 실습을 하면서 흥미를 찾아가는 머신러닝 입문자입니다.

 

최근에 경사하강법에 관하여 c++에서 갑자기 구현해보고 싶어서 방금 만들어봤는데,

진짜로 이론대로 그대로 하니까 되더라구요..!!!ㅋㅋㅋㅋㅋ

신기해서 직접 쓴 경사하강법 코드 올립니다.

(경사하강법에 대한 공식유도를 알고싶으신분들은 아래 링크로 이동해주시기 바랍니다.)

https://mawile.tistory.com/222

 

경사하강법(Gradient Descent) 공식 유도

텐서플로우나 케라스와 같은 머신러닝 프레임워크로 경사하강법을 사용하다보면 내부적으로 어떻게 작동하는지, 어떻게 최적의 w와 b값을 얻을 수 있는지 궁금해지신분들이 계실겁니다. 이번

mawile.tistory.com

 

 

밑에 코드에 대한 이론및 설명도 적어놨습니다.

끝까지 내려서 봐주시길 바랍니다!

 

// 블로그 소스코드 아래쪽에 이론설명 있습니다!
// 아래 코드는 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, double& b){
	const int m = X.size();
	double loss = 0.0, dW = 0.0, db = 0.0;
	
	if(m != Y.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] + b;
		
		dW += ((H - Y[i]) * X[i]);
		db += (H - Y[i]);
	}
	dW = 2 * dW / m;
	db = 2 * db / m;
	
	// W and b update
	W -= learning_rate * dW;
	b -= learning_rate * db;
	
	// loss function
	for(int i=0;i<m;++i){
		// Hypothesis
		double H = W * X[i] + b;
		
		loss += std::pow(H - Y[i], 2);
	}
	
	return loss / m;
}

double predict(double& X, double& W, double& b){
	return (W * X + b);
}

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 = 5.0; // random value
	double b = 5.0; // random value
	
	// train 1000 times
	for(int i=0;i<1000;++i){
		double loss = GradientDescent(X, Y, W, b);
		
		if(i % 100 == 0){
			std::cout << "loss: " << loss << ", weight: " << W << '\n' << ", b: " << b << '\n';
		}
	}
	
	// prediction
	const int pred_X = 11;
	std::cout << "prediction: " << predict(pred_X, W, b);
}

결과값

 

우선 아래그림은 위 소스코드에서 사용한 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))의 방향으로 갑니다.

 

그러면 그 기울기는 점점 그래프의 중심점에 모이겠죠??

 

궁금한 부분있으시면 댓글로 질문 부탁드립니다.

 


 

728x90

댓글