데이터 과학 및 머신 러닝(파트 06): 경사 하강법(Gradient Descent)
성급한 최적화는 프로그래밍에서 모든 악의 근원입니다.
-도널드 크누스
소개
Wikipedia에 따르면 경사 하강법(가장 가파른 강하라고도 함)은 미분 가능 함수의 로컬 최소값을 찾기 위한 1차 반복 최적화 알고리즘입니다. 아이디어는 현재 지점에서 함수의 기울기(또는 대략적인 기울기)의 반대 방향으로 반복되는 단계를 수행하는 것입니다. 이것이 가장 가파른 내리막의 방향이기 때문입니다. 반대로 기울기 방향으로 이동하면 해당 함수의 로컬 최대값이 됩니다; 이 절차는 경사 상승(gradient ascent)으로 알려져 있습니다. 기본적으로 경사 하강법은 함수의 최소값을 찾는 데 사용되는 최적화 알고리즘입니다:
경사 하강법은 데이터 세트에 대해 가장 적합한 모델의 매개변수를 찾는 데 도움이 되므로 머신 러닝에서 매우 중요한 알고리즘입니다. 비용 함수(Cost Function)라는 용어를 먼저 설명하겠습니다.
비용 함수
어떤 사람들은 이것을 손실 함수(loss function)라고도 부릅니다. 이것은 우리 모델이 x와 y 값 사이의 관계를 예측하는 데 얼마나 좋은지 또는 나쁜지를 계산하는 척도입니다.
모델이 예측하는 방법을 결정하는 데 사용할 수 있는 메트릭은 많이 있지만 비용 함수는 전체 데이터 세트에서 평균 손실을 찾습니다. 비용 함수가 클수록 우리의 모델이 데이터 세트에서 관계를 찾는 것에 안 좋은 영향을 미칩니다.
기울기 하강법은 비용 함수가 가장 낮은 모델이 최고의 모델이기 때문에 비용 함수를 최소화하는 것을 목표로 합니다. 방금 설명한 내용을 이해하기 위해 다음과 같은 예제를 살펴보겠습니다.
비용 함수가 방정식이라고 가정합니다.
파이썬으로 이 함수의 그래프를 그리면 다음과 같이 보일 것입니다:
비용 함수에 대해 수행해야 하는 첫 번째 단계는 체인 규칙을 사용하여 비용 함수를 차별화하는 것입니다.
방정식y= (x+5)^2는 합성 함수입니다(다른 함수 안에 하나의 함수가 있음). 외부 함수는 (x+5)^2이고 내부 함수는(x+5)입니다. 이를 구별하기 위해 체인 규칙을 적용해 보겠습니다. 이미지를 참조하십시오:
이해하기 어려우시면 동영상 링크를 따라가 보세요. 동영상은 손으로 직접 계산하는 것입니다. 우리가 지금 얻은 이 함수는 기울기입니다. 방정식의 기울기를 찾는 과정은 모든 과정에서 가장 중요한 단계이며 함수를 미분하는 목적은 함수의 기울기를 얻기 위한 것이라고 예전에 수학 선생님들이 말해줬던거 같습니다.
이것이 첫 번째이자 가장 중요한 단계이며 아래는 두 번째 단계입니다.
02단계:
이제 기울기의 음의 방향으로 이동해 봅니다. 여기서 질문이 제기됩니다. 얼마나 이동해야 합니까? 이곳이 학습율이 작동하는 곳입니다.
학습율
정의에 따라 이것은 최소 손실 함수를 향해 이동하는 동안의 각 반복 단계의 크기입니다. 사람이 산을 내려가는 경우와 같은 예를 들어보면 걸음은 학습율이고 걸음이 작을수록 더 오래 걸립니다. 걸음을 통해 산의 바닥에 도달하거나 그 반대의 경우도 마찬가지입니다.
알고리즘 학습율을 0.0001과 같이 너무 작지 않은 작은 값으로 유지하면 알고리즘이 최소값에 도달하는 데 시간이 더 오래 걸릴 수 있으므로 프로그램 실행 시간이 늘어납니다. 반대로 학습율에 큰 숫자를 사용하면 알고리즘이 최소값을 건너뛰게 되어 결국에는 목표로 하는 최소값을 놓칠 수 있습니다.
기본 학습율은 0.01입니다.
반복을 수행하여 알고리즘이 어떻게 작동하는지 살펴보겠습니다.
첫 번째 반복: 임의의 지점을 알고리즘의 시작점으로 선택합니다. 이제 x의 값을 업데이트하기 위해 x의 첫 번째 값으로 0을 선택했습니다. 이것이 공식입니다.
반복할 때마다 함수의 최소값을 향해 하강하므로 경사 하강법이라는 이름도 마찬가지입니다. 이제 이해 되나요?
이것이 어떻게 작동하는지 자세히 살펴보겠습니다. 무슨 일이 일어나고 있는지 확실하게 이해할 수 있도록 2회 반복에서 수동으로 값을 계산해 보겠습니다.
1차 반복:
공식: x1 = x0 - 학습율 * ( 2*(x+5) )
x1 = 0 - 0.01 * 0.01 * 2*(0+5)
x1 = -0.01 * 10
x1 = -0.1(최종)
이제 마지막으로 새로운 값을 이전 값에 할당하여 값을 업데이트하고 함수의 최소값에 도달할 때까지 절차를 반복합니다.
x0 = x1
두 번째 반복:
x1 = -0.1 - 0.01 * 2*(-0.1+5)
x1 = -0.198
그러면: x0 = x1
이 절차를 여러 번 반복하면 10회 첫 번째 반복에 대한 출력은 다음과 같습니다.
RS 0 17:15:16.793 gradient-descent test (EURUSD,M1) Gradient Descent CostFunction CUSTOM QQ 0 17:15:16.793 gradient-descent test (EURUSD,M1) 1 x0 = 0.0000000000 x1 = -0.1000000000 CostFunction = 10.0000000000 ES 0 17:15:16.793 gradient-descent test (EURUSD,M1) 2 x0 = -0.1000000000 x1 = -0.1980000000 CostFunction = 9.8000000000 PR 0 17:15:16.793 gradient-descent test (EURUSD,M1) 3 x0 = -0.1980000000 x1 = -0.2940400000 CostFunction = 9.6040000000 LE 0 17:15:16.793 gradient-descent test (EURUSD,M1) 4 x0 = -0.2940400000 x1 = -0.3881592000 CostFunction = 9.4119200000 JD 0 17:15:16.793 gradient-descent test (EURUSD,M1) 5 x0 = -0.3881592000 x1 = -0.4803960160 CostFunction = 9.2236816000 IG 0 17:15:16.793 gradient-descent test (EURUSD,M1) 6 x0 = -0.4803960160 x1 = -0.5707880957 CostFunction = 9.0392079680 IG 0 17:15:16.793 gradient-descent test (EURUSD,M1) 7 x0 = -0.5707880957 x1 = -0.6593723338 CostFunction = 8.8584238086 JF 0 17:15:16.793 gradient-descent test (EURUSD,M1) 8 x0 = -0.6593723338 x1 = -0.7461848871 CostFunction = 8.6812553325 NI 0 17:15:16.793 gradient-descent test (EURUSD,M1) 9 x0 = -0.7461848871 x1 = -0.8312611893 CostFunction = 8.5076302258 CK 0 17:15:16.793 gradient-descent test (EURUSD,M1) 10 x0 = -0.8312611893 x1 = -0.9146359656 CostFunction = 8.3374776213
함수의 최소값에 매우 근접할 때 알고리즘의 다른 10개의 값도 살펴보겠습니다.
GK 0 17:15:16.800 gradient-descent test (EURUSD,M1) 1052 x0 = -4.9999999970 x1 = -4.9999999971 CostFunction = 0.0000000060 IH 0 17:15:16.800 gradient-descent test (EURUSD,M1) 1053 x0 = -4.9999999971 x1 = -4.9999999971 CostFunction = 0.0000000059 NH 0 17:15:16.800 gradient-descent test (EURUSD,M1) 1054 x0 = -4.9999999971 x1 = -4.9999999972 CostFunction = 0.0000000058 QI 0 17:15:16.800 gradient-descent test (EURUSD,M1) 1055 x0 = -4.9999999972 x1 = -4.9999999972 CostFunction = 0.0000000057 II 0 17:15:16.800 gradient-descent test (EURUSD,M1) 1056 x0 = -4.9999999972 x1 = -4.9999999973 CostFunction = 0.0000000055 RN 0 17:15:16.800 gradient-descent test (EURUSD,M1) 1057 x0 = -4.9999999973 x1 = -4.9999999973 CostFunction = 0.0000000054 KN 0 17:15:16.800 gradient-descent test (EURUSD,M1) 1058 x0 = -4.9999999973 x1 = -4.9999999974 CostFunction = 0.0000000053 JO 0 17:15:16.800 gradient-descent test (EURUSD,M1) 1059 x0 = -4.9999999974 x1 = -4.9999999974 CostFunction = 0.0000000052 JO 0 17:15:16.800 gradient-descent test (EURUSD,M1) 1060 x0 = -4.9999999974 x1 = -4.9999999975 CostFunction = 0.0000000051 QL 0 17:15:16.800 gradient-descent test (EURUSD,M1) 1061 x0 = -4.9999999975 x1 = -4.9999999975 CostFunction = 0.0000000050 QL 0 17:15:16.800 gradient-descent test (EURUSD,M1) 1062 x0 = -4.9999999975 x1 = -4.9999999976 CostFunction = 0.0000000049 HP 0 17:15:16.800 gradient-descent test (EURUSD,M1) Local miminum found =-4.999999997546217
1062(천육십이) 반복 후 알고리즘은 이 함수의 로컬 최소값에 도달할 수 있었습니다.
이 알고리즘에서 주목할 점
비용 함수의 값을 살펴보면 처음에는 값이 크게 변경되었다는 것을 볼 수 있지만 비용 함수의 마지막 값에서는 눈에 띄는 변화가 아주 미미합니다.
경사 하강법은 함수의 최소값 근처가 아닐 때 더 큰 단계를 거치지만 함수의 최소값에 가까울 때는 작은 단계를 밟습니다. 산에서 맨 아래쪽의 근처에 있을 때도 마찬가지입니다. 이제 여러분은 경사 하강법이 매우 똑똑하다는 것을 알 수 있을 것입니다!
이렇게 로컬 최소값은
HP 0 17:15:16.800 gradient-descent test (EURUSD,M1) Local miminum found =-4.999999997546217
이 함수의 최소값이-5.0이기 때문에 정확한 값입니다!
여기서 질문
기울기는 언제 중지해야 하는지를 어떻게 알 수 있습니까? 우리는 알고리즘이 무한대 또는 적어도 컴퓨터의 계산 능력이 끝날 때까지 계속 반복하도록 할 수 있습니다.
비용 함수가 0일 때 경사 하강법이 작업을 완료했음을 알 수 있습니다.
이제 MQL5에서 이 전체의 작업을 코딩해 보겠습니다:
while (true) { iterations++; x1 = x0 - m_learning_rate * CustomCostFunction(x0); printf("%d x0 = %.10f x1 = %.10f CostFunction = %.10f",iterations,x0,x1,CustomCostFunction(x0)); if (NormalizeDouble(CustomCostFunction(x0),8) == 0) { Print("Local minimum found =",x0); break; } x0 = x1; }
위의 코드 블록은 우리가 원하는 결과였지만CGradientDescent클래스에만 있는 것은 아닙니다. CustomCostFunction함수는 우리의 미분 방정식이 유지되고 계산되는 곳입니다.
double CGradientDescent::CustomCostFunction(double x) { return(2 * ( x + 5 )); }
목적이 무엇일까요?
이 주제를 다룬 기사 시리즈에서 이전의 라이브러리에서 생성한 기본 선형 모델을 사용할 수 있는데 굳이 이러한 계산을 한 목적이 무엇인지 여러분들이 궁금할지도 모릅니다. Newsflash 기본값을 사용하여 만든 모델이 언제나 최상의 모델은 아니므로 오류가 거의 없는 모델(최상의 모델)에 대한 최상의 매개 변수를 컴퓨터가 학습하도록 해야 합니다.
이제 우리는 인공 신경망 구축에 있어 역전파 및 이외 기술에서 신경망이 학습(패턴을 학습)하는 방법을 이해하는 데에 더 가까워지고 있습니다. 경사 하강법은 이 모든 것을 가능하게 만든 가장 인기 있는 알고리즘입니다. 경사 하강법에 대한 확실한 이해 없이는 상황이 복잡해지면서 프로세스를 전혀 이해하지 못할 수도 있습니다.
회귀 모델에 대한 경사 하강법
Salary Dataset을 사용하여 경사 하강법을 사용하여 최상의 모델을 만들어 보겠습니다.
Python의 데이터 시각화:
import pandas as pd import numpy as np import matplotlib.pyplot as plt data = pd.read_csv(r"C:\Users\Omega Joctan\AppData\Roaming\MetaQuotes\Terminal\892B47EBC091D6EF95E3961284A76097\MQL5\Files\Salary_Data.csv") print(data.head(10)) x = data["YearsExperience"] y = data["Salary"] plt.figure(figsize=(16,9)) plt.title("Experience vs Salary") plt.scatter(x,y,c="green") plt.xlabel(xlabel="Years of Experience") plt.ylabel(ylabel="Salary") plt.show()
이것은 우리의 그래프가 될 것입니다:
년수 vs 급여
데이터 세트를 보면 이 데이터 세트가 회귀 문제를 위한 것임을 알 수 있지만 예측하거나 달성하려는 것이 무엇이든 우리에게는 도움이 되는 백만 개의 모델이 있을 수 있습니다.
개인의 경험과 급여를 예측하는 데 사용할 수 있는 최고의 모델은 무엇일까요? 그것이 우리가 알아내려고 하는 것입니다. 먼저 회귀 모델의 비용 함수를 도출해 보겠습니다.
이론
선형 회귀로 돌아가 보겠습니다.
우리는 모든 선형 모델에는 오류가 있다는 사실을 알고 있습니다. 우리는 또한 이 그래프에서 백만 개의 선을 만들 수 있고 그중 가장 잘 맞는 선은 항상 오류가 가장 적은 선이라는 것을 알고 있습니다.
비용 함수는 실제 값과 예측 값 사이의 오차를 나타내며 비용 함수의 공식을 다음과 같이 작성할 수 있습니다:
비용 = 실제 Y - 예측 Y
오류의 크기를 보고 있으므로 제곱을 하면 이제 공식은 다음과 같습니다.
그러나 우리는 전체 데이터 세트에서 오류를 찾고 있습니다. 그러므로 우리는 합계를 만들어야 합니다.
마지막으로 오류의 합계를 데이터 세트의 항목 수인m으로 나눕니다:
다음은 수작업으로 수행되는 수학 절차 전체를 보여주는 비디오입니다.
이제 비용 함수가 있으므로 경사 하강법을 코딩하고 두 가지 모두에 가장 적합한 매개변수를 찾아보겠습니다. Bo 로 표시되는 X(Slope)의 계수와B1 로 표시되는 Y 절편
double cost_B0=0, cost_B1=0; if (costFunction == MSE) { int iterations=0; for (int i=0; i<m_iterations; i++, iterations++) { cost_B0 = Mse(b0,b1,Intercept); cost_B1 = Mse(b0,b1,Slope); b0 = b0 - m_learning_rate * cost_B0; b1 = b1 - m_learning_rate * cost_B1; printf("%d b0 = %.8f cost_B0 = %.8f B1 = %.8f cost_B1 = %.8f",iterations,b0,cost_B0,b1,cost_B1); DBL_MAX_MIN(b0); DBL_MAX_MIN(cost_B0); DBL_MAX_MIN(cost_B1); if (NormalizeDouble(cost_B0,8) == 0 && NormalizeDouble(cost_B1,8) == 0) break; } printf("%d Iterations Local Minima are\nB0(Intercept) = %.5f || B1(Coefficient) = %.5f",iterations,b0,b1); }
경사 하강법 코드에서 몇 가지 사항을 확인해 보시기 바랍니다.
- 프로세스는 이전에 수행한 프로세스와 동일하지만 이번에는 Bo 및 B1 값을 한 번에 두 번 찾고 업데이트합니다.
- 제한된 수의 반복이 있습니다. 누군가 무한 루프를 만드는 가장 좋은 방법은 while 루프를 사용하는 것이라고 말했습니다. 이번에는 while 루프를 사용하지 않고 대신 최상의 모델에 대한 계수를 찾기 위해 사용하는 알고리즘이 작동하는 횟수를 제한하려고 합니다.
- DBL_MAX_MIN 은 컴퓨터의 수학적 한계에 도달했는지 확인하고 알려주는 디버깅 목적의 함수입니다.
이것은 알고리즘 작업의 출력입니다. 학습율 = 0.01 반복 = 10000
PD 0 17:29:17.999 gradient-descent test (EURUSD,M1) [20] 91738.0000 98273.0000 101302.0000 113812.0000 109431.0000 105582.0000 116969.0000 112635.0000 122391.0000 121872.0000 JS 0 17:29:17.999 gradient-descent test (EURUSD,M1) Gradient Descent CostFunction MSE RF 0 17:29:17.999 gradient-descent test (EURUSD,M1) 0 b0 = 1520.06000000 cost_B0 = -152006.00000000 B1 = 9547.97400000 cost_B1 = -954797.40000000 OP 0 17:29:17.999 gradient-descent test (EURUSD,M1) 1 b0 = 1995.08742960 cost_B0 = -47502.74296000 B1 = 12056.69235267 cost_B1 = -250871.83526667 LP 0 17:29:17.999 gradient-descent test (EURUSD,M1) 2 b0 = 2194.02117366 cost_B0 = -19893.37440646 B1 = 12707.81767044 cost_B1 = -65112.53177770 QN 0 17:29:17.999 gradient-descent test (EURUSD,M1) 3 b0 = 2319.78332575 cost_B0 = -12576.21520809 B1 = 12868.77569178 cost_B1 = -16095.80213357 LO 0 17:29:17.999 gradient-descent test (EURUSD,M1) 4 b0 = 2425.92576238 cost_B0 = -10614.24366387 B1 = 12900.42596039 cost_B1 = -3165.02686058 GH 0 17:29:17.999 gradient-descent test (EURUSD,M1) 5 b0 = 2526.58198175 cost_B0 = -10065.62193621 B1 = 12897.99808257 cost_B1 = 242.78778134 CJ 0 17:29:17.999 gradient-descent test (EURUSD,M1) 6 b0 = 2625.48307920 cost_B0 = -9890.10974571 B1 = 12886.62268517 cost_B1 = 1137.53974060 DD 0 17:29:17.999 gradient-descent test (EURUSD,M1) 7 b0 = 2723.61498028 cost_B0 = -9813.19010723 B1 = 12872.93147573 cost_B1 = 1369.12094310 HF 0 17:29:17.999 gradient-descent test (EURUSD,M1) 8 b0 = 2821.23916252 cost_B0 = -9762.41822398 B1 = 12858.67435081 cost_B1 = 1425.71249248 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Last Iterations >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> EI 0 17:29:48.247 gradient-descent test (EURUSD,M1) 6672 b0 = 25792.20019866 cost_B0 = -0.00000001 B1 = 9449.96232146 cost_B1 = 0.00000000 NG 0 17:29:48.247 gradient-descent test (EURUSD,M1) 6673 b0 = 25792.20019866 cost_B0 = -0.00000001 B1 = 9449.96232146 cost_B1 = 0.00000000 GD 0 17:29:48.247 gradient-descent test (EURUSD,M1) 6674 b0 = 25792.20019866 cost_B0 = -0.00000001 B1 = 9449.96232146 cost_B1 = 0.00000000 PR 0 17:29:48.247 gradient-descent test (EURUSD,M1) 6675 b0 = 25792.20019866 cost_B0 = -0.00000001 B1 = 9449.96232146 cost_B1 = 0.00000000 IS 0 17:29:48.247 gradient-descent test (EURUSD,M1) 6676 b0 = 25792.20019866 cost_B0 = -0.00000001 B1 = 9449.96232146 cost_B1 = 0.00000000 RQ 0 17:29:48.247 gradient-descent test (EURUSD,M1) 6677 b0 = 25792.20019866 cost_B0 = -0.00000001 B1 = 9449.96232146 cost_B1 = 0.00000000 KN 0 17:29:48.247 gradient-descent test (EURUSD,M1) 6678 b0 = 25792.20019866 cost_B0 = -0.00000001 B1 = 9449.96232146 cost_B1 = 0.00000000 DL 0 17:29:48.247 gradient-descent test (EURUSD,M1) 6679 b0 = 25792.20019866 cost_B0 = -0.00000001 B1 = 9449.96232146 cost_B1 = 0.00000000 RM 0 17:29:48.247 gradient-descent test (EURUSD,M1) 6680 b0 = 25792.20019866 cost_B0 = -0.00000001 B1 = 9449.96232146 cost_B1 = 0.00000000 IK 0 17:29:48.247 gradient-descent test (EURUSD,M1) 6681 b0 = 25792.20019866 cost_B0 = -0.00000001 B1 = 9449.96232146 cost_B1 = 0.00000000 PH 0 17:29:48.247 gradient-descent test (EURUSD,M1) 6682 b0 = 25792.20019866 cost_B0 = -0.00000001 B1 = 9449.96232146 cost_B1 = 0.00000000 GF 0 17:29:48.247 gradient-descent test (EURUSD,M1) 6683 b0 = 25792.20019866 cost_B0 = -0.00000001 B1 = 9449.96232146 cost_B1 = 0.00000000 MG 0 17:29:48.247 gradient-descent test (EURUSD,M1) 6684 b0 = 25792.20019866 cost_B0 = -0.00000000 B1 = 9449.96232146 cost_B1 = 0.00000000 LE 0 17:29:48.247 gradient-descent test (EURUSD,M1) 6684 Iterations Local Minima are OJ 0 17:29:48.247 gradient-descent test (EURUSD,M1) B0(Intercept) = 25792.20020 || B1(Coefficient) = 9449.96232
matplotlib 를 사용하여 그래프를 그리면
맞습니다, 경사 하강법은 우리가 시도한 10000개의 모델 중에서 최고의 모델을 성공적으로 얻을 수 있었습니다. 훌륭하지만 우리 모델이 이상하게 작동하거나 원하지 않는 결과를 얻게 만들 수도 있는 중요한 단계가 하나 있습니다.
선형 회귀 입력 변수 데이터 정규화
우리는 서로 다른 데이터 세트에 대해 서로 다른 반복 후에 최고의 모델을 찾을 수 있다는 것을 알고 있습니다. 어떤 것은 최고의 모델에 도달하는 데 100회의 반복이 필요할 수 있고 일부는 비용 함수가 0이 되는 데 10000 또는 최대 백만번의 반복이 걸릴 수 있습니다. 학습율이 잘못된 값으로 인해 로컬 최소값을 놓치게 될 수도 있으며 해당 목표를 놓치면 결국 컴퓨터의 수학적 한계에 도달하게 됩니다. 이러한 케이스를 살펴보겠습니다.
학습율 = 0.1 반복 1000
시스템에서 허용하는 최대 double 값에 도달했습니다. 다음은 로그입니다.
GM 0 17:28:14.819 gradient-descent test (EURUSD,M1) Gradient Descent CostFunction MSE OP 0 17:28:14.819 gradient-descent test (EURUSD,M1) 0 b0 = 15200.60000000 cost_B0 = -152006.00000000 B1 = 95479.74000000 cost_B1 = -954797.40000000 GR 0 17:28:14.819 gradient-descent test (EURUSD,M1) 1 b0 = -74102.05704000 cost_B0 = 893026.57040000 B1 = -512966.08473333 cost_B1 = 6084458.24733333 NM 0 17:28:14.819 gradient-descent test (EURUSD,M1) 2 b0 = 501030.91374462 cost_B0 = -5751329.70784622 B1 = 3356325.13824362 cost_B1 = -38692912.22976952 LH 0 17:28:14.819 gradient-descent test (EURUSD,M1) 3 b0 = -3150629.51591119 cost_B0 = 36516604.29655810 B1 = -21257352.71857720 cost_B1 = 246136778.56820822 KD 0 17:28:14.819 gradient-descent test (EURUSD,M1) 4 b0 = 20084177.14287909 cost_B0 = -232348066.58790281 B1 = 135309993.40314889 cost_B1 = -1565673461.21726084 OQ 0 17:28:14.819 gradient-descent test (EURUSD,M1) 5 b0 = -127706877.34210962 cost_B0 = 1477910544.84988713 B1 = -860620298.24803317 cost_B1 = 9959302916.51181984 FM 0 17:28:14.819 gradient-descent test (EURUSD,M1) 6 b0 = 812402202.33122230 cost_B0 = -9401090796.73331833 B1 = 5474519904.86084747 cost_B1 = -63351402031.08880615 JJ 0 17:28:14.819 gradient-descent test (EURUSD,M1) 7 b0 = -5167652856.43381691 cost_B0 = 59800550587.65039062 B1 = -34823489070.42410278 cost_B1 = 402980089752.84948730 MP 0 17:28:14.819 gradient-descent test (EURUSD,M1) 8 b0 = 32871653967.62362671 cost_B0 = -380393068240.57440186 B1 = 221513298448.70788574 cost_B1 = -2563367875191.31982422 MM 0 17:28:14.819 gradient-descent test (EURUSD,M1) 9 b0 = -209097460110.12799072 cost_B0 = 2419691140777.51611328 B1 = -1409052343513.33935547 cost_B1 = 16305656419620.47265625 HD 0 17:28:14.819 gradient-descent test (EURUSD,M1) 10 b0 = 1330075004152.67309570 cost_B0 = -15391724642628.00976562 B1 = 8963022367351.18359375 cost_B1 = -103720747108645.23437500 DP 0 17:28:14.819 gradient-descent test (EURUSD,M1) 11 b0 = -8460645083849.12207031 cost_B0 = 97907200880017.93750000 B1 = -57014041694401.67187500 cost_B1 = 659770640617528.50000000
이는 학습율이 잘못되면 최상의 모델을 찾을 가능성이 희박하거나 가능성이 없을 수도 있으며 방금 경고를 본 것처럼 컴퓨터의 수학적 한계에 도달할 가능성이 높다는 것을 의미합니다.
하지만 이 데이터 세트에서 학습율로0.01을 시도하면 학습 프로세스가 훨씬 느려지더라도 문제가 발생하지 않지만 만약 이 dataset에 이 학습 속도를 사용하면 수학적 한계에 도달하게 될 것입니다. 이제 우리는 모든 데이터 세트에 학습율이 있다는 것을 알고 있지만 때로는 여러 변수가 있는 데이터 세트와 복잡한 문제가 있기 때문에 학습율을 최적화할 기회가 없을 수도 있습니다. 이는 전체 프로세스를 수행하는 비효율적인 방법입니다.
이 모든 것에 대한 해결책은 전체 데이터 세트를 정규화 하여 동일한 척도에 있게 하는 것입니다. 이렇게 하면 동일한 축에 값을 그릴 때 가독성이 향상 되고 정규화된 값이 일반적으로0부터 1까지의 범위에 있기 때문에훈련 시간이 향상됩니다. 학습율0.01과 같이 학습율 매개변수가 하나만 있으면 모든 데이터 세트에 사용할 수 있기 때문에 더 이상 학습율에 대해 걱정할 필요가 없습니다. 정규화에 대해 자세히 알고 싶으시다면 여기를 읽어보세요.
마지막으로 중요한 것은
우리는 급여 데이터 값이 평균39,343에서 121,782 인 반면 경력 년수는 1.1에서 10.5까지라는 것을 알고 있습니다. 이러한 방식으로 데이터를 유지하면 급여 값이 엄청나게 되고 모델은 급여가 더 중요하다고 여기게 될 수 있습니다. 그렇게 되면 급여가 경험에 비해 더 큰 영향을 미치게 됩니다. 다른 변수와 동일한 영향을 미치게 하려면 독립 변수가 필요합니다. 이제 값을 정규화 하는 것이 얼마나 중요한지 알 수 있을 것입니다.
(정규화) 최소-최대 스칼라
이 접근 방식에서는 데이터를0과 1범위 내로 정규화 합니다. 공식은 아래와 같습니다:
이 공식을 MQL5의 코드로 변환하면 다음과 같습니다:
void CGradientDescent::MinMaxScaler(double &Array[]) { double mean = Mean(Array); double max,min; double Norm[]; ArrayResize(Norm,ArraySize(Array)); max = Array[ArrayMaximum(Array)]; min = Array[ArrayMinimum(Array)]; for (int i=0; i<ArraySize(Array); i++) Norm[i] = (Array[i] - min) / (max - min); printf("Scaled data Mean = %.5f Std = %.5f",Mean(Norm),std(Norm)); ArrayFree(Array); ArrayCopy(Array,Norm); }
std()함수는 데이터가 정규화 된 후 표준 편차를 알려주기 위한 것입니다. 코드는 다음과 같습니다:
double CGradientDescent::std(double &data[]) { double mean = Mean(data); double sum = 0; for (int i=0; i<ArraySize(data); i++) sum += MathPow(data[i] - mean,2); return(MathSqrt(sum/ArraySize(data))); }
이제 이 모든 것을 호출하고 출력을 인쇄하여 어떻게 되는지 살펴보겠습니다:
void OnStart() { //--- string filename = "Salary_Data.csv"; double XMatrix[]; double YMatrix[]; grad = new CGradientDescent(1, 0.01,1000); grad.ReadCsvCol(filename,1,XMatrix); grad.ReadCsvCol(filename,2,YMatrix); grad.MinMaxScaler(XMatrix); grad.MinMaxScaler(YMatrix); ArrayPrint("Normalized X",XMatrix); ArrayPrint("Normalized Y",YMatrix); grad.GradientDescentFunction(XMatrix,YMatrix,MSE); delete (grad); }
출력:
OK 0 18:50:53.387 gradient-descent test (EURUSD,M1) Scaled data Mean = 0.44823 Std = 0.29683 MG 0 18:50:53.387 gradient-descent test (EURUSD,M1) Scaled data Mean = 0.45207 Std = 0.31838 MP 0 18:50:53.387 gradient-descent test (EURUSD,M1) Normalized X JG 0 18:50:53.387 gradient-descent test (EURUSD,M1) [ 0] 0.0000 0.0213 0.0426 0.0957 0.1170 0.1915 0.2021 0.2234 0.2234 0.2766 0.2979 0.3085 0.3085 0.3191 0.3617 ER 0 18:50:53.387 gradient-descent test (EURUSD,M1) [15] 0.4043 0.4255 0.4468 0.5106 0.5213 0.6064 0.6383 0.7234 0.7553 0.8085 0.8404 0.8936 0.9043 0.9787 1.0000 NQ 0 18:50:53.387 gradient-descent test (EURUSD,M1) Normalized Y IF 0 18:50:53.387 gradient-descent test (EURUSD,M1) [ 0] 0.0190 0.1001 0.0000 0.0684 0.0255 0.2234 0.2648 0.1974 0.3155 0.2298 0.3011 0.2134 0.2271 0.2286 0.2762 IS 0 18:50:53.387 gradient-descent test (EURUSD,M1) [15] 0.3568 0.3343 0.5358 0.5154 0.6639 0.6379 0.7151 0.7509 0.8987 0.8469 0.8015 0.9360 0.8848 1.0000 0.9939
이제 그래프는 다음과 같이 표시됩니다:
로지스틱 회귀를 위한 경사 하강법
경사 하강법의 리니어 측면을 살펴보았으므로 이제 로지스틱 측면을 살펴보겠습니다.
여기서 우리는 선형 회귀 부분에서 수행한 것과 동일한 프로세스를 수행합니다. 로지스틱 회귀가 선형 모델의 프로세스보다 더 복잡하다는 사실 이외 관련된 프로세스가 완전히 동일합니다. 먼저 비용 함수를 살펴보겠습니다.
로지스틱 회귀 모델의 비용 함수는 아래 주어진 Binary Cross Entropy AKA Log Loss입니다. 우리는 이미 로지스틱 회귀와 관련한 시리즈의 두 번째 기사에서 샆펴본 적이 있습니다.
이제 어려운 부분을 먼저 해봅시다. 이 함수를 미분하여 기울기를 얻습니다.
미분 계수를 찾은 후
비용 함수 의 미분
Binary Cross Entropy를 나타내는 BCE 함수 내에서 수식을 MQL5 코드로 변환해 보겠습니다.
double CGradientDescent::Bce(double Bo,double B1,Beta wrt) { double sum_sqr=0; double m = ArraySize(Y); double x[]; MatrixColumn(m_XMatrix,x,2); if (wrt == Slope) for (int i=0; i<ArraySize(Y); i++) { double Yp = Sigmoid(Bo+B1*x[i]); sum_sqr += (Y[i] - Yp) * x[i]; } if (wrt == Intercept) for (int i=0; i<ArraySize(Y); i++) { double Yp = Sigmoid(Bo+B1*x[i]); sum_sqr += (Y[i] - Yp); } return((-1/m)*sum_sqr); }
분류 모델을 다루기 때문에 선택한 데이터 세트는 로지스틱 회귀에서 사용한 Titanic 데이터 세트입니다. 우리의 독립 변수는Pclass(Passenger class)이고 종속 변수는 Survived입니다.
분류된 산점도
이제 경사 하강법 클래스를 호출할 것이지만 이번에는BCE(Binary Cross Entropy)를 비용 함수로 사용합니다.
filename = "titanic.csv"; ZeroMemory(XMatrix); ZeroMemory(YMatrix); grad.ReadCsvCol(filename,3,XMatrix); grad.ReadCsvCol(filename,2,YMatrix); grad.GradientDescentFunction(XMatrix,YMatrix,BCE); delete (grad);
결과를 봅시다:
CP 0 07:19:08.906 gradient-descent test (EURUSD,M1) Gradient Descent CostFunction BCE KD 0 07:19:08.906 gradient-descent test (EURUSD,M1) 0 b0 = -0.01161616 cost_B0 = 0.11616162 B1 = -0.04057239 cost_B1 = 0.40572391 FD 0 07:19:08.906 gradient-descent test (EURUSD,M1) 1 b0 = -0.02060337 cost_B0 = 0.08987211 B1 = -0.07436893 cost_B1 = 0.33796541 KE 0 07:19:08.906 gradient-descent test (EURUSD,M1) 2 b0 = -0.02743120 cost_B0 = 0.06827832 B1 = -0.10259883 cost_B1 = 0.28229898 QE 0 07:19:08.906 gradient-descent test (EURUSD,M1) 3 b0 = -0.03248925 cost_B0 = 0.05058047 B1 = -0.12626640 cost_B1 = 0.23667566 EE 0 07:19:08.907 gradient-descent test (EURUSD,M1) 4 b0 = -0.03609603 cost_B0 = 0.03606775 B1 = -0.14619252 cost_B1 = 0.19926123 CF 0 07:19:08.907 gradient-descent test (EURUSD,M1) 5 b0 = -0.03851035 cost_B0 = 0.02414322 B1 = -0.16304363 cost_B1 = 0.16851108 MF 0 07:19:08.907 gradient-descent test (EURUSD,M1) 6 b0 = -0.03994229 cost_B0 = 0.01431946 B1 = -0.17735996 cost_B1 = 0.14316329 JG 0 07:19:08.907 gradient-descent test (EURUSD,M1) 7 b0 = -0.04056266 cost_B0 = 0.00620364 B1 = -0.18958010 cost_B1 = 0.12220146 HE 0 07:19:08.907 gradient-descent test (EURUSD,M1) 8 b0 = -0.04051073 cost_B0 = -0.00051932 B1 = -0.20006123 cost_B1 = 0.10481129 ME 0 07:19:08.907 gradient-descent test (EURUSD,M1) 9 b0 = -0.03990051 cost_B0 = -0.00610216 B1 = -0.20909530 cost_B1 = 0.09034065 JQ 0 07:19:08.907 gradient-descent test (EURUSD,M1) 10 b0 = -0.03882570 cost_B0 = -0.01074812 B1 = -0.21692190 cost_B1 = 0.07826600 <<<<<< Last 10 iterations >>>>>> FN 0 07:19:09.725 gradient-descent test (EURUSD,M1) 6935 b0 = 1.44678930 cost_B0 = -0.00000001 B1 = -0.85010666 cost_B1 = 0.00000000 PN 0 07:19:09.725 gradient-descent test (EURUSD,M1) 6936 b0 = 1.44678931 cost_B0 = -0.00000001 B1 = -0.85010666 cost_B1 = 0.00000000 NM 0 07:19:09.726 gradient-descent test (EURUSD,M1) 6937 b0 = 1.44678931 cost_B0 = -0.00000001 B1 = -0.85010666 cost_B1 = 0.00000000 KL 0 07:19:09.726 gradient-descent test (EURUSD,M1) 6938 b0 = 1.44678931 cost_B0 = -0.00000001 B1 = -0.85010666 cost_B1 = 0.00000000 PK 0 07:19:09.726 gradient-descent test (EURUSD,M1) 6939 b0 = 1.44678931 cost_B0 = -0.00000001 B1 = -0.85010666 cost_B1 = 0.00000000 RK 0 07:19:09.726 gradient-descent test (EURUSD,M1) 6940 b0 = 1.44678931 cost_B0 = -0.00000001 B1 = -0.85010666 cost_B1 = 0.00000000 MJ 0 07:19:09.726 gradient-descent test (EURUSD,M1) 6941 b0 = 1.44678931 cost_B0 = -0.00000001 B1 = -0.85010666 cost_B1 = 0.00000000 HI 0 07:19:09.726 gradient-descent test (EURUSD,M1) 6942 b0 = 1.44678931 cost_B0 = -0.00000001 B1 = -0.85010666 cost_B1 = 0.00000000 CH 0 07:19:09.726 gradient-descent test (EURUSD,M1) 6943 b0 = 1.44678931 cost_B0 = -0.00000001 B1 = -0.85010666 cost_B1 = 0.00000000 MH 0 07:19:09.727 gradient-descent test (EURUSD,M1) 6944 b0 = 1.44678931 cost_B0 = -0.00000001 B1 = -0.85010666 cost_B1 = 0.00000000 QG 0 07:19:09.727 gradient-descent test (EURUSD,M1) 6945 b0 = 1.44678931 cost_B0 = -0.00000000 B1 = -0.85010666 cost_B1 = 0.00000000 NG 0 07:19:09.727 gradient-descent test (EURUSD,M1) 6945 Iterations Local Minima are MJ 0 07:19:09.727 gradient-descent test (EURUSD,M1) B0(Intercept) = 1.44679 || B1(Coefficient) = -0.85011
선형 회귀에서는 분류된 데이터를 정규화 하거나 확장하지만 로지스틱 회귀에서는 그렇지 않습니다.
여기 가장 중요한 두 가지 머신 러닝 모델에 대한 경사 하강법이 있습니다. 이해하기 쉽고 유용한 Python 코드가 되었으면 좋겠습니다. 데이터 세트는 이 GitHub에 연결되어 있습니다. Gradient-Descent-MQL5 저장소 .
결론
우리는 하나의 독립 변수와 하나의 종속 변수에 대한 경사 하강법을 보았습니다. 여러 독립 변수에 대해서라면 벡터/행렬 형태의 방정식을 사용해야 합니다. 그리 어렵지는 않을 것입니다. 우리에게는 최근 MQL5에서 출시한 행렬용 라이브러리가 있습니다. 행렬에 대한 도움이 필요하시면 언제든지 저에게 연락해 주세요. 기꺼이 도와드리겠습니다.
감사합니다
미적분에 대해 더 알아보려면:
- https://www.youtube.com/watch?v=5yfh5cf4-0w
- https://www.youtube.com/watch?v=yg_497u6JnA
- https://www.youtube.com/watch?v=HaHsqDjWMLU
MetaQuotes 소프트웨어 사를 통해 영어가 번역됨
원본 기고글: https://www.mql5.com/en/articles/11200