R: implementando il mio algoritmo di aumento gradiente


10

Sto cercando di scrivere il mio algoritmo di aumento gradiente. Capisco che ci sono pacchetti esistenti come gbme xgboost,ma volevo capire come funziona l'algoritmo scrivendo il mio.

Sto usando il irisset di dati e il mio risultato è Sepal.Length(continuo). La mia funzione di perdita è mean(1/2*(y-yhat)^2)(sostanzialmente l'errore quadratico medio con 1/2 davanti), quindi il gradiente corrispondente è solo il residuo y - yhat. Sto inizializzando le previsioni a 0.

library(rpart)
data(iris)

#Define gradient
grad.fun <- function(y, yhat) {return(y - yhat)}

mod <- list()

grad_boost <- function(data, learning.rate, M, grad.fun) {
  # Initialize fit to be 0
  fit <- rep(0, nrow(data))
  grad <- grad.fun(y = data$Sepal.Length, yhat = fit)

  # Initialize model
  mod[[1]] <- fit

  # Loop over a total of M iterations
  for(i in 1:M){

    # Fit base learner (tree) to the gradient
    tmp <- data$Sepal.Length
    data$Sepal.Length <- grad
    base_learner <- rpart(Sepal.Length ~ ., data = data, control = ("maxdepth = 2"))
    data$Sepal.Length <- tmp

    # Fitted values by fitting current model
    fit <- fit + learning.rate * as.vector(predict(base_learner, newdata = data))

    # Update gradient
    grad <- grad.fun(y = data$Sepal.Length, yhat = fit)

    # Store current model (index is i + 1 because i = 1 contain the initialized estiamtes)
    mod[[i + 1]] <- base_learner

  }
  return(mod)
}

Con questo, ho diviso il irisset di dati in un set di dati di training e test e ho adattato il mio modello ad esso.

train.dat <- iris[1:100, ]
test.dat <- iris[101:150, ]
learning.rate <- 0.001
M = 1000
my.model <- grad_boost(data = train.dat, learning.rate = learning.rate, M = M, grad.fun = grad.fun)

Ora calcolo i valori previsti da my.model. Per my.model, i valori adattati sono 0 (vector of initial estimates) + learning.rate * predictions from tree 1 + learning rate * predictions from tree 2 + ... + learning.rate * predictions from tree M.

yhats.mymod <- apply(sapply(2:length(my.model), function(x) learning.rate * predict(my.model[[x]], newdata = test.dat)), 1, sum)

# Calculate RMSE
> sqrt(mean((test.dat$Sepal.Length - yhats.mymod)^2))
[1] 2.612972

Ho alcune domande

  1. Il mio algoritmo di aumento gradiente sembra giusto?
  2. Ho calcolato yhats.mymodcorrettamente i valori previsti ?

Risposte:


0
  1. Sì, questo sembra corretto. Ad ogni passo ti stai adattando ai psue-residui, che sono calcolati come derivata della perdita rispetto all'adattamento. Hai correttamente derivato questo gradiente all'inizio della tua domanda e ti sei persino preso la briga di ottenere il fattore 2 giusto.
  2. Anche questo sembra corretto. Stai aggregando tra i modelli, ponderato per il tasso di apprendimento, proprio come hai fatto durante l'allenamento.

Ma per affrontare qualcosa che non è stato chiesto, ho notato che la configurazione dell'allenamento ha alcune stranezze.

  • Il irisset di dati è diviso equamente tra 3 specie (setosa, versicolor, virginica) e queste sono adiacenti nei dati. I tuoi dati di allenamento contengono tutti i setosa e i versicolor, mentre il set di test contiene tutti gli esempi di virginica. Non vi è alcuna sovrapposizione, che porterà a problemi fuori campione. È preferibile bilanciare l'allenamento e i set di test per evitarlo.
  • La combinazione di tasso di apprendimento e numero di modelli mi sembra troppo bassa. L'adattamento converge come (1-lr)^n. Con lr = 1e-3e n = 1000puoi modellare solo il 63,2% della grandezza dei dati. Cioè, anche se ogni modello prevede correttamente ogni campione, si stimerebbe il 63,2% del valore corretto. Inizializzare l'adattamento con una media, invece di 0, sarebbe d'aiuto da allora l'effetto è una regressione alla media anziché solo un trascinamento.

Grazie per i vostri commenti. Potresti espandere il motivo per cui "fit converge as (1-lr) ^ n"? Qual è la logica alla base di questo?
YQW,

È perché fit <- fit + learning.rate * prediction, dov'è predictionil residuo target - fit. Quindi fit <- fit + lr * (target - fit), o fit <- fit * (1 - lr) + target * lr. Questa è solo una media mobile esponenziale. Per Wikipedia , "il peso omesso dall'interruzione dopo k termini è (1-α)^kfuori dal peso totale" ( αè il tasso di apprendimento ed kè n). Stai iniziando con una stima di 0 invece della media, quindi questo peso omesso esce direttamente dalla previsione.
mcskinner,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.