diff --git a/modules/trainer/BaseTrainer.py b/modules/trainer/BaseTrainer.py index 20fc5eb7a..e4b7a3b29 100644 --- a/modules/trainer/BaseTrainer.py +++ b/modules/trainer/BaseTrainer.py @@ -97,7 +97,13 @@ def _start_tensorboard(self): if self.config.tensorboard_expose: tensorboard_args.append("--bind_all") - self.tensorboard_subprocess = subprocess.Popen(tensorboard_args) + # Discard the tensorboard child's stdout/stderr: the TF-not-found notice, the + # experimental-data-loading NOTE and the serving banner are all noise, and the + # UI already exposes the tensorboard URL. Popen still raises if the executable + # is missing, so a real launch failure is not hidden. + self.tensorboard_subprocess = subprocess.Popen( + tensorboard_args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, + ) def _stop_tensorboard(self): self.tensorboard_subprocess.kill() diff --git a/modules/ui/TrainUIController.py b/modules/ui/TrainUIController.py index 72623def4..2c4896226 100644 --- a/modules/ui/TrainUIController.py +++ b/modules/ui/TrainUIController.py @@ -103,8 +103,13 @@ def _start_always_on_tensorboard(self): if self.train_config.tensorboard_expose: tensorboard_args.append("--bind_all") + # Discard the tensorboard child's stdout/stderr: the TF-not-found notice, the + # experimental-data-loading NOTE and the serving banner are all noise, and the + # UI already exposes the tensorboard URL. try: - self.always_on_tensorboard_subprocess = subprocess.Popen(tensorboard_args) + self.always_on_tensorboard_subprocess = subprocess.Popen( + tensorboard_args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, + ) except Exception: self.always_on_tensorboard_subprocess = None diff --git a/modules/util/ui/pyside6_util.py b/modules/util/ui/pyside6_util.py index fd7b2ef8a..42b4a3e60 100644 --- a/modules/util/ui/pyside6_util.py +++ b/modules/util/ui/pyside6_util.py @@ -1,3 +1,4 @@ +import os import signal import sys from abc import ABCMeta @@ -19,6 +20,14 @@ def create_application() -> QApplication: # active and Ctrl+C would be ignored. signal.signal(signal.SIGINT, signal.SIG_DFL) + # On desktops without the xdg-desktop-portal Settings interface, Qt spams two + # "qt.qpa.theme.gnome: dbus reply error ... org.freedesktop.portal.Settings" + # lines while probing for the system color scheme. Silence just that category; + # the rules string is read when Qt's logging initializes at QApplication init. + _gnome_theme_rule = "qt.qpa.theme.gnome=false" + existing_rules = os.environ.get("QT_LOGGING_RULES") + os.environ["QT_LOGGING_RULES"] = f"{existing_rules};{_gnome_theme_rule}" if existing_rules else _gnome_theme_rule + app = QApplication(sys.argv) # Force Fusion everywhere: native styles (e.g. windowsvista) draw standard # controls via OS theme APIs, which breaks once an application stylesheet diff --git a/scripts/util/import_util.py b/scripts/util/import_util.py index 150df4d8a..a0c0a83b6 100644 --- a/scripts/util/import_util.py +++ b/scripts/util/import_util.py @@ -1,7 +1,9 @@ def script_imports(allow_zluda: bool = True): import logging import os + import re import sys + import warnings from pathlib import Path # Filter out the Triton warning on startup. @@ -10,6 +12,40 @@ def script_imports(allow_zluda: bool = True): .getLogger("xformers") \ .addFilter(lambda record: 'A matching Triton is not available' not in record.getMessage()) + # Silence specific non-actionable startup/compile warnings. A logger filter + # targets the exact emitting logger, since a parent logger's filter misses + # records from child loggers. + + # diffusers/transformers chatty logger.warning() lines at import/load time. + logging.getLogger("diffusers.modular_pipelines").addFilter( + lambda record: 'Modular Diffusers is currently an experimental feature' not in record.getMessage() + ) + # The subject of these two is interpolated into the message, so match the whole + # sentence with .* standing in for the runtime value. + logging.getLogger("diffusers.configuration_utils").addFilter( + lambda record: not re.search( + r"The config attributes .* were passed to .*, but are not expected and will be ignored", + record.getMessage(), + ) + ) + logging.getLogger("transformers.modeling_utils").addFilter( + lambda record: not re.search( + r"`loss_type=.*` was set in the config but it is unrecognized", record.getMessage() + ) + ) + + # A dependency still calls hf_hub_download with the removed local_dir_use_symlinks + # argument; the deprecation warning is not actionable. + warnings.filterwarnings("ignore", message=r".*local_dir_use_symlinks.*") + + # torch.compile emits performance notes when inductor falls back or can't use a + # fast path; harmless and noisy for normal runs. The SMs note is a logger.warning() + # on its exact emitting logger; the complex-operators note is a warnings.warn(). + warnings.filterwarnings("ignore", message=r".*does not support code generation for complex operators.*") + logging.getLogger("torch._inductor.utils").addFilter( + lambda record: 'Not enough SMs to use max_autotune_gemm mode' not in record.getMessage() + ) + # Insert ourselves as the highest-priority library path, so our modules are # always found without any risk of being shadowed by another import path. # 3 .parent calls to navigate from /scripts/util/import_util.py to the main directory