Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

suppress alias warnings with verbosity<0 (fixes #4518) #5253

Merged
merged 18 commits into from
Oct 11, 2022
Merged
Show file tree
Hide file tree
Changes from 14 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
4 changes: 3 additions & 1 deletion include/LightGBM/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ struct Config {
*/
inline static bool SortAlias(const std::string& x, const std::string& y);

static void KV2Map(std::unordered_map<std::string, std::string>* params, const char* kv);
static void KeepFirstValueFromKeys(const std::unordered_map<std::string, std::vector<std::string>>& params, std::unordered_map<std::string, std::string>* out);
static void KV2Map(std::unordered_map<std::string, std::vector<std::string>>* params, const char* kv);
static void SetVerbosity(const std::unordered_map<std::string, std::vector<std::string>>& params);
static std::unordered_map<std::string, std::string> Str2Map(const char* parameters);

#ifndef __NVCC__
Expand Down
23 changes: 13 additions & 10 deletions src/application/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ Application::~Application() {
}

void Application::LoadParameters(int argc, char** argv) {
std::unordered_map<std::string, std::vector<std::string>> all_params;
std::unordered_map<std::string, std::string> params;
for (int i = 1; i < argc; ++i) {
Config::KV2Map(&params, argv[i]);
Config::KV2Map(&all_params, argv[i]);
}
// check for alias
ParameterAlias::KeyAliasTransform(&params);
// read parameters from config file
if (params.count("config") > 0) {
TextReader<size_t> config_reader(params["config"].c_str(), false);
bool config_file_ok = true;
if (all_params.count("config") > 0) {
TextReader<size_t> config_reader(all_params["config"][0].c_str(), false);
config_reader.ReadAllLines();
if (!config_reader.Lines().empty()) {
for (auto& line : config_reader.Lines()) {
Expand All @@ -68,16 +68,19 @@ void Application::LoadParameters(int argc, char** argv) {
if (line.size() == 0) {
continue;
}
Config::KV2Map(&params, line.c_str());
Config::KV2Map(&all_params, line.c_str());
}
} else {
Log::Warning("Config file %s doesn't exist, will ignore",
params["config"].c_str());
config_file_ok = false;
}
}
// check for alias again
Config::SetVerbosity(all_params);
// de-duplicate params
Config::KeepFirstValueFromKeys(all_params, &params);
if (!config_file_ok) {
Log::Warning("Config file %s doesn't exist, will ignore", params["config"].c_str());
}
ParameterAlias::KeyAliasTransform(&params);
// load configs
config_.Set(params);
Log::Info("Finished loading parameters");
}
Expand Down
65 changes: 45 additions & 20 deletions src/io/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace LightGBM {

void Config::KV2Map(std::unordered_map<std::string, std::string>* params, const char* kv) {
void Config::KV2Map(std::unordered_map<std::string, std::vector<std::string>>* params, const char* kv) {
std::vector<std::string> tmp_strs = Common::Split(kv, '=');
if (tmp_strs.size() == 2 || tmp_strs.size() == 1) {
std::string key = Common::RemoveQuotationSymbol(Common::Trim(tmp_strs[0]));
Expand All @@ -22,26 +22,61 @@ void Config::KV2Map(std::unordered_map<std::string, std::string>* params, const
value = Common::RemoveQuotationSymbol(Common::Trim(tmp_strs[1]));
}
if (key.size() > 0) {
auto value_search = params->find(key);
if (value_search == params->end()) { // not set
params->emplace(key, value);
} else {
Log::Warning("%s is set=%s, %s=%s will be ignored. Current value: %s=%s",
key.c_str(), value_search->second.c_str(), key.c_str(), value.c_str(),
key.c_str(), value_search->second.c_str());
}
params->operator[](key).emplace_back(value);
}
} else {
Log::Warning("Unknown parameter %s", kv);
}
}

void RetrieveFirstValueFromKey(const std::unordered_map<std::string, std::vector<std::string>>& params, std::string key, int* out) {
jmoralez marked this conversation as resolved.
Show resolved Hide resolved
const auto pair = params.find(key);
if (pair != params.end()) {
auto candidate = pair->second[0].c_str();
if (!Common::AtoiAndCheck(candidate, out)) {
Log::Fatal("Parameter %s should be of type int, got \"%s\"", key.c_str(), candidate);
}
}
}

void Config::SetVerbosity(const std::unordered_map<std::string, std::vector<std::string>>& params) {
int verbosity = Config().verbosity;
jmoralez marked this conversation as resolved.
Show resolved Hide resolved
RetrieveFirstValueFromKey(params, "verbose", &verbosity);
RetrieveFirstValueFromKey(params, "verbosity", &verbosity);
if (verbosity < 0) {
LightGBM::Log::ResetLogLevel(LightGBM::LogLevel::Fatal);
} else if (verbosity == 0) {
LightGBM::Log::ResetLogLevel(LightGBM::LogLevel::Warning);
} else if (verbosity == 1) {
LightGBM::Log::ResetLogLevel(LightGBM::LogLevel::Info);
} else {
LightGBM::Log::ResetLogLevel(LightGBM::LogLevel::Debug);
}
}

void Config::KeepFirstValueFromKeys(const std::unordered_map<std::string, std::vector<std::string>>& params, std::unordered_map<std::string, std::string>* out) {
for (auto pair = params.begin(); pair != params.end(); ++pair) {
auto name = pair->first.c_str();
auto values = pair->second;
out->emplace(name, values[0]);
for (size_t i = 1; i < pair->second.size(); ++i) {
Log::Warning("%s is set=%s, %s=%s will be ignored. Current value: %s=%s",
name, values[0].c_str(),
name, values[i].c_str(),
name, values[0].c_str());
}
}
}

std::unordered_map<std::string, std::string> Config::Str2Map(const char* parameters) {
std::unordered_map<std::string, std::vector<std::string>> all_params;
std::unordered_map<std::string, std::string> params;
auto args = Common::Split(parameters, " \t\n\r");
for (auto arg : args) {
KV2Map(&params, Common::Trim(arg).c_str());
KV2Map(&all_params, Common::Trim(arg).c_str());
}
SetVerbosity(all_params);
KeepFirstValueFromKeys(all_params, &params);
ParameterAlias::KeyAliasTransform(&params);
return params;
}
Expand Down Expand Up @@ -240,16 +275,6 @@ void Config::Set(const std::unordered_map<std::string, std::string>& params) {
save_binary = true;
}

if (verbosity == 1) {
jmoralez marked this conversation as resolved.
Show resolved Hide resolved
LightGBM::Log::ResetLogLevel(LightGBM::LogLevel::Info);
} else if (verbosity == 0) {
LightGBM::Log::ResetLogLevel(LightGBM::LogLevel::Warning);
} else if (verbosity >= 2) {
LightGBM::Log::ResetLogLevel(LightGBM::LogLevel::Debug);
} else {
LightGBM::Log::ResetLogLevel(LightGBM::LogLevel::Fatal);
}

// check for conflicts
CheckParamConflict();
}
Expand Down
42 changes: 42 additions & 0 deletions tests/python_package_test/test_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pickle
import platform
import random
import re
from os import getenv
from pathlib import Path

Expand Down Expand Up @@ -3661,6 +3662,47 @@ def test_cegb_split_buffer_clean():
assert rmse < 10.0


def test_verbosity_and_verbose(capsys):
X, y = make_synthetic_regression()
ds = lgb.Dataset(X, y)
params = {
'num_leaves': 3,
'verbose': 1,
'verbosity': 0,
}
lgb.train(params, ds, num_boost_round=1)
expected_msg = (
'[LightGBM] [Warning] verbosity is set=0, verbose=1 will be ignored. '
'Current value: verbosity=0'
)
stdout = capsys.readouterr().out
assert expected_msg in stdout


@pytest.mark.parametrize('verbosity_param', lgb.basic._ConfigAliases.get("verbosity"))
@pytest.mark.parametrize('verbosity', [-1, 0])
jmoralez marked this conversation as resolved.
Show resolved Hide resolved
def test_verbosity_can_suppress_alias_warnings(capsys, verbosity_param, verbosity):
jmoralez marked this conversation as resolved.
Show resolved Hide resolved
X, y = make_synthetic_regression()
ds = lgb.Dataset(X, y)
params = {
'num_leaves': 3,
'subsample': 0.75,
'bagging_fraction': 0.8,
'force_col_wise': True,
verbosity_param: verbosity,
}
lgb.train(params, ds, num_boost_round=1)
expected_msg = (
'[LightGBM] [Warning] bagging_fraction is set=0.8, subsample=0.75 will be ignored. '
'Current value: bagging_fraction=0.8'
)
stdout = capsys.readouterr().out
if verbosity >= 0:
assert expected_msg in stdout
else:
assert re.search(r'\[LightGBM\]', stdout) is None


@pytest.mark.skipif(not PANDAS_INSTALLED, reason='pandas is not installed')
def test_validate_features():
X, y = make_synthetic_regression()
Expand Down