johannesschmude's picture
Initial commit
b73936d
import functools
import logging
import os
import sys
from time import time
from packaging.version import Version
import wandb
from typing import Dict, Optional, Any
if Version(wandb.__version__) < Version("0.20.0"):
WANDB_USE_SYNC = True
else:
WANDB_USE_SYNC = False
def log(
run,
data: Dict[str, Any],
step: Optional[int] = None,
commit: Optional[bool] = None,
sync: Optional[bool] = None,
) -> None:
if run is not None:
# Note: wandb changed the .log API with version 0.20.0.
# This includes: "Removed no-op sync argument from wandb.Run::log function"
# We didn't test whether sync has any function here. But since we did
# all our development with it, let's keep it here for now.
# See https://github.com/wandb/wandb/releases/tag/v0.20.0
if WANDB_USE_SYNC:
run.log(data, step, commit, sync)
else:
run.log(data, step, commit)
else:
print(data)
# See: https://github.com/microsoft/Swin-Transformer/blob/main/logger.py
# See: https://github.com/Meituan-AutoML/Twins/blob/main/logger.py
def create_logger(output_dir: str, dist_rank: int, name: str) -> logging.Logger:
# create logger
logger = logging.getLogger(name)
logger.setLevel(logging.DEBUG)
logger.propagate = False
# create formatter
fmt = "[%(asctime)s %(name)s]: %(levelname)s %(message)s"
# create console handlers
if name.endswith("main"):
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(
logging.Formatter(fmt=fmt, datefmt="%Y-%m-%d %H:%M:%S")
)
logger.addHandler(console_handler)
# create file handlers
file_handler = logging.FileHandler(
os.path.join(output_dir, f"{name}.log"), mode="a"
)
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(logging.Formatter(fmt=fmt, datefmt="%Y-%m-%d %H:%M:%S"))
logger.addHandler(file_handler)
return logger
def log_decorator(logger, _func=None):
def log_decorator_info(func):
@functools.wraps(func)
def log_decorator_wrapper(*args, **kwargs):
"""Create a list of the positional arguments passed to function.
- Using repr() for string representation for each argument. repr() is similar to str() only
difference being it prints with a pair of quotes and if we calculate a value we get more
precise value than str().
"""
# py_file_caller = getframeinfo(stack()[1][0])
local_rank = os.environ.get("LOCAL_RANK", default=None)
rank = os.environ.get("LOCAL_RANK", default=None)
try:
"""log return value from the function"""
start_time = time()
value = func(*args, **kwargs)
if local_rank is None or rank is None:
logger.info(
f"Function '{func.__name__}' - Execution time: {(time() - start_time):.1f} seconds."
)
else:
logger.info(
f"Function '{func.__name__}' - Execution time: {(time() - start_time):.1f} "
f"seconds on rank {os.environ['RANK']} and local_rank {os.environ['LOCAL_RANK']}."
)
except Exception as err:
logger.error(f"Exception: {err}")
raise
return value
# Return the pointer to the function
return log_decorator_wrapper
# Decorator was called with arguments, so return a decorator function that can read and return a function
if _func is None:
return log_decorator_info
# Decorator was called without arguments, so apply the decorator to the function immediately
else:
return log_decorator_info(_func)