Table of Contents
Gradient Descent
task: y hat = a + b*x 의 regression 에서 a 와 b를 구하기
- regressin line으로 이루어지는 에측치로 결과되는 오차의 제곱의 합은 (sum of square residuals, ssr 혹은 sse) 최소값이 되어야 한다.
- 방법 1. (버릴 방법)
- 우선 b를 안다고 하고 정해두면 (가령 -2.4와 같이 – 비현실적이지만)
- 예측할 수 있는 a값의 range를 두고
- 하나씩 대입하여 그 때의 sum of square residual 을 (ssr 혹은 sse) 구해서 기록한다.
- 이때 우리는 sse값이 ()^2의 형태를 띄기 때문에 알파벳 U 형태를 띄는 것을 안다.
- 따라서 이 sse 그래프의 최소값이 될 때의 a값이 무엇인가를 구해보면 된다.
- 아래 r script는 이런 방법으로 구해 본것인데 아래처럼 두가지 단점이 있다.
- 우선 정확한 b값을 알 수는 없다.
- a 값을 장님 문고리 잡듯이 -40에서 40 사이의 점수를 0.1씩 증가시켜 보는 것이 너무 비효율적이다.
- 더불어 이렇게 구한 a값은 1/10 단위의 숫자를 구하게 되지 정확한 a값을 구하는 것은 아니다 (예를 들면 1.4로 a값을 구했는데 정확한 값은 1.38976 일 수도 있다.
rs01
library(ggplot2)
library(ggpmisc)
library(tidyverse)
library(data.table)
library(MASS)
# settle down
rm(list=ls())
rnorm2 <- function(n,mean,sd) {
mean + sd * scale(rnorm(n))
}
ss <- function(x) {
sum((x-mean(x))^2)
}
sp <- function(x, y) {
sum((x-mean(x))*(y-mean(y)))
}
# 1. mean of three variables
# iq, allowance, gpa
# x, x2, y
means <- c(108, 42, 3.2)
# allowance, iq, gpa
sds <- c(11, 8, 0.4) # standard deviations
# correlation matrix. note that correlation
# between v1 and v2 is near none (0.05)
corr_matrix <- matrix(c(1, 0.05, 0.4,
0.05, 1, 0.2,
0.4, 0.2, 1),
nrow = 3) # Target correlation matrix
# 2. covariance matrix
# diagonal matrix of SDs
sd_diag <- diag(sds)
sd_diag
# Calculate covariance matrix
cov_matrix <- sd_diag %*% corr_matrix %*% sd_diag
# 3. population data
# set.seed(32)
set.seed(432)
# n_pop <- 100000
# pop <- mvrnorm(n = n_pop, mu = means, Sigma = cov_matrix)
# pop <- as.data.frame(pop)
# colnames(pop) <- c("x", "x2", "y")
# cor(pop)
# n_sam <- 100
# sam <- pop |> slice_sample(n = n_sam, replace = T)
# head(sam)
# cor(sam)
n_sam <- 100
sam <- mvrnorm(n = n_sam, mu = means, Sigma = cov_matrix)
sam <- as.data.frame(sam)
colnames(sam) <- c("x", "x2", "y")
cor(sam)
y <- sam$y
x <- sam$x
x2 <- sam$x2
# check with regression
mo <- lm(y ~ x, data = sam)
summary(mo)
# graph
ggplot(data = sam, aes(x = x, y = y)) +
geom_point() +
stat_poly_line() +
stat_poly_eq(use_label(c("eq", "R2"))) +
theme_classic()
a <- summary(mo)$coefficient[1]
b <- summary(mo)$coefficient[2]
cat(a, b)
# We know what b and a are from the proof
bc <- sp(y, x)/ss(x)
ac <- mean(y) - bc * mean(x)
cat(ac, bc)
# but,
# finding a with b being fixed
# set.seed(191)
# Initialize random betas
# 우선 b를 고정하고 a만
# 변화시켜서 이해
b <- summary(mo)$coefficients[2] # 원래 b값
a <- 0
b.init <- b
a.init <- a
b.init
a.init
# Predict function:
predict <- function(x, a, b){
return (a + b * x)
}
# we use sum of square of error which oftentimes become big
sseloss<- function(predictions, y) {
residuals <- (y - predictions)
return(sum(residuals^2))
}
sses <- c() # for sum of square residuals
as <- c() # for as (intercepts)
summary(x)
for (i in seq(from = -40, to = 40, by = 0.01)) {
pred <- predict(x, i, b)
sse <- sseloss(pred, y)
sses <- append(sses, sse)
as <- append(as, i)
}
length(sses)
length(as)
min(sses)
max(sses)
min.pos.sses <- which(sses == min(sses))
min.pos.sses
print(as[min.pos.sses])
summary(mo)
plot(as, sses, type='l', lwd=2)
abline(v=as[min.pos.sses])
text(x = as[min.pos.sses], y = median(sses), col='red',
labels = paste(" sse = ", round(min(sses),4),
"\n is minimum value
when a =", as[min.pos.sses]),
pos=4)
ro01
> library(ggplot2)
> library(ggpmisc)
> library(tidyverse)
> library(data.table)
> library(MASS)
>
> # settle down
> rm(list=ls())
>
> rnorm2 <- function(n,mean,sd) {
+ mean + sd * scale(rnorm(n))
+ }
> ss <- function(x) {
+ sum((x-mean(x))^2)
+ }
> sp <- function(x, y) {
+ sum((x-mean(x))*(y-mean(y)))
+ }
>
> # 1. mean of three variables
> # iq, allowance, gpa
> # x, x2, y
> means <- c(108, 42, 3.2)
>
> # allowance, iq, gpa
> sds <- c(11, 8, 0.4) # standard deviations
> # correlation matrix. note that correlation
> # between v1 and v2 is near none (0.05)
> corr_matrix <- matrix(c(1, 0.05, 0.4,
+ 0.05, 1, 0.2,
+ 0.4, 0.2, 1),
+ nrow = 3) # Target correlation matrix
> # 2. covariance matrix
> # diagonal matrix of SDs
> sd_diag <- diag(sds)
> sd_diag
[,1] [,2] [,3]
[1,] 11 0 0.0
[2,] 0 8 0.0
[3,] 0 0 0.4
>
> # Calculate covariance matrix
> cov_matrix <- sd_diag %*% corr_matrix %*% sd_diag
>
> # 3. population data
> # set.seed(32)
> set.seed(432)
> # n_pop <- 100000
> # pop <- mvrnorm(n = n_pop, mu = means, Sigma = cov_matrix)
> # pop <- as.data.frame(pop)
> # colnames(pop) <- c("x", "x2", "y")
> # cor(pop)
>
> # n_sam <- 100
> # sam <- pop |> slice_sample(n = n_sam, replace = T)
> # head(sam)
> # cor(sam)
>
> n_sam <- 100
> sam <- mvrnorm(n = n_sam, mu = means, Sigma = cov_matrix)
> sam <- as.data.frame(sam)
> colnames(sam) <- c("x", "x2", "y")
> cor(sam)
x x2 y
x 1.0000000 0.1880415 0.4143930
x2 0.1880415 1.0000000 0.3373768
y 0.4143930 0.3373768 1.0000000
>
>
> y <- sam$y
> x <- sam$x
> x2 <- sam$x2
>
> # check with regression
> mo <- lm(y ~ x, data = sam)
> summary(mo)
Call:
lm(formula = y ~ x, data = sam)
Residuals:
Min 1Q Median 3Q Max
-0.92770 -0.20715 0.03368 0.20038 0.90512
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.614428 0.344622 4.685 9.04e-06 ***
x 0.014476 0.003212 4.508 1.82e-05 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.3346 on 98 degrees of freedom
Multiple R-squared: 0.1717, Adjusted R-squared: 0.1633
F-statistic: 20.32 on 1 and 98 DF, p-value: 1.818e-05
>
> # graph
> ggplot(data = sam, aes(x = x, y = y)) +
+ geom_point() +
+ stat_poly_line() +
+ stat_poly_eq(use_label(c("eq", "R2"))) +
+ theme_classic()
>
> a <- summary(mo)$coefficient[1]
> b <- summary(mo)$coefficient[2]
> cat(a, b)
1.614428 0.01447618> # We know what b and a are from the proof
> bc <- sp(y, x)/ss(x)
> ac <- mean(y) - bc * mean(x)
> cat(ac, bc)
1.614428 0.01447618>
> # but,
> # finding a with b being fixed
> # set.seed(191)
> # Initialize random betas
> # 우선 b를 고정하고 a만
> # 변화시켜서 이해
> b <- summary(mo)$coefficients[2] # 원래 b값
> a <- 0
>
> b.init <- b
> a.init <- a
> b.init
[1] 0.01447618
> a.init
[1] 0
>
> # Predict function:
> predict <- function(x, a, b){
+ return (a + b * x)
+ }
>
> # we use sum of square of error which oftentimes become big
> sseloss<- function(predictions, y) {
+ residuals <- (y - predictions)
+ return(sum(residuals^2))
+ }
>
> sses <- c() # for sum of square residuals
> as <- c() # for as (intercepts)
> summary(x)
Min. 1st Qu. Median Mean 3rd Qu. Max.
87.12 98.44 106.27 106.80 114.62 133.33
> for (i in seq(from = -40, to = 40, by = 0.01)) {
+ pred <- predict(x, i, b)
+ sse <- sseloss(pred, y)
+ sses <- append(sses, sse)
+ as <- append(as, i)
+ }
> length(sses)
[1] 8001
> length(as)
[1] 8001
>
> min(sses)
[1] 10.97429
> max(sses)
[1] 173187
> min.pos.sses <- which(sses == min(sses))
> min.pos.sses
[1] 4162
> print(as[min.pos.sses])
[1] 1.61
> summary(mo)
Call:
lm(formula = y ~ x, data = sam)
Residuals:
Min 1Q Median 3Q Max
-0.92770 -0.20715 0.03368 0.20038 0.90512
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.614428 0.344622 4.685 9.04e-06 ***
x 0.014476 0.003212 4.508 1.82e-05 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.3346 on 98 degrees of freedom
Multiple R-squared: 0.1717, Adjusted R-squared: 0.1633
F-statistic: 20.32 on 1 and 98 DF, p-value: 1.818e-05
> plot(as, sses, type='l', lwd=2)
> abline(v=as[min.pos.sses])
> text(x = as[min.pos.sses], y = median(sses), col='red',
+ labels = paste(" sse = ", round(min(sses),4),
+ "\n is minimum value
+ when a =", as[min.pos.sses]),
+ pos=4)
>


위의 두번째 그래프는 a값이 -40 에서 40 까지 0.1 단위로 변할 때의 sse값을 구한 후에 이를 기록하여 그래프로 만든 것이다. 이렇게 구한 sse 값들 중 최소값일 때의 a값을 regression의 a값으로 추정한 것이다. 이렇게 해서 구한 값은 summary(mo)에서의 a와 값과 같다.
SSE 대신에 MSE를 쓰기
위에서 sse값을 저장해서 그 중에 최소값이 13.98253 임을 알게 된것이다. 그러나 이 계산은 각각의 sse값이 아주 크게 되는 경우가 많다.
> min(sses)
[1] 13.98253
> max(sses)
[1] 180081.3
따라서 sse 대신에 mse 값을 구해서 저장한다. mse = sse 를 n으로 나눈 값 (mean square error (residual)).
rs.01
#####
# with mean square error (mse) instead of sse
b <- summary(mo)$coefficients[2]
a <- 0
# we use sum of square of error which oftentimes become big
mseloss <- function(predictions, y) {
residuals <- (y - predictions)
return(mean(residuals^2))
}
mses <- c() # for sum of square residuals
as <- c() # for as (intercepts)
for (i in seq(from = -40, to = 40, by = 0.01)) {
pred <- predict(x, i, b)
mse <- mseloss(pred, y)
mses <- append(mses, mse)
as <- append(as, i)
}
length(mses)
length(as)
min(mses)
max(mses)
min.pos.mses <- which(mses == min(mses))
min.pos.mses
print(as[min.pos.mses])
summary(mo)
plot(as, mses, type='l', lwd=2)
abline(v=as[min.pos.mses])
text(x = as[min.pos.mses], y = median(mses), col='red',
labels = paste(" mse = ", round(min(mses),4),
"\n is minimum value
when a =", as[min.pos.mses]),
pos=4)
ro.02
> #####
> # with mean square error (mse) instead of sse
>
> b <- summary(mo)$coefficients[2]
> a <- 0
>
> # we use sum of square of error which oftentimes become big
> mseloss <- function(predictions, y) {
+ residuals <- (y - predictions)
+ return(mean(residuals^2))
+ }
>
> mses <- c() # for sum of square residuals
> as <- c() # for as (intercepts)
>
> for (i in seq(from = -40, to = 40, by = 0.01)) {
+ pred <- predict(x, i, b)
+ mse <- mseloss(pred, y)
+ mses <- append(mses, mse)
+ as <- append(as, i)
+ }
> length(mses)
[1] 8001
> length(as)
[1] 8001
>
> min(mses)
[1] 0.1097429
> max(mses)
[1] 1731.87
> min.pos.mses <- which(mses == min(mses))
> min.pos.mses
[1] 4162
> print(as[min.pos.mses])
[1] 1.61
> summary(mo)
Call:
lm(formula = y ~ x, data = sam)
Residuals:
Min 1Q Median 3Q Max
-0.92770 -0.20715 0.03368 0.20038 0.90512
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.614428 0.344622 4.685 9.04e-06 ***
x 0.014476 0.003212 4.508 1.82e-05 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.3346 on 98 degrees of freedom
Multiple R-squared: 0.1717, Adjusted R-squared: 0.1633
F-statistic: 20.32 on 1 and 98 DF, p-value: 1.818e-05
> plot(as, mses, type='l', lwd=2)
> abline(v=as[min.pos.mses])
> text(x = as[min.pos.mses], y = median(mses), col='red',
+ labels = paste(" mse = ", round(min(mses),4),
+ "\n is minimum value
+ when a =", as[min.pos.mses]),
+ pos=4)
>
>
b값 구하기
이제는 a값을 고정하고 b값도 같은 방식으로 구해볼 수 있다
rs01
##############################################
# b값도 범위를 추측한 후에 0.01씩 증가시키면서
# 각 b값에서 mse값을 구해본후 가장 작은 값을
# 가질 때의 b값을 구하면 된다.
# 그러나 b값의 적절한 구간을 예측하는 것이
# 불가능하다 (그냥 추측뿐)
# 위의 y 데이터에서 y = 314*x + rnorm(. . .)
# 이라면 -30-30 구간은 적절하지 않은 구간이 된다.
# 더우기 a값을 정확히 알아야 b값을 추출할 수 있다.
# 이는 적절한 방법이 아니다.
b <- 1
a <- summary(mo)$coefficients[1]
b.init <- b
a.init <- a
# Predict function:
predict <- function(x, a, b){
return (a + b * x)
}
# we use sum of square of error which oftentimes become big
mseloss <- function(predictions, y) {
residuals <- (y - predictions)
return(mean(residuals^2))
}
mses <- c()
bs <- c()
for (i in seq(from = -40, to = 40, by = 0.01)) {
pred <- predict(x, b, i)
mse <- mseloss(pred, y)
mses <- append(mses, mse)
bs <- append(bs,i)
}
min(mses)
max(mses)
min.pos.mses <- which(mses == min(mses))
print(bs[min.pos.mses])
summary(mo)
plot(bs, mses, type='l', lwd=2)
abline(v=bs[min.pos.mses])
text(x = bs[min.pos.mses], y = median(mses), col='red',
labels = paste(" mse = ", round(min(mses),4),
"\n is minimum value
when b =", round(bs[min.pos.mses],4)),
pos=4)
ro01
> ##############################################
> # b값도 범위를 추측한 후에 0.01씩 증가시키면서
> # 각 b값에서 mse값을 구해본후 가장 작은 값을
> # 가질 때의 b값을 구하면 된다.
> # 그러나 b값의 적절한 구간을 예측하는 것이
> # 불가능하다 (그냥 추측뿐)
> # 위의 y 데이터에서 y = 314*x + rnorm(. . .)
> # 이라면 -30-30 구간은 적절하지 않은 구간이 된다.
> # 더우기 a값을 정확히 알아야 b값을 추출할 수 있다.
> # 이는 적절한 방법이 아니다.
>
> b <- 1
> a <- summary(mo)$coefficients[1]
>
> b.init <- b
> a.init <- a
>
> # Predict function:
> predict <- function(x, a, b){
+ return (a + b * x)
+ }
>
> # we use sum of square of error which oftentimes become big
> mseloss <- function(predictions, y) {
+ residuals <- (y - predictions)
+ return(mean(residuals^2))
+ }
>
> mses <- c()
> bs <- c()
>
> for (i in seq(from = -40, to = 40, by = 0.01)) {
+ pred <- predict(x, b, i)
+ mse <- mseloss(pred, y)
+ mses <- append(mses, mse)
+ bs <- append(bs,i)
+ }
>
> min(mses)
[1] 0.1136351
> max(mses)
[1] 18442152
> min.pos.mses <- which(mses == min(mses))
> print(bs[min.pos.mses])
[1] 0.02
> summary(mo)
Call:
lm(formula = y ~ x, data = sam)
Residuals:
Min 1Q Median 3Q Max
-0.92770 -0.20715 0.03368 0.20038 0.90512
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.614428 0.344622 4.685 9.04e-06 ***
x 0.014476 0.003212 4.508 1.82e-05 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.3346 on 98 degrees of freedom
Multiple R-squared: 0.1717, Adjusted R-squared: 0.1633
F-statistic: 20.32 on 1 and 98 DF, p-value: 1.818e-05
> plot(bs, mses, type='l', lwd=2)
> abline(v=bs[min.pos.mses])
> text(x = bs[min.pos.mses], y = median(mses), col='red',
+ labels = paste(" mse = ", round(min(mses),4),
+ "\n is minimum value
+ when b =", round(bs[min.pos.mses],4)),
+ pos=4)
>
a와 b를 동시에 구할 수 있는 방법은 없을까? 위의 방법으로는 어렵다. 일반적으로 우리는 a와 b값이 무엇이되는가를 미분을 이용해서 구할 수 있었다. R에서 미분의 해를 구하기 보다는 해에 접근하도록 하는 프로그래밍을 써서 a와 b의 근사값을 구한다. 이것을 gradient descent라고 부른다.
Gradient descend
위에서 a값이 무엇일 때 mse값이 최소가 될까를 봐서 이 때의 a값을 실제 $y = a + bx$ 의 a 값으로 삼았다. 이 때 a값의 추정을 위해서
seq(-10, 10, 0.01) 의 범위와 증가값을 가지고 일일이 대입하여 mse를 구아였다.
위에서의 0.01씩 증가시켜 대입하는 것이 아니라 처음 한 숫자에서 시작한 후 그 다음 숫자를 정한 후에 점진적으로 그 숫자 간격을 줄여가면서 보면 정율적으로 0.01씩 증가시키는 것 보다 효율적일 것 같다. 이 증가분을 구하기 위해서 미분을 사용한다.
점차하강 = 조금씩 깍아서 원하는 기울기 (미분값) 찾기
prerequisite:
표준편차 추론에서 평균을 사용하는 이유: 실험적_수학적_이해
deriviation of a and b in a simple regression
위의 문서는 a, b에 대한 값을 미분법을 이용해서 직접 구하였다. 컴퓨터로는 이렇게 하기가 쉽지 않다. 그렇다면 이 값을 반복계산을 이용해서 추출하는 방법은 없을까? gradient descent
\begin{eqnarray*}
\text{for a (constant)} \\
\\
\text{SSE} & = & \text{Sum of Square Residuals} \\
\text{Residual} & = & (Y_i - (a + bX_i)) \\
\\
\frac{\text{dSSE}}{\text{da}}
& = & \frac{\text{dResidual^2}}{\text{dResidual}} * \frac{\text{dResidual}}{\text{da}} \\
& = & 2 * \text{Residual} * \dfrac{\text{d}}{\text{da}} (Y_i - (a+bX_i)) \\
& \because & \dfrac{\text{d}}{\text{da}} (Y_i - (a+bX_i)) = -1 \\
& = & 2 * \sum{(Y_i - (a + bX_i))} * -1 \\
& = & -2 *\sum{\text{residual}} \\
& .. & -2 \frac{\sum{\text{residual}}}{n} \\
& = & -2 * \overline{\text{residual}} \\
\end{eqnarray*}
위 미분결과는 주어진 Xi값에서 얻는 a값을 의미한다.
아래 R code에서 gradient function을 참조.
\begin{eqnarray*} \text{for b, (coefficient)} \\ \\ \dfrac{\text{d}}{\text{db}} \sum{(Y_i - (a + bX_i))^2} & = & \sum{\dfrac{\text{dResidual}^2}{\text{db}}} \\ & = & \sum{\dfrac{\text{dResidual}^2}{\text{dResidual}}*\dfrac{\text{dResidual}}{\text{db}} } \\ & = & \sum{2*\text{Residual} * \dfrac{\text{dResidual}}{\text{db}} } \\ & = & \sum{2*\text{Residual} * (-X_i) } \;\;\;\; \\ & \because & \dfrac{\text{dResidual}}{\text{db}} = (Y_i - (a+bX_i)) = -X_i \\ & = & -2 X_i \sum{(Y_i - (a + bX_i))} \\ & = & -2 * X_i * \sum{\text{residual}} \\ & .. & -2 * X_i * \frac{\sum{\text{residual}}}{n} \\ & = & -2 * \overline{X_i * \text{residual}} \\ \end{eqnarray*}
위의 미분결과는 주어진 Xi 값에서의 b값을 즉 기울기 값을 구하것을 의미한다.
위의 설명은 Sum of Square값을 미분하는 것을 전제로 하였지만, Mean Square 값을 (Sum of Square값을 N으로 나눈 것) 대용해서 이해할 수도 있다. 아래의 code는 (미분을 이해한다는 것을 전제로) b값과 a값이 변할 때 msr (mean square residual) 값이 어떻게 변하는가를 알려주는 것이다.
gradient <- function(x, y, predictions){
error = y - predictions
db = -2 * mean(x * error)
da = -2 * mean(error)
return(list("b" = db, "a" = da))
}
위 펑션으로 얻은 da와 db값을 초기에 설정한 a, b 값에 더해 준 값을 다시 a, b값으로 하여 gradient 펑션을 통해서 다시 db, da값을 구하고 이를 다시 이전 단계에서 구한 a, b값에 더하여 그 값을 다시 a, b값을 하여 . . . .
위를 반복한다. 단, db값과 da값을 그냥 대입하기 보다는 초기에 설정한 learning.rate값을 (0.01 예를 들면) 곱하여 구한 값을 더하게 된다. 이것이 아래의 code이다.
a 와 b 값을 gradient descent 방법을 이용하여 한꺼번에 구하기
rs01
# 아래는 a 와 b 를 랜덤하게 정한 후 (rnorm)
# 두 가지 일을 하게 된다. 첫 째는
# 이 때의 mse값을 저장한다. 둘째는
# a, b 값을 가질 때의 a 와 b에 대한 미분 값을
# 구한 후, 이 값에 1보다 작은 값을 곱하여 (learning rate)
# 구한 값을 다음의 a 와 b 값으로 써서 다시
# 이를 대입하여 mse값을 구하고 이 때의 미분 값을
# 구한다. 이 미분하여 구한 a, b값을 저장한 후에
# 다시 learning rate값을 곱하여 이를 다음의 a, b
# 값으로 사용한다. . . . 이를 반복한다.
a <- rnorm(1)
b <- rnorm(1)
a.init <- a
b.init <- b
# 이 때의 db, da는 무슨 값인가?
# 미분결과값이므로 db는 기울기값
# da는 그 당시의 a값
gradient <- function(x, y, predictions){
error = y - predictions
db = -2 * mean(x * error)
da = -2 * mean(error)
return(list("b" = db, "a" = da))
# return(c(db, da))
}
mseloss <- function(predictions, y) {
residuals <- (y - predictions)
return(mean(residuals^2))
}
# Train the model with scaled features
learning.rate = 0.1
# Record Loss for each epoch:
as = c()
bs = c()
das = c()
dbs = c()
ep <- c()
mses = c()
zx <- (x-mean(x))/sd(x)
nlen <- 75
for (epoch in 1:nlen) {
predictions <- predict(zx, a, b)
#residual <- residuals(predictions, y)
loss <- mseloss(predictions, y)
mses <- append(mses, loss)
grad <- gradient(zx, y, predictions)
db <- grad$b
da <- grad$a
dbs <- append(dbs, db)
das <- append(das, da)
ep <- append(ep, epoch)
step.b <- grad$b * learning.rate
step.a <- grad$a * learning.rate
b <- b-step.b
a <- a-step.a
as <- append(as, a)
bs <- append(bs, b)
}
tmp <- data.frame(ep, das, as, dbs, bs, mse)
tmp
# 위의 루프를 이해했는지 체크하기
a.init
b.init
tmp.p <- predict(zx, a.init, b.init)
# a.init b.init 일 때의 미분 결과
# 즉, 기울기와 절편 값
tmp.g <- gradient(zx, y, tmp.p)
tmp.g
# 이 값에 learning rate 값을 곱한 후에
a.step <- tmp.g$a*learning.rate
b.step <- tmp.g$b*learning.rate
# 이를 원래 a값에서 빼준 값을 다음 순서의
a.init <- a.init-a.step
b.init <- b.init-b.step
# a, b값으로 쓰고, 이 때의 미분 값을 구한 후에
# (루프 안에서), 미분 결과를 다시 learning rate
# 로 곱해 준 값을 (두번째 단계의) a, b 값에서
# 빼 준 값을 다음 단계의 a, b값으로 쓰고, 다시
# . . . . . . 위의 loop문은 이것을 75번 반복한 것
# scaled
# 이렇게 해서 구한 제일 마지막 a, b 값은 x 변인 대신에
# 표준화한 zx 변인을 사용해서 구한 값이므로 이 값을
# 다시 x 를 사용했을 때의 값으로 환원을 해야 한다 (unscale).
data.frame(a, b)
# unscale coefficients to make them comprehensible
# see http://commres.net/wiki/gradient_descent#why_normalize_scale_or_make_z-score_xi
# and
# http://commres.net/wiki/gradient_descent#how_to_unnormalize_unscale_a_and_b
a = a - (mean(x) / sd(x)) * b
b = b / sd(x)
cat(" unscaled a:", a, "\n unscaled b:", b, "\n")
# 아래 lm 결과와 확인
summary(mo)
# 아래는 a와 b를 구하는 과정에서 저장했던 temporary
# a, b 값들은 (as, bs 변인 내의) 모두 unscale한 것
as <- as - (mean(x) /sd(x)) * bs
bs <- bs / sd(x)
as
bs
# 이것을 그래프로 나타내기 위해서 parameters 라는
# 변인으로 저장
# 이하 if 문들은 그래프에 처음 a, b값과 루프 문에서의
# 그 값들이 변화하는 것을 모두 나타내기 위해서 사용한
# 것으로 결과와 상관없다.
parameters <- data.frame(as, bs, mses)
cat(paste0("Intercept: ", a, "\n", "Slope: ", b, "\n"))
summary(lm(y~x, data=sam))$coefficients
if (as[nlen] > as[1]) {
amax <- as[nlen]
amin <- as[1]
} else {
amax <- as[1]
amin <- as[nlen]
}
if (max(y) > amax) {
y.max <- max(y)
} else {
y.max <- amax
}
if (min(y) > amin) {
y.min <- amin
} else {
y.min <- min(y)
}
max(y)
min(y)
y.max
y.min
ggplot(sam, aes(x = x, y = y)) +
geom_point(size = 2) +
coord_cartesian(xlim = c(0, max(x)+30), ylim = c(y.min-2,y.max+2)) +
geom_abline(aes(intercept = as, slope = bs),
data = parameters, linewidth = 0.5,
color = 'green') +
geom_abline(aes(intercept = as, slope = bs),
data = parameters %>% slice_head(),
linewidth = 1, color = 'blue') +
geom_abline(aes(intercept = as, slope = bs),
data = parameters %>% slice_tail(),
linewidth = 1, color = 'red') +
# stat_poly_line() +
stat_poly_eq(use_label(c("eq", "R2"))) +
theme_classic() +
labs(title = 'Gradient descent. blue: start, red: end, green: gradients')
summary(lm(y~x))
data.frame(head(as), head(bs))
data.frame(tail(as), tail(bs))
a
b
ggplot(sam, aes(x = x, y = y)) +
geom_point(size = 2) +
geom_abline(aes(intercept = as, slope = bs),
data = parameters %>% slice_tail(),
linewidth = 1, color = 'red') +
stat_poly_line() +
stat_poly_eq(use_label(c("eq", "R2"))) +
theme_classic() +
labs(title = 'Gradient descent. blue: start, red: end, green: gradients')
ro01
> # 아래는 a 와 b 를 랜덤하게 정한 후 (rnorm)
> # 두 가지 일을 하게 된다. 첫 째는
> # 이 때의 mse값을 저장한다. 둘째는
> # a, b 값을 가질 때의 a 와 b에 대한 미분 값을
> # 구한 후, 이 값에 1보다 작은 값을 곱하여 (learning rate)
> # 구한 값을 다음의 a 와 b 값으로 써서 다시
> # 이를 대입하여 mse값을 구하고 이 때의 미분 값을
> # 구한다. 이 미분하여 구한 a, b값을 저장한 후에
> # 다시 learning rate값을 곱하여 이를 다음의 a, b
> # 값으로 사용한다. . . . 이를 반복한다.
> a <- rnorm(1)
> b <- rnorm(1)
> a.init <- a
> b.init <- b
>
> # 이 때의 db, da는 무슨 값인가?
> # 미분결과값이므로 db는 기울기값
> # da는 그 당시의 a값
> gradient <- function(x, y, predictions){
+ error = y - predictions
+ db = -2 * mean(x * error)
+ da = -2 * mean(error)
+ return(list("b" = db, "a" = da))
+ # return(c(db, da))
+ }
>
> mseloss <- function(predictions, y) {
+ residuals <- (y - predictions)
+ return(mean(residuals^2))
+ }
>
> # Train the model with scaled features
> learning.rate = 0.1
>
> # Record Loss for each epoch:
> as = c()
> bs = c()
> das = c()
> dbs = c()
> ep <- c()
>
> mses = c()
> zx <- (x-mean(x))/sd(x)
>
>
> nlen <- 75
> for (epoch in 1:nlen) {
+ predictions <- predict(zx, a, b)
+ #residual <- residuals(predictions, y)
+ loss <- mseloss(predictions, y)
+ mses <- append(mses, loss)
+
+ grad <- gradient(zx, y, predictions)
+ db <- grad$b
+ da <- grad$a
+
+ dbs <- append(dbs, db)
+ das <- append(das, da)
+ ep <- append(ep, epoch)
+
+ step.b <- grad$b * learning.rate
+ step.a <- grad$a * learning.rate
+ b <- b-step.b
+ a <- a-step.a
+
+ as <- append(as, a)
+ bs <- append(bs, b)
+ }
>
> tmp <- data.frame(ep, das, as, dbs, bs, mse)
> tmp
ep das as dbs bs mse
1 1 -8.349964e+00 -0.1795060 6.595337e-01 0.4187294 18404982
2 2 -6.679971e+00 0.4884911 5.289460e-01 0.3658348 18404982
3 3 -5.343977e+00 1.0228888 4.242147e-01 0.3234133 18404982
4 4 -4.275181e+00 1.4504069 3.402202e-01 0.2893913 18404982
5 5 -3.420145e+00 1.7924215 2.728566e-01 0.2621057 18404982
6 6 -2.736116e+00 2.0660331 2.188310e-01 0.2402226 18404982
7 7 -2.188893e+00 2.2849224 1.755025e-01 0.2226723 18404982
8 8 -1.751114e+00 2.4600338 1.407530e-01 0.2085970 18404982
9 9 -1.400891e+00 2.6001229 1.128839e-01 0.1973086 18404982
10 10 -1.120713e+00 2.7121942 9.053288e-02 0.1882553 18404982
11 11 -8.965705e-01 2.8018513 7.260737e-02 0.1809946 18404982
12 12 -7.172564e-01 2.8735769 5.823111e-02 0.1751715 18404982
13 13 -5.738051e-01 2.9309574 4.670135e-02 0.1705014 18404982
14 14 -4.590441e-01 2.9768619 3.745448e-02 0.1667559 18404982
15 15 -3.672353e-01 3.0135854 3.003849e-02 0.1637521 18404982
16 16 -2.937882e-01 3.0429642 2.409087e-02 0.1613430 18404982
17 17 -2.350306e-01 3.0664673 1.932088e-02 0.1594109 18404982
18 18 -1.880245e-01 3.0852697 1.549535e-02 0.1578613 18404982
19 19 -1.504196e-01 3.1003117 1.242727e-02 0.1566186 18404982
20 20 -1.203357e-01 3.1123452 9.966668e-03 0.1556220 18404982
21 21 -9.626853e-02 3.1219721 7.993268e-03 0.1548226 18404982
22 22 -7.701482e-02 3.1296736 6.410601e-03 0.1541816 18404982
23 23 -6.161186e-02 3.1358348 5.141302e-03 0.1536674 18404982
24 24 -4.928949e-02 3.1407637 4.123324e-03 0.1532551 18404982
25 25 -3.943159e-02 3.1447069 3.306906e-03 0.1529244 18404982
26 26 -3.154527e-02 3.1478614 2.652139e-03 0.1526592 18404982
27 27 -2.523622e-02 3.1503850 2.127015e-03 0.1524465 18404982
28 28 -2.018897e-02 3.1524039 1.705866e-03 0.1522759 18404982
29 29 -1.615118e-02 3.1540190 1.368105e-03 0.1521391 18404982
30 30 -1.292094e-02 3.1553111 1.097220e-03 0.1520294 18404982
31 31 -1.033675e-02 3.1563448 8.799704e-04 0.1519414 18404982
32 32 -8.269403e-03 3.1571717 7.057362e-04 0.1518708 18404982
33 33 -6.615523e-03 3.1578333 5.660005e-04 0.1518142 18404982
34 34 -5.292418e-03 3.1583625 4.539324e-04 0.1517688 18404982
35 35 -4.233935e-03 3.1587859 3.640538e-04 0.1517324 18404982
36 36 -3.387148e-03 3.1591246 2.919711e-04 0.1517032 18404982
37 37 -2.709718e-03 3.1593956 2.341608e-04 0.1516798 18404982
38 38 -2.167774e-03 3.1596124 1.877970e-04 0.1516610 18404982
39 39 -1.734220e-03 3.1597858 1.506132e-04 0.1516460 18404982
40 40 -1.387376e-03 3.1599245 1.207918e-04 0.1516339 18404982
41 41 -1.109901e-03 3.1600355 9.687500e-05 0.1516242 18404982
42 42 -8.879204e-04 3.1601243 7.769375e-05 0.1516164 18404982
43 43 -7.103363e-04 3.1601954 6.231039e-05 0.1516102 18404982
44 44 -5.682691e-04 3.1602522 4.997293e-05 0.1516052 18404982
45 45 -4.546153e-04 3.1602977 4.007829e-05 0.1516012 18404982
46 46 -3.636922e-04 3.1603340 3.214279e-05 0.1515980 18404982
47 47 -2.909538e-04 3.1603631 2.577852e-05 0.1515954 18404982
48 48 -2.327630e-04 3.1603864 2.067437e-05 0.1515933 18404982
49 49 -1.862104e-04 3.1604050 1.658085e-05 0.1515917 18404982
50 50 -1.489683e-04 3.1604199 1.329784e-05 0.1515903 18404982
51 51 -1.191747e-04 3.1604318 1.066487e-05 0.1515893 18404982
52 52 -9.533973e-05 3.1604414 8.553223e-06 0.1515884 18404982
53 53 -7.627178e-05 3.1604490 6.859685e-06 0.1515877 18404982
54 54 -6.101743e-05 3.1604551 5.501467e-06 0.1515872 18404982
55 55 -4.881394e-05 3.1604600 4.412177e-06 0.1515867 18404982
56 56 -3.905115e-05 3.1604639 3.538566e-06 0.1515864 18404982
57 57 -3.124092e-05 3.1604670 2.837930e-06 0.1515861 18404982
58 58 -2.499274e-05 3.1604695 2.276020e-06 0.1515859 18404982
59 59 -1.999419e-05 3.1604715 1.825368e-06 0.1515857 18404982
60 60 -1.599535e-05 3.1604731 1.463945e-06 0.1515855 18404982
61 61 -1.279628e-05 3.1604744 1.174084e-06 0.1515854 18404982
62 62 -1.023703e-05 3.1604754 9.416152e-07 0.1515853 18404982
63 63 -8.189621e-06 3.1604762 7.551754e-07 0.1515853 18404982
64 64 -6.551696e-06 3.1604769 6.056507e-07 0.1515852 18404982
65 65 -5.241357e-06 3.1604774 4.857318e-07 0.1515851 18404982
66 66 -4.193086e-06 3.1604778 3.895569e-07 0.1515851 18404982
67 67 -3.354469e-06 3.1604782 3.124247e-07 0.1515851 18404982
68 68 -2.683575e-06 3.1604784 2.505646e-07 0.1515850 18404982
69 69 -2.146860e-06 3.1604786 2.009528e-07 0.1515850 18404982
70 70 -1.717488e-06 3.1604788 1.611641e-07 0.1515850 18404982
71 71 -1.373990e-06 3.1604789 1.292536e-07 0.1515850 18404982
72 72 -1.099192e-06 3.1604791 1.036614e-07 0.1515850 18404982
73 73 -8.793538e-07 3.1604791 8.313646e-08 0.1515850 18404982
74 74 -7.034830e-07 3.1604792 6.667544e-08 0.1515850 18404982
75 75 -5.627864e-07 3.1604793 5.347370e-08 0.1515850 18404982
>
> # 위의 루프를 이해했는지 체크하기
> a.init
[1] -1.014502
> b.init
[1] 0.4846828
> tmp.p <- predict(zx, a.init, b.init)
> # a.init b.init 일 때의 미분 결과
> # 즉, 기울기와 절편 값
> tmp.g <- gradient(zx, y, tmp.p)
> tmp.g
$b
[1] 0.6595337
$a
[1] -8.349964
>
> # 이 값에 learning rate 값을 곱한 후에
> a.step <- tmp.g$a*learning.rate
> b.step <- tmp.g$b*learning.rate
>
> # 이를 원래 a값에서 빼준 값을 다음 순서의
> a.init <- a.init-a.step
> b.init <- b.init-b.step
> # a, b값으로 쓰고, 이 때의 미분 값을 구한 후에
> # (루프 안에서), 미분 결과를 다시 learning rate
> # 로 곱해 준 값을 (두번째 단계의) a, b 값에서
> # 빼 준 값을 다음 단계의 a, b값으로 쓰고, 다시
> # . . . . . . 위의 loop문은 이것을 75번 반복한 것
>
> # scaled
> # 이렇게 해서 구한 제일 마지막 a, b 값은 x 변인 대신에
> # 표준화한 zx 변인을 사용해서 구한 값이므로 이 값을
> # 다시 x 를 사용했을 때의 값으로 환원을 해야 한다 (unscale).
> data.frame(a, b)
a b
1 3.160479 0.151585
>
> # unscale coefficients to make them comprehensible
> # see http://commres.net/wiki/gradient_descent#why_normalize_scale_or_make_z-score_xi
> # and
> # http://commres.net/wiki/gradient_descent#how_to_unnormalize_unscale_a_and_b
> a = a - (mean(x) / sd(x)) * b
> b = b / sd(x)
> cat(" unscaled a:", a, "\n unscaled b:", b, "\n")
unscaled a: 1.614428
unscaled b: 0.01447618
> # 아래 lm 결과와 확인
> summary(mo)
Call:
lm(formula = y ~ x, data = sam)
Residuals:
Min 1Q Median 3Q Max
-0.92770 -0.20715 0.03368 0.20038 0.90512
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.614428 0.344622 4.685 9.04e-06 ***
x 0.014476 0.003212 4.508 1.82e-05 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.3346 on 98 degrees of freedom
Multiple R-squared: 0.1717, Adjusted R-squared: 0.1633
F-statistic: 20.32 on 1 and 98 DF, p-value: 1.818e-05
>
> # 아래는 a와 b를 구하는 과정에서 저장했던 temporary
> # a, b 값들은 (as, bs 변인 내의) 모두 unscale한 것
> as <- as - (mean(x) /sd(x)) * bs
> bs <- bs / sd(x)
>
> as
[1] -4.45022736 -3.24274555 -2.27568113 -1.50116427 -0.88085678 -0.38405420 0.01383425 0.33250300
[9] 0.58772512 0.79213308 0.95584412 1.08696106 1.19197340 1.27607853 1.34343904 1.39738872
[17] 1.44059760 1.47520412 1.50292095 1.52511976 1.54289914 1.55713894 1.56854386 1.57767829
[25] 1.58499424 1.59085375 1.59554676 1.59930551 1.60231600 1.60472717 1.60665835 1.60820509
[33] 1.60944392 1.61043613 1.61123083 1.61186734 1.61237714 1.61278545 1.61311249 1.61337442
[41] 1.61358422 1.61375225 1.61388684 1.61399463 1.61408097 1.61415012 1.61420551 1.61424987
[49] 1.61428541 1.61431387 1.61433666 1.61435492 1.61436954 1.61438126 1.61439064 1.61439815
[57] 1.61440417 1.61440899 1.61441285 1.61441594 1.61441842 1.61442041 1.61442199 1.61442327
[65] 1.61442429 1.61442510 1.61442576 1.61442628 1.61442670 1.61442704 1.61442731 1.61442752
[73] 1.61442769 1.61442783 1.61442794
> bs
[1] 0.03998814 0.03493677 0.03088558 0.02763651 0.02503077 0.02294096 0.02126493 0.01992076 0.01884273
[10] 0.01797815 0.01728476 0.01672866 0.01628267 0.01592498 0.01563812 0.01540805 0.01522354 0.01507556
[19] 0.01495689 0.01486170 0.01478537 0.01472415 0.01467505 0.01463567 0.01460409 0.01457877 0.01455845
[28] 0.01454216 0.01452910 0.01451862 0.01451021 0.01450348 0.01449807 0.01449373 0.01449026 0.01448747
[37] 0.01448523 0.01448344 0.01448200 0.01448085 0.01447992 0.01447918 0.01447859 0.01447811 0.01447773
[46] 0.01447742 0.01447717 0.01447698 0.01447682 0.01447669 0.01447659 0.01447651 0.01447644 0.01447639
[55] 0.01447635 0.01447631 0.01447629 0.01447626 0.01447625 0.01447623 0.01447622 0.01447621 0.01447621
[64] 0.01447620 0.01447619 0.01447619 0.01447619 0.01447619 0.01447618 0.01447618 0.01447618 0.01447618
[73] 0.01447618 0.01447618 0.01447618
>
> # 이것을 그래프로 나타내기 위해서 parameters 라는
> # 변인으로 저장
> # 이하 if 문들은 그래프에 처음 a, b값과 루프 문에서의
> # 그 값들이 변화하는 것을 모두 나타내기 위해서 사용한
> # 것으로 결과와 상관없다.
> parameters <- data.frame(as, bs, mses)
>
> cat(paste0("Intercept: ", a, "\n", "Slope: ", b, "\n"))
Intercept: 1.61442794384896
Slope: 0.0144761780722265
> summary(lm(y~x, data=sam))$coefficients
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.61442839 0.344622352 4.684631 9.041202e-06
x 0.01447618 0.003211564 4.507515 1.817763e-05
>
> if (as[nlen] > as[1]) {
+ amax <- as[nlen]
+ amin <- as[1]
+ } else {
+ amax <- as[1]
+ amin <- as[nlen]
+ }
> if (max(y) > amax) {
+ y.max <- max(y)
+ } else {
+ y.max <- amax
+ }
> if (min(y) > amin) {
+ y.min <- amin
+ } else {
+ y.min <- min(y)
+ }
> max(y)
[1] 3.878048
> min(y)
[1] 2.092215
> y.max
[1] 3.878048
> y.min
[1] -4.450227
>
> ggplot(sam, aes(x = x, y = y)) +
+ geom_point(size = 2) +
+ coord_cartesian(xlim = c(0, max(x)+30), ylim = c(y.min-2,y.max+2)) +
+ geom_abline(aes(intercept = as, slope = bs),
+ data = parameters, linewidth = 0.5,
+ color = 'green') +
+ geom_abline(aes(intercept = as, slope = bs),
+ data = parameters %>% slice_head(),
+ linewidth = 1, color = 'blue') +
+ geom_abline(aes(intercept = as, slope = bs),
+ data = parameters %>% slice_tail(),
+ linewidth = 1, color = 'red') +
+ # stat_poly_line() +
+ stat_poly_eq(use_label(c("eq", "R2"))) +
+ theme_classic() +
+ labs(title = 'Gradient descent. blue: start, red: end, green: gradients')
>
> summary(lm(y~x))
Call:
lm(formula = y ~ x)
Residuals:
Min 1Q Median 3Q Max
-0.92770 -0.20715 0.03368 0.20038 0.90512
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.614428 0.344622 4.685 9.04e-06 ***
x 0.014476 0.003212 4.508 1.82e-05 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.3346 on 98 degrees of freedom
Multiple R-squared: 0.1717, Adjusted R-squared: 0.1633
F-statistic: 20.32 on 1 and 98 DF, p-value: 1.818e-05
>
> data.frame(head(as), head(bs))
head.as. head.bs.
1 -4.4502274 0.03998814
2 -3.2427456 0.03493677
3 -2.2756811 0.03088558
4 -1.5011643 0.02763651
5 -0.8808568 0.02503077
6 -0.3840542 0.02294096
> data.frame(tail(as), tail(bs))
tail.as. tail.bs.
1 1.614427 0.01447618
2 1.614427 0.01447618
3 1.614428 0.01447618
4 1.614428 0.01447618
5 1.614428 0.01447618
6 1.614428 0.01447618
> a
[1] 1.614428
> b
[1] 0.01447618
>
> ggplot(sam, aes(x = x, y = y)) +
+ geom_point(size = 2) +
+ geom_abline(aes(intercept = as, slope = bs),
+ data = parameters %>% slice_tail(),
+ linewidth = 1, color = 'red') +
+ stat_poly_line() +
+ stat_poly_eq(use_label(c("eq", "R2"))) +
+ theme_classic() +
+ labs(title = 'Gradient descent. blue: start, red: end, green: gradients')
>
Why normalize (scale or make z-score) xi
x 변인의 측정단위로 인해서 b 값이 결정되게 되는데 이 때의 b값은 상당하고 다양한 범위를 가질 수 있다. 가령 월 수입이 (인컴) X 라고 한다면 우리가 추정해야 (추적해야) 할 b값은 수백만이 될 수도 있다.이 값을 gradient로 추적하게 된다면 너무도 많은 iteration을 거쳐야 할 수 있다. 변인이 바뀌면 이 b의 추적범위도 드라마틱하게 바뀌게 된다. 이를 표준화한 x 점수를 사용하게 된다면 일정한 learning rate와 iteration만으로도 정확한 a와 b를 추적할 수 있게 된다.
How to unnormalize (unscale) a and b
\begin{eqnarray*} y & = & a + b * x \\ & & \text{we use z instead of x} \\ & & \text{and } \\ & & z = \frac{(x - \mu)}{\sigma} \\ & & \text{suppose that the result after calculation be } \\ y & = & k + m * z \\ & = & k + m * \frac{(x - \mu)}{\sigma} \\ & = & k + \frac{m * x}{\sigma} - \frac{m * \mu}{\sigma} \\ & = & k - \frac{m * \mu}{\sigma} + \frac{m * x}{\sigma} \\ & = & \underbrace{k - \frac{\mu}{\sigma} * m}_\text{ 1 } + \underbrace{\frac{m}{\sigma}}_\text{ 2 } * x \\ & & \text{therefore, a and be that we try to get are } \\ a & = & k - \frac{\mu}{\sigma} * m \\ b & = & \frac{m}{\sigma} \\ \end{eqnarray*}




