R: Implementierung meines eigenen Algorithmus zur Erhöhung des Gradienten


10

Ich versuche, meinen eigenen Algorithmus zur Erhöhung des Gradienten zu schreiben. Ich verstehe , gibt es bestehende Pakete wie gbmund xgboost,aber ich wollte verstehen , wie der Algorithmus funktioniert durch meine eigenen zu schreiben.

Ich verwende den irisDatensatz und mein Ergebnis ist Sepal.Length(kontinuierlich). Meine Verlustfunktion ist mean(1/2*(y-yhat)^2)(im Grunde der mittlere quadratische Fehler mit 1/2 vorne), also ist mein entsprechender Gradient nur der Rest y - yhat. Ich initialisiere die Vorhersagen bei 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)
}

Damit habe ich den irisDatensatz in einen Trainings- und Testdatensatz aufgeteilt und mein Modell daran angepasst.

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)

Jetzt berechne ich die vorhergesagten Werte aus my.model. Für my.modelsind die angepassten Werte 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

Ich habe ein paar Fragen

  1. Sieht mein Algorithmus zur Erhöhung des Gradienten richtig aus?
  2. Habe ich die vorhergesagten Werte yhats.mymodrichtig berechnet ?

Antworten:


0
  1. Ja das sieht richtig aus. Bei jedem Schritt passen Sie an die Pseudo-Residuen an, die als Ableitung des Verlusts in Bezug auf die Anpassung berechnet werden. Sie haben diesen Gradienten zu Beginn Ihrer Frage korrekt abgeleitet und sich sogar die Mühe gemacht, den Faktor 2 richtig zu machen.
  2. Das sieht auch richtig aus. Sie aggregieren über die Modelle hinweg, gewichtet nach der Lernrate, genau wie während des Trainings.

Aber um etwas anzusprechen, das nicht gefragt wurde, habe ich festgestellt, dass Ihr Trainings-Setup einige Macken aufweist.

  • Der irisDatensatz ist zu gleichen Teilen auf 3 Arten (Setosa, Versicolor, Virginica) aufgeteilt, die in den Daten benachbart sind. Ihre Trainingsdaten enthalten alle Setosa und Versicolor, während der Testsatz alle Virginica-Beispiele enthält. Es gibt keine Überlappung, was zu Problemen außerhalb der Stichprobe führt. Es ist vorzuziehen, Ihre Trainings- und Testsätze auszugleichen, um dies zu vermeiden.
  • Die Kombination aus Lernrate und Modellanzahl erscheint mir zu niedrig. Die Passform konvergiert als (1-lr)^n. Mit lr = 1e-3und können n = 1000Sie nur 63,2% der Datengröße modellieren. Das heißt, selbst wenn jedes Modell jede Stichprobe korrekt vorhersagt, würden Sie 63,2% des korrekten Werts schätzen. Das Initialisieren der Anpassung mit einem Durchschnitt anstelle von Nullen würde helfen, da der Effekt eine Regression auf den Mittelwert statt nur eines Ziehens ist.

Vielen Dank für Ihre Kommentare. Könnten Sie näher erläutern, warum die "Anpassung als (1-lr) ^ n konvergiert"? Was ist der Grund dafür?
YQW

Es liegt daran fit <- fit + learning.rate * prediction, wo predictionist der Rest target - fit. Also fit <- fit + lr * (target - fit)oder fit <- fit * (1 - lr) + target * lr. Dies ist nur ein exponentieller gleitender Durchschnitt. Laut Wikipedia ist "das Gewicht, das beim Stoppen nach k Begriffen weggelassen wird (1-α)^k, nicht das Gesamtgewicht" ( αist die Lernrate und kist n). Sie beginnen mit einer Schätzung von 0 anstelle des Mittelwerts, sodass dieses weggelassene Gewicht direkt aus der Vorhersage hervorgeht.
Mcskinner
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.