Skip to content

Commit 61953de

Browse files
committed
add tf2onnx logging, enhance verbosity support
1 parent 1f7e979 commit 61953de

File tree

9 files changed

+122
-43
lines changed

9 files changed

+122
-43
lines changed

tests/backend_test_base.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,7 @@ def setUp(self):
3030
# reset name generation on every test
3131
utils.INTERNAL_NAME = 1
3232
np.random.seed(1) # Make it reproducible.
33-
3433
self.logger = logging.getLogger(self.__class__.__name__)
35-
if not self.config.is_debug_mode:
36-
# suppress log info of tensorflow so that result of test can be seen much easier
37-
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
38-
tf.logging.set_verbosity(tf.logging.WARN)
3934

4035
def tearDown(self):
4136
if not self.config.is_debug_mode:

tests/common.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44
""" test common utilities."""
55

66
import argparse
7-
import logging
87
import os
98
import sys
109
import unittest
1110
from collections import defaultdict
1211

1312
from distutils.version import LooseVersion
1413
from parameterized import parameterized
15-
from tf2onnx import constants, utils
14+
from tf2onnx import constants, logging, utils
1615

1716
__all__ = ["TestConfig", "get_test_config", "unittest_main", "check_onnxruntime_backend",
1817
"check_tf_min_version", "skip_tf_versions", "check_onnxruntime_min_version",
@@ -31,6 +30,7 @@ def __init__(self):
3130
self.target = os.environ.get("TF2ONNX_TEST_TARGET", ",".join(constants.DEFAULT_TARGET)).split(',')
3231
self.backend = os.environ.get("TF2ONNX_TEST_BACKEND", "onnxruntime")
3332
self.backend_version = self._get_backend_version()
33+
self.log_level = logging.WARNING
3434
self.is_debug_mode = False
3535
self.temp_dir = utils.get_temp_directory()
3636

@@ -86,6 +86,7 @@ def load():
8686
parser.add_argument("--opset", type=int, default=config.opset, help="opset to test against")
8787
parser.add_argument("--target", default=",".join(config.target), choices=constants.POSSIBLE_TARGETS,
8888
help="target platform")
89+
parser.add_argument("--verbose", "-v", help="verbose output, option is additive", action="count")
8990
parser.add_argument("--debug", help="output debugging information", action="store_true")
9091
parser.add_argument("--temp_dir", help="temp dir")
9192
parser.add_argument("unittest_args", nargs='*')
@@ -94,6 +95,7 @@ def load():
9495
config.backend = args.backend
9596
config.opset = args.opset
9697
config.target = args.target.split(',')
98+
config.log_level = logging.get_adjusted_level(args.verbose, config.log_level)
9799
config.is_debug_mode = args.debug
98100
if args.temp_dir:
99101
config.temp_dir = args.temp_dir
@@ -116,8 +118,8 @@ def get_test_config():
116118

117119
def unittest_main():
118120
config = get_test_config()
119-
logging.basicConfig(level=logging.WARNING, format=constants.LOG_FORMAT)
120-
with utils.set_log_level(logging.getLogger(), logging.INFO) as logger:
121+
logging.basicConfig(level=config.log_level)
122+
with logging.set_scope_level(logging.INFO) as logger:
121123
logger.info(config)
122124
unittest.main()
123125

tests/conftest.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33

44
""" print pytest config."""
55

6-
import logging
76
from common import get_test_config
8-
from tf2onnx import constants, utils
7+
from tf2onnx import logging
98

109

1110
def pytest_configure():
1211
config = get_test_config()
13-
logging.basicConfig(level=logging.WARNING, format=constants.LOG_FORMAT)
14-
with utils.set_log_level(logging.getLogger(), logging.INFO) as logger:
12+
logging.basicConfig(level=config.log_level)
13+
with logging.set_scope_level(logging.INFO) as logger:
1514
logger.info(config)

tests/run_pretrained_models.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import time
1616
import traceback
1717
import zipfile
18-
import logging
1918

2019
import PIL.Image
2120
import numpy as np
@@ -28,12 +27,11 @@
2827
import yaml
2928

3029
import tf2onnx
31-
from tf2onnx import constants, loader, optimizer, utils
30+
from tf2onnx import loader, logging, optimizer, utils
3231
from tf2onnx.tfonnx import process_tf_graph
3332

3433
# pylint: disable=broad-except,logging-not-lazy,unused-argument,unnecessary-lambda
3534

36-
logging.basicConfig(level=logging.INFO, format=constants.LOG_FORMAT)
3735
logger = logging.getLogger("run_pretrained")
3836

3937
TEMP_DIR = os.path.join(utils.get_temp_directory(), "run_pretrained")
@@ -331,10 +329,10 @@ def get_args():
331329
parser.add_argument("--target", default="", help="target platform")
332330
parser.add_argument("--backend", default="onnxruntime",
333331
choices=["caffe2", "onnxmsrtnext", "onnxruntime"], help="backend to use")
334-
parser.add_argument("--verbose", help="verbose output", action="store_true")
335332
parser.add_argument("--opset", type=int, default=None, help="opset to use")
336333
parser.add_argument("--extra_opset", default=None,
337334
help="extra opset with format like domain:version, e.g. com.microsoft:1")
335+
parser.add_argument("--verbose", "-v", help="verbose output, option is additive", action="count")
338336
parser.add_argument("--debug", help="debug vlog", action="store_true")
339337
parser.add_argument("--list", help="list tests", action="store_true")
340338
parser.add_argument("--onnx-file", help="create onnx file in directory")
@@ -372,11 +370,9 @@ def tests_from_yaml(fname):
372370

373371

374372
def main():
375-
# suppress log info of tensorflow so that result of test can be seen much easier
376-
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
377-
tf.logging.set_verbosity(tf.logging.WARN)
378-
379373
args = get_args()
374+
logging.basicConfig(level=logging.get_adjusted_level(args.verbose))
375+
380376
Test.cache_dir = args.cache
381377
Test.target = args.target
382378
tests = tests_from_yaml(args.config)

tf2onnx/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
from __future__ import print_function
77
from __future__ import unicode_literals
88

9-
109
__all__ = ["utils", "graph_matcher", "graph", "loader", "tfonnx", "shape_inference", "schemas"]
1110

1211
from .version import version as __version__
12+
from . import logging
1313
from tf2onnx import tfonnx, utils, graph, graph_matcher, shape_inference, schemas # pylint: disable=wrong-import-order

tf2onnx/constants.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
common constants
66
"""
77

8-
from . import utils
8+
from onnx import helper
9+
10+
TF2ONNX_PACKAGE_NAME = __name__.split('.')[0]
911

1012
# Built-in supported domains
1113
ONNX_DOMAIN = ""
@@ -16,7 +18,7 @@
1618
PREFERRED_OPSET = 7
1719

1820
# Default opset for custom ops
19-
TENSORFLOW_OPSET = utils.make_opsetid("ai.onnx.converters.tensorflow", 1)
21+
TENSORFLOW_OPSET = helper.make_opsetid("ai.onnx.converters.tensorflow", 1)
2022

2123
# Target for the generated onnx graph. It possible targets:
2224
# onnx-1.1 = onnx at v1.1 (winml in rs4 is based on this)
@@ -32,5 +34,3 @@
3234
NHWC_TO_NCHW = [0, 3, 1, 2]
3335
HWCN_TO_NCHW = [3, 2, 0, 1]
3436
NCHW_TO_HWCN = [2, 3, 1, 0]
35-
36-
LOG_FORMAT = "%(asctime)s - %(levelname)s - %(name)s: %(message)s"

tf2onnx/convert.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,11 @@
1010
from __future__ import unicode_literals
1111

1212
import argparse
13-
import logging
1413
import tensorflow as tf
1514

16-
from tf2onnx import constants, loader, utils
1715
from tf2onnx.graph import GraphUtil
1816
from tf2onnx.tfonnx import process_tf_graph, tf_optimize
17+
from . import constants, loader, logging, utils
1918

2019

2120
# pylint: disable=unused-argument
@@ -38,7 +37,7 @@ def get_args():
3837
parser.add_argument("--target", default=",".join(constants.DEFAULT_TARGET), choices=constants.POSSIBLE_TARGETS,
3938
help="target platform")
4039
parser.add_argument("--continue_on_error", help="continue_on_error", action="store_true")
41-
parser.add_argument("--verbose", help="verbose output", action="store_true")
40+
parser.add_argument("--verbose", "-v", help="verbose output, option is additive", action="count")
4241
parser.add_argument("--fold_const", help="enable tf constant_folding transformation before conversion",
4342
action="store_true")
4443
# experimental
@@ -70,6 +69,7 @@ def get_args():
7069
if len(tokens) != 2:
7170
raise ValueError("invalid extra_opset argument")
7271
args.extra_opset = [utils.make_opsetid(tokens[0], int(tokens[1]))]
72+
7373
return args
7474

7575

@@ -80,7 +80,7 @@ def default_custom_op_handler(ctx, node, name, args):
8080

8181
def main():
8282
args = get_args()
83-
logging.basicConfig(level=logging.INFO, format=constants.LOG_FORMAT)
83+
logging.basicConfig(level=logging.get_adjusted_level(args.verbose))
8484

8585
# override unknown dimensions from -1 to 1 (aka batchsize 1) since not every runtime does
8686
# support unknown dimensions.

tf2onnx/logging.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT license.
3+
4+
"""
5+
A wrapper of built-in logging with custom level support and utilities.
6+
"""
7+
8+
from contextlib import contextmanager
9+
import logging as _logging
10+
from logging import * # pylint: disable=wildcard-import, unused-wildcard-import
11+
import os
12+
import types
13+
14+
import tensorflow as tf
15+
16+
from . import constants
17+
18+
VERBOSE = 15
19+
20+
21+
def _verbose(self, message, *args, **kwargs):
22+
if self.isEnabledFor(VERBOSE):
23+
self._log(VERBOSE, message, args, **kwargs) # pylint: disable=protected-access
24+
25+
26+
def getLogger(name=None): # pylint: disable=invalid-name, function-redefined
27+
logger = _logging.getLogger(name)
28+
# Inject verbose method to logger object instead logging module
29+
logger.verbose = types.MethodType(_verbose, logger)
30+
return logger
31+
32+
33+
_SIMPLE_LOG_FORMAT = "%(message)s"
34+
_VERBOSE_LOG_FORMAT = "%(asctime)s - %(levelname)s - %(name)s: %(message)s"
35+
36+
37+
def basicConfig(**kwargs): # pylint: disable=invalid-name, function-redefined
38+
""" Do basic configuration for the logging system. tf verbosity is updated accordingly. """
39+
# Choose pre-defined format if format argument is not specified
40+
if "format" not in kwargs:
41+
level = kwargs.get("level", _logging.root.level)
42+
kwargs["format"] = _SIMPLE_LOG_FORMAT if level >= INFO else _VERBOSE_LOG_FORMAT
43+
44+
_logging.basicConfig(**kwargs)
45+
set_tf_verbosity(_logging.getLogger().getEffectiveLevel())
46+
47+
48+
_VERBOSITY_TO_LEVEL = {
49+
1: VERBOSE,
50+
2: DEBUG
51+
}
52+
53+
54+
def get_adjusted_level(verbosity, raw_level=INFO):
55+
""" If verbosity is specified, return corresponding level, otherwise, return raw_level. """
56+
return _VERBOSITY_TO_LEVEL.get(verbosity, raw_level)
57+
58+
59+
def set_level(level):
60+
""" Set logging level for tf2onnx package. tf verbosity is updated accordingly. """
61+
_logging.getLogger(constants.TF2ONNX_PACKAGE_NAME).setLevel(level)
62+
set_tf_verbosity(level)
63+
64+
65+
def set_tf_verbosity(level):
66+
""" Set TF logging verbosity."""
67+
tf.logging.set_verbosity(level)
68+
69+
# TF_CPP_MIN_LOG_LEVEL:
70+
# 0 = all messages are logged (default behavior)
71+
# 1 = INFO messages are not printed
72+
# 2 = INFO and WARNING messages are not printed
73+
# 3 = INFO, WARNING, and ERROR messages are not printed
74+
if level <= INFO:
75+
tf_cpp_min_log_level = "0"
76+
elif level <= WARNING:
77+
tf_cpp_min_log_level = "1"
78+
elif level <= ERROR:
79+
tf_cpp_min_log_level = "2"
80+
else:
81+
tf_cpp_min_log_level = "3"
82+
os.environ["TF_CPP_MIN_LOG_LEVEL"] = tf_cpp_min_log_level
83+
84+
85+
@contextmanager
86+
def set_scope_level(level, logger=None):
87+
"""
88+
Set logging level to logger within context, reset level to previous value when exit context.
89+
TF verbosity is NOT affected.
90+
"""
91+
if logger is None:
92+
logger = getLogger()
93+
94+
current_level = logger.level
95+
logger.setLevel(level)
96+
97+
try:
98+
yield logger
99+
finally:
100+
logger.setLevel(current_level)

tf2onnx/utils.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from __future__ import print_function
1010
from __future__ import unicode_literals
1111

12-
from contextlib import contextmanager
1312
import os
1413
import re
1514
import shutil
@@ -438,15 +437,3 @@ def is_onnx_domain(domain):
438437
if domain is None or domain == "":
439438
return True
440439
return False
441-
442-
443-
@contextmanager
444-
def set_log_level(logger, level):
445-
""" Override current logger level within context. """
446-
current_level = logger.getEffectiveLevel()
447-
logger.setLevel(level)
448-
449-
try:
450-
yield logger
451-
finally:
452-
logger.setLevel(current_level)

0 commit comments

Comments
 (0)