chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
# coding: utf-8
|
||||
import logging
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
import lightgbm as lgb
|
||||
|
||||
|
||||
def test_register_logger(tmp_path):
|
||||
logger = logging.getLogger("LightGBM")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
formatter = logging.Formatter("%(levelname)s | %(message)s")
|
||||
log_filename = tmp_path / "LightGBM_test_logger.log"
|
||||
file_handler = logging.FileHandler(log_filename, mode="w", encoding="utf-8")
|
||||
file_handler.setLevel(logging.DEBUG)
|
||||
file_handler.setFormatter(formatter)
|
||||
logger.addHandler(file_handler)
|
||||
|
||||
def dummy_metric(_, __):
|
||||
logger.debug("In dummy_metric")
|
||||
return "dummy_metric", 1, True
|
||||
|
||||
lgb.register_logger(logger)
|
||||
|
||||
X = np.array([[1, 2, 3], [1, 2, 4], [1, 2, 4], [1, 2, 3]], dtype=np.float32)
|
||||
y = np.array([0, 1, 1, 0])
|
||||
lgb_train = lgb.Dataset(X, y, categorical_feature=[1])
|
||||
lgb_valid = lgb.Dataset(X, y, categorical_feature=[1]) # different object for early-stopping
|
||||
|
||||
eval_records = {}
|
||||
callbacks = [lgb.record_evaluation(eval_records), lgb.log_evaluation(2), lgb.early_stopping(10)]
|
||||
lgb.train(
|
||||
{"objective": "binary", "metric": ["auc", "binary_error"], "verbose": 1},
|
||||
lgb_train,
|
||||
num_boost_round=10,
|
||||
feval=dummy_metric,
|
||||
valid_sets=[lgb_valid],
|
||||
callbacks=callbacks,
|
||||
)
|
||||
|
||||
lgb.plot_metric(eval_records)
|
||||
|
||||
expected_log = r"""
|
||||
INFO | [LightGBM] [Warning] There are no meaningful features which satisfy the provided configuration. Decreasing Dataset parameters min_data_in_bin or min_data_in_leaf and re-constructing Dataset might resolve this warning.
|
||||
INFO | [LightGBM] [Info] Number of positive: 2, number of negative: 2
|
||||
INFO | [LightGBM] [Info] Total Bins 0
|
||||
INFO | [LightGBM] [Info] Number of data points in the train set: 4, number of used features: 0
|
||||
INFO | [LightGBM] [Info] [binary:BoostFromScore]: pavg=0.500000 -> initscore=0.000000
|
||||
INFO | [LightGBM] [Warning] Stopped training because there are no more leaves that meet the split requirements
|
||||
DEBUG | In dummy_metric
|
||||
INFO | Training until validation scores don't improve for 10 rounds
|
||||
INFO | [LightGBM] [Warning] Stopped training because there are no more leaves that meet the split requirements
|
||||
DEBUG | In dummy_metric
|
||||
INFO | [2] valid_0's auc: 0.5 valid_0's binary_error: 0.5 valid_0's dummy_metric: 1
|
||||
INFO | [LightGBM] [Warning] Stopped training because there are no more leaves that meet the split requirements
|
||||
DEBUG | In dummy_metric
|
||||
INFO | [LightGBM] [Warning] Stopped training because there are no more leaves that meet the split requirements
|
||||
DEBUG | In dummy_metric
|
||||
INFO | [4] valid_0's auc: 0.5 valid_0's binary_error: 0.5 valid_0's dummy_metric: 1
|
||||
INFO | [LightGBM] [Warning] Stopped training because there are no more leaves that meet the split requirements
|
||||
DEBUG | In dummy_metric
|
||||
INFO | [LightGBM] [Warning] Stopped training because there are no more leaves that meet the split requirements
|
||||
DEBUG | In dummy_metric
|
||||
INFO | [6] valid_0's auc: 0.5 valid_0's binary_error: 0.5 valid_0's dummy_metric: 1
|
||||
INFO | [LightGBM] [Warning] Stopped training because there are no more leaves that meet the split requirements
|
||||
DEBUG | In dummy_metric
|
||||
INFO | [LightGBM] [Warning] Stopped training because there are no more leaves that meet the split requirements
|
||||
DEBUG | In dummy_metric
|
||||
INFO | [8] valid_0's auc: 0.5 valid_0's binary_error: 0.5 valid_0's dummy_metric: 1
|
||||
INFO | [LightGBM] [Warning] Stopped training because there are no more leaves that meet the split requirements
|
||||
DEBUG | In dummy_metric
|
||||
INFO | [LightGBM] [Warning] Stopped training because there are no more leaves that meet the split requirements
|
||||
DEBUG | In dummy_metric
|
||||
INFO | [10] valid_0's auc: 0.5 valid_0's binary_error: 0.5 valid_0's dummy_metric: 1
|
||||
INFO | Did not meet early stopping. Best iteration is:
|
||||
[1] valid_0's auc: 0.5 valid_0's binary_error: 0.5 valid_0's dummy_metric: 1
|
||||
WARNING | More than one metric available, picking one to plot.
|
||||
""".strip()
|
||||
|
||||
gpu_lines = [
|
||||
"INFO | [LightGBM] [Info] This is the GPU trainer",
|
||||
"INFO | [LightGBM] [Info] Using GPU Device:",
|
||||
"INFO | [LightGBM] [Info] Compiling OpenCL Kernel with 16 bins...",
|
||||
"INFO | [LightGBM] [Info] GPU programs have been built",
|
||||
"INFO | [LightGBM] [Warning] GPU acceleration is disabled because no non-trivial dense features can be found",
|
||||
"INFO | [LightGBM] [Warning] Using sparse features with CUDA is currently not supported.",
|
||||
"INFO | [LightGBM] [Warning] CUDA currently requires double precision calculations.",
|
||||
"INFO | [LightGBM] [Info] LightGBM using CUDA trainer with DP float!!",
|
||||
]
|
||||
cuda_lines = [
|
||||
"INFO | [LightGBM] [Warning] Metric auc is not implemented in cuda version. Fall back to evaluation on CPU.",
|
||||
"INFO | [LightGBM] [Warning] Metric binary_error is not implemented in cuda version. Fall back to evaluation on CPU.",
|
||||
]
|
||||
with open(log_filename, "rt", encoding="utf-8") as f:
|
||||
actual_log = f.read().strip()
|
||||
actual_log_wo_gpu_stuff = []
|
||||
for line in actual_log.split("\n"):
|
||||
if not any(line.startswith(gpu_or_cuda_line) for gpu_or_cuda_line in gpu_lines + cuda_lines):
|
||||
actual_log_wo_gpu_stuff.append(line)
|
||||
|
||||
assert "\n".join(actual_log_wo_gpu_stuff) == expected_log
|
||||
|
||||
|
||||
def test_register_invalid_logger():
|
||||
class LoggerWithoutInfoMethod:
|
||||
def warning(self, msg: str) -> None:
|
||||
print(msg)
|
||||
|
||||
class LoggerWithoutWarningMethod:
|
||||
def info(self, msg: str) -> None:
|
||||
print(msg)
|
||||
|
||||
class LoggerWithAttributeNotCallable:
|
||||
def __init__(self):
|
||||
self.info = 1
|
||||
self.warning = 2
|
||||
|
||||
expected_error_message = "Logger must provide 'info' and 'warning' method"
|
||||
|
||||
with pytest.raises(TypeError, match=expected_error_message):
|
||||
lgb.register_logger(LoggerWithoutInfoMethod())
|
||||
|
||||
with pytest.raises(TypeError, match=expected_error_message):
|
||||
lgb.register_logger(LoggerWithoutWarningMethod())
|
||||
|
||||
with pytest.raises(TypeError, match=expected_error_message):
|
||||
lgb.register_logger(LoggerWithAttributeNotCallable())
|
||||
|
||||
|
||||
def test_register_custom_logger():
|
||||
logged_messages = []
|
||||
|
||||
class CustomLogger:
|
||||
def custom_info(self, msg: str) -> None:
|
||||
logged_messages.append(msg)
|
||||
|
||||
def custom_warning(self, msg: str) -> None:
|
||||
logged_messages.append(msg)
|
||||
|
||||
custom_logger = CustomLogger()
|
||||
lgb.register_logger(custom_logger, info_method_name="custom_info", warning_method_name="custom_warning")
|
||||
|
||||
lgb.basic._log_info("info message")
|
||||
lgb.basic._log_warning("warning message")
|
||||
|
||||
expected_log = ["info message", "warning message"]
|
||||
assert logged_messages == expected_log
|
||||
|
||||
logged_messages = []
|
||||
X = np.array([[1, 2, 3], [1, 2, 4], [1, 2, 4], [1, 2, 3]], dtype=np.float32)
|
||||
y = np.array([0, 1, 1, 0])
|
||||
lgb_data = lgb.Dataset(X, y, categorical_feature=[1])
|
||||
lgb.train(
|
||||
{"objective": "binary", "metric": "auc"},
|
||||
lgb_data,
|
||||
num_boost_round=10,
|
||||
valid_sets=[lgb_data],
|
||||
)
|
||||
assert logged_messages, "custom logger was not called"
|
||||
Reference in New Issue
Block a user