Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,34 @@ VisdomSklearnLogger.autolog(viz, env="sklearn_run")

See `example/train_sklearn_example.py` for a full working example covering plain estimators and grid search.

### XGBoost

`visdom.loggers.VisdomXGBLogger` implements XGBoost's `TrainingCallback` protocol, plotting train/eval metrics to Visdom after every boosting round.

There was no way to visualize XGBoost training runs in Visdom without manually attaching a `TrainingCallback` and wiring up `viz.line()` calls yourself. This adds opt-in auto-logging behind a single `autolog()` call, with no changes required to model, `train()`, or `fit()` code.

```python
import xgboost as xgb
import visdom
from visdom.loggers import VisdomXGBLogger

viz = visdom.Visdom()
VisdomXGBLogger.autolog(viz, env="xgb_run")

booster = xgb.train(params, dtrain, evals=[(dtrain, "train"), (dval, "eval")]) # logged automatically
clf = xgb.XGBClassifier().fit(X_train, y_train, eval_set=[(X_val, y_val)]) # logged automatically
xgb.cv(params, dtrain, nfold=3) # logged automatically
```

Or attach a logger to a single run without patching anything:

```python
callback = VisdomXGBLogger(viz, env="xgb_run")
booster = xgb.train(params, dtrain, evals=[(dtrain, "train"), (dval, "eval")], callbacks=[callback])
```

Each eval metric gets its own window with one trace per data name (`train`/`eval`), and `best_iteration`/`best_score` are logged as a text pane once training finishes. See `example/train_xgboost_example.py` for a full working example.

## Details
<img src="https://user-images.githubusercontent.com/19650074/198747904-7a8a580f-851a-45fb-8f45-94e54a910ee2.png"/>

Expand Down
45 changes: 45 additions & 0 deletions example/train_xgboost_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import xgboost as xgb
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split

import visdom
from visdom.loggers import VisdomXGBLogger


def main():
# synthetic classification: 500 samples, 20 features, 2 classes
X, y = make_classification(
n_samples=500,
n_features=20,
n_informative=10,
random_state=42,
)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)

viz = visdom.Visdom()
VisdomXGBLogger.autolog(viz, env="xgboost_run")

# functional API -> train/eval logloss curves logged automatically
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)
booster = xgb.train(
{"objective": "binary:logistic", "eval_metric": "logloss"},
dtrain,
num_boost_round=50,
evals=[(dtrain, "train"), (dtest, "eval")],
)

# sklearn API -> same curves logged automatically via patched fit()
clf = xgb.XGBClassifier(n_estimators=50, eval_metric="logloss")
clf.fit(X_train, y_train, eval_set=[(X_test, y_test)])

preds = (booster.predict(dtest) > 0.5).astype(int)
accuracy = (preds == y_test).mean()
print("Booster accuracy: {:.4f}".format(accuracy))
print("XGBClassifier accuracy: {:.4f}".format(clf.score(X_test, y_test)))


if __name__ == "__main__":
main()
7 changes: 7 additions & 0 deletions py/visdom/loggers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,10 @@
from visdom.loggers.sklearn import VisdomSklearnLogger

__all__ = ["VisdomLogger", "VisdomSklearnLogger"]

try:
from visdom.loggers.xgboost import VisdomXGBLogger

__all__.append("VisdomXGBLogger")
except ImportError:
pass
Loading
Loading