Optimisasi Statistika - Metode Gradien
Video Pembelajaran - P7
Video Pembelajaran dapat diakses melalui link berikut : https://ipb.link/materiopstat
Pengantar
Metode optimisasi bertujuan untuk menemukan nilai minimum (atau maksimum) dari suatu fungsi tujuan \(f(x)\). Fungsi \(f(x)\) bisa berupa fungsi non-linear, seperti fungsi Rosenbrock berikut: \[ f(x) = 100(x_2 - x_1^2)^2 + (1 - x_1)^2 \]
f<-function(x) {
x1=x[1]; x2=x[2];
100*(x2-x1^2)^2+(1-x1)^2
}
x0<-c(-0,0)
library(numDeriv)
library(pracma)Fungsi ini memiliki bentuk non-linear dengan sebuah lembah sempit yang membuatnya menantang untuk dioptimalkan. Minimum globalnya adalah \(f(1, 1) = 0\), yang terjadi pada titik \((x_1, x_2) = (1, 1)\).
Metode Newton
Metode Newton menggunakan informasi gradien dan matriks Hessian untuk menemukan minimum fungsi. Formula iterasinya adalah: \[ x_{i+1} = x_i - \left( \nabla^2 f(x_i) \right)^{-1} \nabla f(x_i) \]
Komponen Utama:
Gradien: \(\nabla f(x) = \begin{bmatrix} \frac{\partial f}{\partial x_1} \\ \frac{\partial f}{\partial x_2} \end{bmatrix}\)
Hessian: \(\nabla^2 f(x) = \begin{bmatrix} \frac{\partial^2 f}{\partial x_1^2} & \frac{\partial^2 f}{\partial x_1 \partial x_2} \\ \frac{\partial^2 f}{\partial x_2 \partial x_1} & \frac{\partial^2 f}{\partial x_2^2} \end{bmatrix}\)
Keunggulan:
- Cepat konvergen jika \(x_0\) dekat dengan solusi.
- Cocok untuk fungsi kuadratik karena Hessian konstan.
Kelemahan:
- Membutuhkan komputasi invers Hessian (\(O(n^3)\)).
- Tidak stabil jika Hessian tidak positif definit.
Kode Implementasi di R
newton_optimize <- function(f, x0, tol = 1e-6, max_iter = 100) {
iter <- 0
while (iter < max_iter) {
df <- grad(f, x0) # Gradien
ddf <- hessian(f, x0) # Hessian
dx <- solve(ddf, -df) # Perbarui langkah
x1 <- x0 + dx
if (abs(f(x1) - f(x0)) < tol) return(list(x = x1, iter = iter))
iter <- iter + 1
x0 <- x1
}
return(NULL)
}
# Contoh penggunaan
x0 <- c(0, 0)
o1 <- newton_optimize(f, x0)Metode Marquardt
Metode Marquardt adalah kombinasi dari metode Gradient Descent dan Newton. Metode ini menambahkan elemen damping (\(\lambda\)) ke Hessian untuk memperbaiki stabilitas iterasi.
Formula Iterasi:
\[ x_{i+1} = x_i - \left( \nabla^2 f(x_i) + \lambda I \right)^{-1} \nabla f(x_i) \] \(\lambda\) adalah parameter yang mengontrol panjang langkah. Jika iterasi menurun, \(\lambda\) dikurangi; jika tidak, \(\lambda\) diperbesar.
Keunggulan:
- Stabil untuk iterasi awal.
- Mampu menangani gradien kecil pada area tertentu.
Kelemahan:
- Pemilihan parameter damping \(\lambda\) sensitif.
- Tidak cocok untuk dimensi sangat tinggi.
Kode Implementasi di R
marquardt_optimize <- function(f, x0, tol = 1e-6, max_iter = 100, lambda = 1) {
iter <- 0
while (iter < max_iter) {
df <- grad(f, x0)
ddf <- hessian(f, x0)
mu <- lambda * max(diag(ddf)) # Damping factor
dx <- solve(ddf + mu * diag(length(x0)), -df)
x1 <- x0 + dx
if (abs(f(x1) - f(x0)) < tol) return(list(x = x1, iter = iter))
iter <- iter + 1
lambda <- ifelse(f(x1) < f(x0), lambda / 10, lambda * 10)
x0 <- x1
}
return(NULL)
}
# Contoh penggunaan
o2 <- marquardt_optimize(f, x0)Metode Quasi-Newton (DFP dan BFGS)
DFP (Davidon-Fletcher-Powell)
DFP memperbarui aproksimasi matriks Hessian (\(B_k\)) menggunakan: \[ B_{k+1} = B_k + \frac{s_k s_k^\top}{s_k^\top y_k} - \frac{B_k y_k y_k^\top B_k}{y_k^\top B_k y_k} \]
BFGS (Broyden-Fletcher-Goldfarb-Shanno)
Pengembangan lebih stabil dari DFP: \[ B_{k+1} = B_k + \frac{y_k y_k^\top}{y_k^\top s_k} - \frac{B_k s_k s_k^\top B_k}{s_k^\top B_k s_k} \]
Keunggulan:
- Tidak memerlukan Hessian eksplisit.
- Lebih stabil untuk fungsi non-linear.
Kode Implementasi
dfp_optimize <- function(f, x0, B0, tol = 1e-6, max_iter = 100) {
# Initialize variables
iter <- 0
n <- length(x0)
x <- x0
B <- B0
# Loop until convergence or maximum number of iterations is reached
while (iter < max_iter) {
# Calculate the gradient using numerical differentiation
g <- grad(f, x)
# Calculate the search direction
d <- -B %*% g
# Perform line search to find optimal step size
alpha <- optimize(function(alpha) f(x + alpha*d), interval = c(0, 1))$minimum
x_new <- x + alpha * d
# Calculate the new gradient using numerical differentiation
g_new <- grad(f, x_new)
# Calculate the update to the Hessian matrix
s <- alpha * d
y <- g_new - g
B <- B + ((s %*% t(s)) / as.numeric(t(s) %*% y)) - ((B %*% y %*% t(y) %*% B) / as.numeric(t(y) %*% B %*% y))
# Check for convergence
if (abs(f(x_new) - f(x)) < tol) {
return(list(x=x_new, iter=iter))
}
# Update the iteration counter and the guess
iter <- iter + 1
x <- x_new
}
# If the algorithm does not converge within the maximum number of iterations, return NULL
return(NULL)
}
# DFP
B0<-diag(2)
o3 <- dfp_optimize(f, x0, B0)
# BFGS dengan optim
o4 <- optim(par = x0, fn = f, method = "BFGS", control = list(trace = TRUE))## initial value 1.000000
## iter 10 value 0.048025
## iter 20 value 0.000001
## final value 0.000000
## converged
Metode Gradient Descent
Formula Iterasi:
\[ x_{i+1} = x_i - \alpha \nabla f(x_i) \] di mana \(\alpha\) adalah learning rate.
Keunggulan:
- Implementasi sederhana.
- Cocok untuk fungsi dimensi tinggi.
Kelemahan:
- Pemilihan learning rate sulit.
- Lambat untuk fungsi dengan lembah sempit.
Kode Implementasi
gradient_descent <- function(obj_func, init_x, learning_rate = 0.01, maxIter = 1e5, tol = 1e-6) {
x <- init_x
gradx <- grad(obj_func, x)
iter <- 0
while (iter < maxIter && norm(as.matrix(gradx)) > tol) {
gradx <- grad(obj_func, x)
x <- x - learning_rate * gradx
iter <- iter + 1
}
return(list(x = x, iter = iter))
}
# Contoh penggunaan
o5 <- gradient_descent(f, x0)Perbandingan Metode
Berikut adalah hasil perbandingan dari semua metode:
# Newton
o1 <- newton_optimize(f, x0)
# Marquardt
o2 <- marquardt_optimize(f,x0)
# DFP
B0<-diag(2)
o3 <- dfp_optimize(f, x0, B0)
# BFGS
o4 <- optim(par=x0, fn=f, method="BFGS", control = list(trace=T))## initial value 1.000000
## iter 10 value 0.048025
## iter 20 value 0.000001
## final value 0.000000
## converged
# Gradient Descent
o5 <- gradient_descent(obj_func=f, init_x=x0, learning_rate=0.001)
data.frame(Method = c("Newton", "Marquardt", "DFP", "BFGS", "Gradient Descent"), x1 = c(o1$x[1],o2$x[1],o3$x[1],o4$par[1],o5$x[1]), x2 = c(o1$x[2],o2$x[2],o3$x[2],o4$par[2],o5$x[2]), iter = c(o1$iter,o2$iter,o3$iter,o4$counts[2],o5$iter))## Method x1 x2 iter
## 1 Newton 1.0000000 1.0000000 2
## 2 Marquardt 0.9999956 0.9999906 10
## 3 DFP 1.0000180 1.0000189 18
## 4 BFGS 0.9998000 0.9996001 26
## 5 Gradient Descent 0.9999992 0.9999983 32041
fw <- function (x) 10*sin(0.3*x)*sin(1.3*x^2) + 0.00001*x^4 + 0.2*x+80
plot(fw, -50, 50, n = 1000, main = "optim() minimising 'wild function'")x0 <- c(1)
# Newton
o1 <- newton_optimize(fw, x0)
# Marquardt
o2 <- marquardt_optimize(fw,x0)
# DfP
B0<-diag(1)
o3 <- dfp_optimize(fw, x0, B0)
# Optim
o4 <- optim(par=x0, fn=fw, method="BFGS", control = list(trace=T, maxit=100000, temp = 20, parscale = 20))## initial value 83.047519
## final value 67.709261
## converged
# Gradient Descent
o5 <- gradient_descent(obj_func=fw, init_x=x0, learning_rate=0.001)
data.frame(Method = c("Newton", "Marquardt", "DFP", "BFGS", "Gradient Descent"),
x1 = c(o1$x[1],o2$x[1],o3$x[1],o4$par[1],o5$x[1]),
func=c(fw(o1$x),fw(o2$x),fw(o3$x),fw(o4$par[1]),fw(o5$x)),
iter = c(o1$iter,o2$iter,o3$iter,o4$counts[2],o5$iter))## Method x1 func iter
## 1 Newton 1.190594 83.60594 4
## 2 Marquardt 1.186752 83.60565 3
## 3 DFP -1.190591 76.39410 1
## 4 BFGS -15.031766 67.70926 4
## 5 Gradient Descent -1.190591 76.39410 2337