scikit-learn / scikit-learn

scikit-learn: machine learning in Python
https://scikit-learn.org
BSD 3-Clause "New" or "Revised" License
59.23k stars 25.22k forks source link

ConvergenceWarnings cannot be turned off #29294

Open u3Izx9ql7vW4 opened 2 months ago

u3Izx9ql7vW4 commented 2 months ago

Hi, I'm unable to turn off convergence warnings from GraphicalLassoCV.

I've tried most of the solutions from, and none of them worked (see below for actual implementations): https://stackoverflow.com/questions/879173/how-to-ignore-deprecation-warnings-in-python https://stackoverflow.com/questions/32612180/eliminating-warnings-from-scikit-learn/33812427#33812427 https://stackoverflow.com/questions/53968004/how-to-silence-all-sklearn-warning https://stackoverflow.com/questions/14463277/how-to-disable-python-warnings

Contrary to what the designers of the sklearn's exceptions must have thought when it was implemented, some of us actually use stdout to log important information of the host program for diagnostics purposes. Flooding it with garbage that cannot be turned off, as is in the case with cross-validation, is not ok.

To briefly speak to the severity of the issue, the above sklearn-specific questions relating to suppressing warnings have been viewed ~500K times with combined ~400 upvotes, and dates back 7 years.

I've tried the following (n_jobs parameter does not appear to affect the result):

from sklearn.covariance import GraphicalLassoCV
import warnings
warnings.filterwarnings("ignore", category=ConvergenceWarning)

model = GraphicalLassoCV(n_jobs=4)
model = model.fit(data)
from sklearn.covariance import GraphicalLassoCV
import warnings
warnings.filterwarnings(action='ignore')

model = GraphicalLassoCV(n_jobs=4)
model = model.fit(data)
import warnings
with warnings.catch_warnings():
    warnings.simplefilter("ignore", ConvergenceWarning)

    model = GraphicalLassoCV(n_jobs=4)
    model = model.fit(data)
from sklearn.covariance import GraphicalLassoCV
def warn(*args, **kwargs):
    pass
import warnings
warnings.warn = warn

model = GraphicalLassoCV(n_jobs=4)
model = model.fit(data)
import contextlib
import os, sys

@contextlib.contextmanager
def suppress_stdout():
    with open(os.devnull, 'w') as fnull:
        old_stdout = sys.stdout
        sys.stdout = fnull
        try:
            yield
        finally:
            sys.stdout = old_stdout

with suppress_stdout():
    model = GraphicalLassoCV(n_jobs=4)
    model = model.fit(data)
import logging
logging.captureWarnings(True)

logging.getLogger("py.warnings").setLevel(logging.ERROR)

model = GraphicalLassoCV(n_jobs=4)
model = model.fit(data)
lesteve commented 2 months ago

If you give a fully stand-alone example, in particular some data that triggers a warning, this may give you a lot more chance that someone tries to look into this :pray:.

I would expect that warnings.simplefilter would work (I am guessing you did the right import to have ConvergenceWarning defined although you have not included it), but maybe there are subtleties involved with subprocesses, not sure ...

lesteve commented 2 months ago

Hmmm looking at SO myself, it seems like indeed this is subprocesses with joblib, see this answer.

Basically warnings filters only applied to the main process and not the subprocesses. One proposed solution in the SO answer is to:

@u3Izx9ql7vW4 can you confirm this fixes the issue for you?

In an ideal world, you would not need this work-around. In our imperfect world, I don't really know if there is some magic we can do in joblib and/or loky to have the subprocesses inherit the warnings filters from the main process ...

In any cases this should be an issue in joblib I think: I opened https://github.com/joblib/joblib/issues/1591.

An alternative may actually be to use our already existing joblib wrappers like delayed to apply the warning filters to subprocesses, not sure how doable this is and that would be scikit-learn specific.

ogrisel commented 2 months ago

In the future we will all use free-threading CPython 3.13 or later and use a threading backend instead of subprocesses :)

lesteve commented 2 months ago

In the future we will all use free-threading CPython 3.13 or later and use a threading backend instead of subprocesses :)

Yeah that's the ideal world future :crossed_fingers: but still some road to get there :wink:

jeremiedbb commented 2 months ago

We could add an option to disable convergence warnings (or warning of a given category) in the global config and define our own warn function that would check the global config to trigger or not the warning. It should work in all settings since the global config is now propagated to sub-processes.

lesteve commented 2 months ago

We could add an option to disable convergence warnings (or warning of a given category) in the global config and define our own warn function that would check the global config to trigger or not the warning.

Good point indeed! We could indeed, whether we should is another question, since free-threading is coming :crossed_fingers: and there is some kind of not so great but at least existing work-around :cold_sweat: ...

Edit: thinking about it more, the config-based solution, may be a reasonable stop-gap solution, I guess someone maybe should have a closer look? Maybe an issue for a sprint? Personally I am not planning to look at it in the near-future. I am going to set the label "Help Wanted"