Diese Werte werden nach xgboost::xgb.train
vorhergesagt:
247367.2 258693.3 149572.2 201675.8 250493.9 292349.2 414828.0 296503.2 260851.9 190413.3
Diese Werte werden nach xgboost::xgb.save
und xgboost::xgb.load
des VorgÀngermodells vorhergesagt:
247508.8 258658.2 149252.1 201692.6 250458.1 292313.4 414787.2 296462.5 260879.0 190430.1
Sie sind nah, aber nicht gleich. Die Unterschiede zwischen diesen beiden Vorhersagen reichen von -1317.094
bis 1088.859
bei einem Satz von 25.000 Stichproben. Beim Vergleich mit wahren Labels unterscheiden sich die MAE/RMSE dieser beiden Vorhersagen nicht wesentlich.
Ich vermute also, dass dies mit Rundungsfehlern beim Laden/Speichern zu tun hat, da sich MAE/RMSE nicht so stark unterscheiden. Trotzdem finde ich das seltsam, da das binĂ€re Speichern des Modells keine Rundungsfehler einfĂŒhren sollte?
Jemand eine Ahnung?
PS Das Hochladen und Dokumentieren des Schulungsprozesses scheint mir hier nicht wichtig. Ich könnte bei Bedarf Details liefern oder eine Simulation mit Dummy-Daten durchfĂŒhren, um das zu beweisen.
Es sollte kein Rundungsfehler sowohl fĂŒr BinĂ€r als auch fĂŒr JSON auftreten. Benutzt du Dart?
Nein, bin ich nicht:
params <- list(objective = 'reg:squarederror',
max_depth = 10, eta = 0.02, subsammple = 0.5,
base_score = median(xgboost::getinfo(xgb.train, 'label'))
)
xgboost::xgb.train(
params = params, data = xgb.train,
watchlist = list('train' = xgb.train, 'test' = xgb.test),
nrounds = 10000, verbose = TRUE, print_every_n = 25,
eval_metric = 'mae',
early_stopping_rounds = 3, maximize = FALSE)
Können Sie uns Dummy-Daten zur VerfĂŒgung stellen, wo dieses PhĂ€nomen auftritt?
Los geht's (Quick & Dirty):
N <- 100000
set.seed(2020)
X <- data.frame('X1' = rnorm(N), 'X2' = runif(N), 'X3' = rpois(N, lambda = 1))
Y <- with(X, X1 + X2 - X3 + X1*X2^2 - ifelse(X1 > 0, 2, X3))
params <- list(objective = 'reg:squarederror',
max_depth = 5, eta = 0.02, subsammple = 0.5,
base_score = median(Y)
)
dtrain <- xgboost::xgb.DMatrix(data = data.matrix(X), label = Y)
fit <- xgboost::xgb.train(
params = params, data = dtrain,
watchlist = list('train' = dtrain),
nrounds = 10000, verbose = TRUE, print_every_n = 25,
eval_metric = 'mae',
early_stopping_rounds = 3, maximize = FALSE
)
pred <- stats::predict(fit, newdata = dtrain)
xgboost::xgb.save(fit, 'booster.raw')
fit.loaded <- xgboost::xgb.load('booster.raw')
pred.loaded <- stats::predict(fit.loaded, newdata = dtrain)
identical(pred, pred.loaded)
pred[1:10]
pred.loaded[1:10]
sqrt(mean((Y - pred)^2))
sqrt(mean((Y - pred.loaded)^2))
Auf meinem Computer ist identical(pred, pred.loaded)
FALSE (dh sollte WAHR sein). Hier die Ausgabe der letzten Befehle:
> identical(pred, pred.loaded)
[1] FALSE
> pred[1:10]
[1] -4.7971768 -2.5070562 -0.8889422 -4.9199696 -4.4374819 -0.2739395 -0.9825708 0.4579227 1.3667605 -4.3333349
> pred.loaded[1:10]
[1] -4.7971768 -2.5070562 -0.8889424 -4.9199696 -4.4373770 -0.2739397 -0.9825710 0.4579227 1.3667605 -4.3333349
>
> sqrt(mean((Y - pred)^2))
[1] 0.02890702
> sqrt(mean((Y - pred.loaded)^2))
[1] 0.02890565
Sie sehen, dass die Vorhersagen manchmal leicht abweichen. Können Sie den Beispielcode auf Ihrem Computer erneut ausfĂŒhren und sehen, ob das gleiche Problem auftritt?
Einige zusÀtzliche Informationen zu R und xgboost:
> sessionInfo()
R version 3.6.1 (2019-07-05)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)
Matrix products: default
locale:
[1] LC_COLLATE=English_United States.1252 LC_CTYPE=English_United States.1252 LC_MONETARY=English_United States.1252 LC_NUMERIC=C
[5] LC_TIME=English_United States.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
loaded via a namespace (and not attached):
[1] compiler_3.6.1 magrittr_1.5 Matrix_1.2-17 tools_3.6.1 yaml_2.2.0 xgboost_0.90.0.2 stringi_1.4.3 grid_3.6.1
[9] data.table_1.12.4 lattice_0.20-38
Beachten Sie auch:
> identical(fit$raw, fit.loaded$raw)
[1] TRUE
Danke fĂŒr das Skript. Nur ein Update, ich habe es sowohl in der Json- als auch in der BinĂ€rdatei gespeichert mit:
xgboost::xgb.save(fit, 'booster.json')
fit.loaded <- xgboost::xgb.load('booster.json')
xgboost::xgb.save(fit.loaded, 'booster-1.json')
Die Hashwerte (via sha256sum ./booster.json
) von booster.json
und booster-1.json
sind genau gleich, also vermute ich, dass es irgendwo eine Diskrepanz gibt, die durch Gleitkommaarithmetik verursacht wird.
Warum das Problem schlieĂen, ohne die Ursache zu kennen?
@trivialfis Hast du True fĂŒr identical(pred, pred.loaded)
? Das OP fragt, warum die Vorhersagen nicht ĂŒbereinstimmen, obwohl zwei Modelle dieselbe binĂ€re Signatur haben.
Ich werde versuchen, es selbst zu reproduzieren.
Oh, das tut mir leid. Die Ursache, die ich gefunden habe, ist der Vorhersage-Cache. Nach dem Laden des Modells stammen die Vorhersagewerte aus der echten Vorhersage und nicht aus dem zwischengespeicherten Wert:
Ich vermute also, dass es irgendwo eine Diskrepanz gibt, die durch Gleitkommaarithmetik verursacht wird.
Der Vorhersage-Cache interagiert also auf destruktive Weise mit Gleitkomma-Arithmetik?
@ hcho3 Es ist ein Problem, das ich bei der Implementierung der neuen
Rekonstruieren Sie die DMatrix vor der Vorhersage, um den Cache aus dem Weg zu rÀumen:
dtrain_2 <- xgboost::xgb.DMatrix(data = data.matrix(X), label = Y)
pred <- stats::predict(fit, newdata = dtrain_2)
Es wird den identical
Test bestehen. Andernfalls schlÀgt es fehl.
Bei mehr BĂ€umen weist der identische Test immer noch kleine Unterschiede auf (1e-7 fĂŒr 2000 BĂ€ume). Aber mĂŒssen wir auch in einer Multithread-Umgebung nach und nach identische Ergebnisse erzielen?
Da die Gleitkomma-Summierung nicht assoziativ ist, können wir sie als Aufgabe verwenden, um eine starke Garantie fĂŒr die Berechnungsreihenfolge zu haben, wenn dies gewĂŒnscht wird.
TatsĂ€chlich wird es nicht funktionieren, eine starke Garantie fĂŒr die Bestellung zu geben (wird viel helfen, aber es wird trotzdem Diskrepanzen geben). Ein Gleitkommawert im CPU-FPU-Register kann eine höhere Genauigkeit haben, als er im Speicher gespeichert wird. (Die Hardwareimplementierung kann eine höhere Genauigkeit fĂŒr Zwischenwerte verwenden, https://en.wikipedia.org/wiki/Extended_precision). Mein Punkt ist, wenn das Ergebnis fĂŒr 1000 BĂ€ume innerhalb von 32-Bit-Float genau reproduzierbar ist, ist es unwahrscheinlich, dass es sich um einen Programmierfehler handelt.
Ich stimme zu, dass die Gleitkomma-Summierung nicht assoziativ ist. Ich werde das Skript selbst ausfĂŒhren und sehen, ob der Unterschied klein genug ist, um ihn der Gleitkommaarithmetik zuzuschreiben.
Im Allgemeinen verwende ich normalerweise np.testing.assert_almost_equal
mit decimal=5
, um zu testen, ob zwei Float-Arrays fast gleich sind.
Jep. Entschuldigung fĂŒr das SchlieĂen ohne detaillierte Hinweise.
@hcho3 Irgendein Update?
Ich bin noch nicht drum herum gekommen. Lass mich diese Woche mal nachschauen.
@trivialfis Ich habe es geschafft, den Fehler zu reproduzieren. Ich habe das bereitgestellte Skript ausgefĂŒhrt und FALSE
fĂŒr identical(pred, pred.loaded)
. Ich habe versucht, eine neue DMatrix dtrain_2
erstellen, wie Sie es vorgeschlagen haben, und habe immer noch FALSE
fĂŒr den Test erhalten.
Ausgabe aus dem Skript von
[1] FALSE # identical(pred, pred.loaded)
[1] -4.7760534 -2.5083885 -0.8860036 -4.9163256 -4.4455137 -0.2548684
[7] -0.9745615 0.4646015 1.3602829 -4.3288369 # pred[1:10]
[1] -4.7760534 -2.5083888 -0.8860038 -4.9163256 -4.4454765 -0.2548686
[7] -0.9745617 0.4646015 1.3602829 -4.3288369 # pred.loaded[1:10]
[1] 0.02456085 # MSE on pred
[1] 0.02455945 # MSE on pred.loaded
Ausgabe vom modifizierten Skript mit dtrain_2 <- xgboost::xgb.DMatrix(data = data.matrix(X), label = Y)
:
[1] FALSE # identical(pred, pred.loaded)
[1] -4.7760534 -2.5083885 -0.8860036 -4.9163256 -4.4455137 -0.2548684
[7] -0.9745615 0.4646015 1.3602829 -4.3288369 # pred[1:10]
[1] -4.7760534 -2.5083888 -0.8860038 -4.9163256 -4.4454765 -0.2548686
[7] -0.9745617 0.4646015 1.3602829 -4.3288369 # pred.loaded[1:10]
[1] 0.02456085 # MSE on pred
[1] 0.02455945 # MSE on pred.loaded
Also muss etwas anderes passieren.
Ich habe auch versucht, einen Round-Trip-Test durchzufĂŒhren:
xgboost::xgb.save(fit, 'booster.raw')
fit.loaded <- xgboost::xgb.load('booster.raw')
xgboost::xgb.save(fit.loaded, 'booster.raw.roundtrip')
und die beiden BinÀrdateien booster.raw
und booster.raw.roundtrip
waren identisch.
Der maximale Unterschied zwischen pred
und pred.loaded
betrÀgt 0,0008370876.
Ein kleineres Beispiel, das schneller lÀuft:
library(xgboost)
N <- 5000
set.seed(2020)
X <- data.frame('X1' = rnorm(N), 'X2' = runif(N), 'X3' = rpois(N, lambda = 1))
Y <- with(X, X1 + X2 - X3 + X1*X2^2 - ifelse(X1 > 0, 2, X3))
params <- list(objective = 'reg:squarederror',
max_depth = 5, eta = 0.02, subsammple = 0.5,
base_score = median(Y)
)
dtrain <- xgboost::xgb.DMatrix(data = data.matrix(X), label = Y)
fit <- xgboost::xgb.train(
params = params, data = dtrain,
watchlist = list('train' = dtrain),
nrounds = 10000, verbose = TRUE, print_every_n = 25,
eval_metric = 'mae',
early_stopping_rounds = 3, maximize = FALSE
)
pred <- stats::predict(fit, newdata = dtrain)
invisible(xgboost::xgb.save(fit, 'booster.raw'))
fit.loaded <- xgboost::xgb.load('booster.raw')
invisible(xgboost::xgb.save(fit.loaded, 'booster.raw.roundtrip'))
pred.loaded <- stats::predict(fit.loaded, newdata = dtrain)
identical(pred, pred.loaded)
pred[1:10]
pred.loaded[1:10]
max(abs(pred - pred.loaded))
sqrt(mean((Y - pred)^2))
sqrt(mean((Y - pred.loaded)^2))
Ausgabe:
[1] FALSE
[1] -2.4875379 -0.9452241 -6.9658904 -2.9985323 -4.2192593 -0.8505422
[7] -0.3928839 -1.6886091 -1.3611379 -3.1278882
[1] -2.4875379 -0.9452239 -6.9658904 -2.9985323 -4.2192593 -0.8505420
[7] -0.3928837 -1.6886090 -1.3611377 -3.1278882
[1] 0.0001592636
[1] 0.01370754
[1] 0.01370706
Ich habe gerade versucht, eine zusÀtzliche Rundreise zu machen, und jetzt Àndern sich die Vorhersagen nicht mehr.
library(xgboost)
N <- 5000
set.seed(2020)
X <- data.frame('X1' = rnorm(N), 'X2' = runif(N), 'X3' = rpois(N, lambda = 1))
Y <- with(X, X1 + X2 - X3 + X1*X2^2 - ifelse(X1 > 0, 2, X3))
params <- list(objective = 'reg:squarederror',
max_depth = 5, eta = 0.02, subsammple = 0.5,
base_score = median(Y)
)
dtrain <- xgboost::xgb.DMatrix(data = data.matrix(X), label = Y)
fit <- xgboost::xgb.train(
params = params, data = dtrain,
watchlist = list('train' = dtrain),
nrounds = 10000, verbose = TRUE, print_every_n = 25,
eval_metric = 'mae',
early_stopping_rounds = 3, maximize = FALSE
)
pred <- stats::predict(fit, newdata = dtrain)
invisible(xgboost::xgb.save(fit, 'booster.raw'))
fit.loaded <- xgboost::xgb.load('booster.raw')
invisible(xgboost::xgb.save(fit.loaded, 'booster.raw.roundtrip'))
fit.loaded2 <- xgboost::xgb.load('booster.raw.roundtrip')
pred.loaded <- stats::predict(fit.loaded, newdata = dtrain)
pred.loaded2 <- stats::predict(fit.loaded2, newdata = dtrain)
identical(pred, pred.loaded)
identical(pred.loaded, pred.loaded2)
pred[1:10]
pred.loaded[1:10]
pred.loaded2[1:10]
max(abs(pred - pred.loaded))
max(abs(pred.loaded - pred.loaded2))
sqrt(mean((Y - pred)^2))
sqrt(mean((Y - pred.loaded)^2))
sqrt(mean((Y - pred.loaded2)^2))
Ergebnis:
[1] FALSE
[1] TRUE
[1] -2.4875379 -0.9452241 -6.9658904 -2.9985323 -4.2192593 -0.8505422
[7] -0.3928839 -1.6886091 -1.3611379 -3.1278882
[1] -2.4875379 -0.9452239 -6.9658904 -2.9985323 -4.2192593 -0.8505420
[7] -0.3928837 -1.6886090 -1.3611377 -3.1278882
[1] -2.4875379 -0.9452239 -6.9658904 -2.9985323 -4.2192593 -0.8505420
[7] -0.3928837 -1.6886090 -1.3611377 -3.1278882
[1] 0.0001592636
[1] 0
[1] 0.01370754
[1] 0.01370706
[1] 0.01370706
Vielleicht ist der Vorhersage-Cache also tatsÀchlich ein Problem.
Ich habe das Skript mit deaktiviertem Vorhersage-Caching erneut ausgefĂŒhrt:
diff --git a/src/predictor/cpu_predictor.cc b/src/predictor/cpu_predictor.cc
index ebc15128..c40309bc 100644
--- a/src/predictor/cpu_predictor.cc
+++ b/src/predictor/cpu_predictor.cc
@@ -259,7 +259,7 @@ class CPUPredictor : public Predictor {
// delta means {size of forest} * {number of newly accumulated layers}
uint32_t delta = end_version - beg_version;
CHECK_LE(delta, model.trees.size());
- predts->Update(delta);
+ //predts->Update(delta);
CHECK(out_preds->Size() == output_groups * dmat->Info().num_row_ ||
out_preds->Size() == dmat->Info().num_row_);
(Das Deaktivieren des Vorhersage-Caching fĂŒhrt zu einem sehr langsamen Training.)
Ausgabe:
[1] FALSE
[1] TRUE
[1] -2.4908853 -0.9507379 -6.9615889 -2.9935317 -4.2165089 -0.8543566
[7] -0.3940181 -1.6930715 -1.3572118 -3.1403396
[1] -2.4908853 -0.9507380 -6.9615889 -2.9935317 -4.2165089 -0.8543567
[7] -0.3940183 -1.6930716 -1.3572119 -3.1403399
[1] -2.4908853 -0.9507380 -6.9615889 -2.9935317 -4.2165089 -0.8543567
[7] -0.3940183 -1.6930716 -1.3572119 -3.1403399
[1] 0.0001471043
[1] 0
[1] 0.01284297
[1] 0.01284252
[1] 0.01284252
Der Vorhersage-Cache ist also definitiv NICHT die Ursache fĂŒr diesen Fehler.
Auch die Blattvorhersagen gehen auseinander:
invisible(xgboost::xgb.save(fit, 'booster.raw'))
fit.loaded <- xgboost::xgb.load('booster.raw')
invisible(xgboost::xgb.save(fit.loaded, 'booster.raw.roundtrip'))
fit.loaded2 <- xgboost::xgb.load('booster.raw.roundtrip')
x <- predict(fit, newdata = dtrain2, predleaf = TRUE)
x2 <- predict(fit.loaded, newdata = dtrain2, predleaf = TRUE)
x3 <- predict(fit.loaded2, newdata = dtrain2, predleaf = TRUE)
identical(x, x2)
identical(x2, x3)
Ausgabe:
[1] FALSE
[1] TRUE
Geheimnis gelĂŒftet. Ich habe die wahre Ursache identifiziert. Beim Speichern des Modells auf der Festplatte werden Informationen zum vorzeitigen Stoppen verworfen. Im Beispiel fĂŒhrt XGBoost 6381 Boosting-Runden aus und findet das beste Modell bei 6378 Runden. Das Modellobjekt im Speicher enthĂ€lt 6381 BĂ€ume, nicht 6378 BĂ€ume, da kein Baum entfernt wird. Es gibt ein zusĂ€tzliches Feld best_iteration
, das sich daran erinnert, welche Iteration die beste war:
> fit$best_iteration
[1] 6378
Dieses zusÀtzliche Feld wird stillschweigend verworfen, wenn wir das Modell auf der Festplatte speichern. So verwendet predict()
mit dem ursprĂŒnglichen Modell 6378 BĂ€ume, wĂ€hrend predict()
mit dem wiederhergestellten Modell 6381 BĂ€ume verwendet.
> x <- predict(fit, newdata = dtrain2, predleaf = TRUE)
> x2 <- predict(fit.loaded, newdata = dtrain2, predleaf = TRUE)
> dim(x)
[1] 5000 6378
> dim(x2)
[1] 5000 6381
@trivialfis Ich neige dazu, BĂ€ume physisch zu entfernen. Wenn das Training bei 6381 Runden endete und die beste Iteration bei 6378 Runden war, erwarten Benutzer, dass das endgĂŒltige Modell 6378 BĂ€ume enthĂ€lt.
@hcho3 Ich denke, es ist ein Àhnliches Problem in https://github.com/dmlc/xgboost/issues/4052 .
Die bset_iteration
sollten in Learner::attributes_
gespeichert werden, auf das ĂŒber xgboost::xgb.attr
zugegriffen werden kann.
@hcho3 , schöner Fund!
Beachten Sie auch die Dokumentation von xgboost:::predict.xgb.Booster()
:
Wenn ich das richtig verstehe, ist die Dokumentation nicht ganz korrekt? Basierend auf der Dokumentation hatte ich erwartet, dass die Vorhersage bereits alle BĂ€ume verwendet. Dies hatte ich leider nicht verifiziert.
@DavorJ Wenn das frĂŒhe Stoppen aktiviert ist, verwendet predict()
das Feld best_iteration
, um eine Vorhersage zu erhalten.
@trivialfis Die Situation ist auf Python-Seite schlimmer, da xgb.predict()
keine Informationen aus einem frĂŒhen Stoppen verwendet:
import xgboost as xgb
import numpy as np
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
X, y = load_boston(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)
params = {'objective': 'reg:squarederror'}
bst = xgb.train(params, dtrain, 100, [(dtrain, 'train'), (dtest, 'test')],
early_stopping_rounds=5)
x = bst.predict(dtrain, pred_leaf=True)
x2 = bst.predict(dtrain, pred_leaf=True, ntree_limit=bst.best_iteration)
print(x.shape)
print(x2.shape)
pred = bst.predict(dtrain)
pred2 = bst.predict(dtrain, ntree_limit=bst.best_iteration)
print(np.max(np.abs(pred - pred2)))
Ausgabe:
Will train until test-rmse hasn't improved in 5 rounds.
[1] train-rmse:12.50316 test-rmse:11.92709
...
[25] train-rmse:0.56720 test-rmse:2.56874
[26] train-rmse:0.54151 test-rmse:2.56722
[27] train-rmse:0.51842 test-rmse:2.56124
[28] train-rmse:0.47489 test-rmse:2.56640
[29] train-rmse:0.45489 test-rmse:2.58780
[30] train-rmse:0.43093 test-rmse:2.59385
[31] train-rmse:0.41865 test-rmse:2.59364
[32] train-rmse:0.40823 test-rmse:2.59465
Stopping. Best iteration:
[27] train-rmse:0.51842 test-rmse:2.56124
(404, 33)
(404, 27)
0.81269073
Benutzer mĂŒssen daran denken, bst.best_iteration
zu holen und es als ntree_limit
Argument zu ĂŒbergeben, wenn sie predict()
aufrufen. Dies ist fehleranfĂ€llig und sorgt fĂŒr eine unangenehme Ăberraschung.
Wir haben zwei Möglichkeiten zur Behebung:
best_iteration
.best_iteration
Informationen bei, wenn Sie das Modell serialisieren, und lassen Sie sie von der predict()
Funktion verwenden.@hcho3 Ich habe eine halbfertige Idee dazu, die auch mit unserer Option process_type = update
und Wald zusammenhÀngt.
FĂŒr eine kurze Zusammenfassung der Probleme, die wir mit update
, wenn num_boost_round
das mit update
wird, kleiner ist als die Anzahl der bereits vorhandenen BĂ€ume, werden die nicht aktualisierten BĂ€ume entfernt .
FĂŒr eine kurze EinfĂŒhrung in die Probleme mit dem Wald: best_iteration
gilt nicht fĂŒr den Wald, da die Funktion predict
eine bestimmte Anzahl von BĂ€umen anstelle einer Iteration erfordert, also gibt es in Python etwas namens best_ntree_limit
, was mich sehr verwirrt. Ich habe ntree_limit
in inplace_predict
explizit durch ntree_limit
iteration_range
, um dieses Attribut zu vermeiden.
Ich möchte slice
und concat
booster
hinzufĂŒgen, die die BĂ€ume in 2 Modelle extrahieren und BĂ€ume aus 2 Modellen in 1 verketten. Wenn wir diese 2 Methoden haben :
base_margin_
wird nicht mehr benötigt und ich glaube, es ist fĂŒr andere Benutzer intuitiver.ntree_limit
in der Vorhersage wird nicht mehr benötigt, wir schneiden einfach das Modell und fĂŒhren die Vorhersage auf den Slices aus.update
Prozess ist in sich abgeschlossen, aktualisieren Sie einfach die BĂ€ume in Slices auf einmal, kein num_boost_rounds
.Ich glaube auch, dass dies irgendwie mit Multi-Target-BĂ€umen verbunden ist. Als ob wir Multi-Class - Multi-Target - BĂ€ume in der Zukunft unterstĂŒtzen können, gibt es mehr Möglichkeiten , um BĂ€ume zu arrangieren, wie mit output_groups
fĂŒr jede Klasse oder jedes Ziel, mit Wald und Vektor - Blatt Paarung. ntree_limit
wird nicht ausreichen.
Auch #5531.
Aber die Idee ist noch ziemlich frĂŒh, also hatte ich nicht das Vertrauen, sie zu teilen. Jetzt sind wir bei diesem Thema, vielleicht kann ich einige Anregungen dazu bekommen.
Können wir angesichts des Zeitplans von 1.1 die Dokumentation erweitern, um zu verdeutlichen, wie Benutzer diese beste Iteration bei der Vorhersage manuell erfassen und verwenden mĂŒssen?
Und es zu bekannten Problemen in den Versionshinweisen hinzufĂŒgen?
@trivialfis klingt interessant, solange wir Konfigurationsprobleme dadurch nicht weiter verkomplizieren.
Das Löschen der zusĂ€tzlichen BĂ€ume aus dem Modell, wie von @hcho3 vorgeschlagen, ist ansprechend, da wir uns nicht mit Inkonsistenzen durch die gleichzeitige Verwendung einer tatsĂ€chlichen ModelllĂ€nge auseinandersetzen mĂŒssen.
Hilfreichster Kommentar
Geheimnis gelĂŒftet. Ich habe die wahre Ursache identifiziert. Beim Speichern des Modells auf der Festplatte werden Informationen zum vorzeitigen Stoppen verworfen. Im Beispiel fĂŒhrt XGBoost 6381 Boosting-Runden aus und findet das beste Modell bei 6378 Runden. Das Modellobjekt im Speicher enthĂ€lt 6381 BĂ€ume, nicht 6378 BĂ€ume, da kein Baum entfernt wird. Es gibt ein zusĂ€tzliches Feld
best_iteration
, das sich daran erinnert, welche Iteration die beste war:Dieses zusÀtzliche Feld wird stillschweigend verworfen, wenn wir das Modell auf der Festplatte speichern. So verwendet
predict()
mit dem ursprĂŒnglichen Modell 6378 BĂ€ume, wĂ€hrendpredict()
mit dem wiederhergestellten Modell 6381 BĂ€ume verwendet.