From 0f4d7508624d101a9bec3b507c1edea992c891fc Mon Sep 17 00:00:00 2001 From: Jindra Helcl Date: Wed, 4 Apr 2018 00:28:38 +0200 Subject: [PATCH 1/3] Super-duper tensor logging functionality --- neuralmonkey/decorators.py | 6 ++++++ neuralmonkey/logging.py | 35 ++++++++++++++++++++++------------- neuralmonkey/tf_utils.py | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 13 deletions(-) diff --git a/neuralmonkey/decorators.py b/neuralmonkey/decorators.py index 62f968009..c4664b6c9 100644 --- a/neuralmonkey/decorators.py +++ b/neuralmonkey/decorators.py @@ -1,6 +1,9 @@ from functools import wraps +import tensorflow as tf + from neuralmonkey.model.model_part import ModelPart +from neuralmonkey.tf_utils import tf_print def tensor(func): @@ -12,6 +15,9 @@ def decorate(self, *args, **kwargs): # jump out of the caller's scope and into the ModelPart's scope with self.use_scope(): value = func(self, *args, **kwargs) + if isinstance(value, tf.Tensor): + value = tf_print( + value, "<{}.{}>".format(self.name, func.__name__)) else: value = func(self, *args, **kwargs) setattr(self, attribute_name, value) diff --git a/neuralmonkey/logging.py b/neuralmonkey/logging.py index fd6670916..6c4c5c00f 100644 --- a/neuralmonkey/logging.py +++ b/neuralmonkey/logging.py @@ -3,7 +3,7 @@ import os # pylint: disable=unused-import -from typing import Any, Optional, List +from typing import Any, List # pylint: enable=unused-import from termcolor import colored @@ -11,13 +11,13 @@ class Logging(object): - log_file = None # type: Optional[Any] + log_file = None # type: Any # 'all' and 'none' are special symbols, # others are filtered according the labels - debug_enabled = [ + debug_enabled_for = [ os.environ.get("NEURALMONKEY_DEBUG_ENABLE", "none")] # type: List[str] - debug_disabled = [ + debug_disabled_for = [ os.environ.get("NEURALMONKEY_DEBUG_DISABLE", "")] # type: List[str] strict_mode = os.environ.get("NEURALMONKEY_STRICT") # type: str @@ -76,15 +76,8 @@ def print_header(title: str, path: str) -> None: log_print("") @staticmethod - def debug(message: str, label: Optional[str] = None): - if "none" in Logging.debug_enabled: - return - - if (label not in Logging.debug_enabled and - "all" not in Logging.debug_enabled): - return - - if label in Logging.debug_disabled: + def debug(message: str, label: str = None): + if not debug_enabled(label): return if label: @@ -94,6 +87,21 @@ def debug(message: str, label: Optional[str] = None): log_print("{}{}".format(colored(prefix, color="cyan"), message)) + @staticmethod + def debug_enabled(label: str = None): + if "none" in Logging.debug_enabled_for: + return False + + if label is None: + return True + + if (label in Logging.debug_disabled_for + or ("all" not in Logging.debug_enabled_for + and label not in Logging.debug_enabled_for)): + return False + + return True + # pylint: disable=invalid-name # we want these helper functions to have this exact name @@ -102,3 +110,4 @@ def debug(message: str, label: Optional[str] = None): debug = Logging.debug warn = Logging.warn notice = Logging.notice +debug_enabled = Logging.debug_enabled diff --git a/neuralmonkey/tf_utils.py b/neuralmonkey/tf_utils.py index c30b9b4a9..daedebfcb 100644 --- a/neuralmonkey/tf_utils.py +++ b/neuralmonkey/tf_utils.py @@ -4,6 +4,7 @@ from typing import Dict, Set # pylint: enable=unused-import import tensorflow as tf +from neuralmonkey.logging import debug, debug_enabled def _get_current_experiment(): @@ -45,3 +46,37 @@ def get_variable(name: str, name=name, shape=shape, dtype=dtype, initializer=get_initializer(name, initializer), **kwargs) + + +def tf_print(tensor: tf.Tensor, message: str = None) -> tf.Tensor: + """Print the value of a tensor to the debug log. + + Better than tf.Print, logs to console only when the "tensorval" debug + subject is turned on. + + Idea found at: https://stackoverflow.com/a/39649614 + + Args: + tensor: The tensor whose value to print + + Returns: + As tf.Print, this function returns a tensor identical to the input + tensor, with the printing side-effect added. + """ + def print_tensor(x: tf.Tensor) -> tf.Tensor: + if message is not None: + debug("{}: {}".format(message, x), "tensorval") + else: + debug(x, "tensorval") + return x + + # To save time, check if debug will print something + if not debug_enabled("tensorval"): + return tensor + + log_op = tf.py_func(print_tensor, [tensor], [tensor.dtype])[0] + + with tf.control_dependencies([log_op]): + res = tf.identity(tensor) + + return res From 2ba8bbb69cb271b1a6df88e65aa9367390ae1929 Mon Sep 17 00:00:00 2001 From: Jindra Helcl Date: Wed, 4 Apr 2018 01:17:36 +0200 Subject: [PATCH 2/3] tf_print: Tweaking the debug message a little bit --- neuralmonkey/logging.py | 4 ++-- neuralmonkey/tf_utils.py | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/neuralmonkey/logging.py b/neuralmonkey/logging.py index 6c4c5c00f..8b92861a2 100644 --- a/neuralmonkey/logging.py +++ b/neuralmonkey/logging.py @@ -81,9 +81,9 @@ def debug(message: str, label: str = None): return if label: - prefix = "DEBUG ({}):".format(label) + prefix = "{}: DEBUG ({}): ".format(Logging._get_time(), label) else: - prefix = "DEBUG:" + prefix = "{}: DEBUG: ".format(Logging._get_time()) log_print("{}{}".format(colored(prefix, color="cyan"), message)) diff --git a/neuralmonkey/tf_utils.py b/neuralmonkey/tf_utils.py index daedebfcb..cbdc36979 100644 --- a/neuralmonkey/tf_utils.py +++ b/neuralmonkey/tf_utils.py @@ -3,7 +3,9 @@ # pylint: disable=unused-import from typing import Dict, Set # pylint: enable=unused-import +import numpy as np import tensorflow as tf + from neuralmonkey.logging import debug, debug_enabled @@ -63,11 +65,12 @@ def tf_print(tensor: tf.Tensor, message: str = None) -> tf.Tensor: As tf.Print, this function returns a tensor identical to the input tensor, with the printing side-effect added. """ - def print_tensor(x: tf.Tensor) -> tf.Tensor: + def print_tensor(x: np.ndarray) -> tf.Tensor: if message is not None: - debug("{}: {}".format(message, x), "tensorval") + debug( + "{}, shape: {}:\n{}".format(message, x.shape, x), "tensorval") else: - debug(x, "tensorval") + debug("Shape: {}\n{}".format(x.shape, x), "tensorval") return x # To save time, check if debug will print something From fc7e72768f7facaeb9498598fe831da054ae68ee Mon Sep 17 00:00:00 2001 From: Jindra Helcl Date: Wed, 4 Apr 2018 17:35:19 +0200 Subject: [PATCH 3/3] Adding arbitrary debug label arg to tf_print keeping "tensorval" inside @tensor decorator --- neuralmonkey/decorators.py | 3 ++- neuralmonkey/tf_utils.py | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/neuralmonkey/decorators.py b/neuralmonkey/decorators.py index c4664b6c9..146ac986c 100644 --- a/neuralmonkey/decorators.py +++ b/neuralmonkey/decorators.py @@ -17,7 +17,8 @@ def decorate(self, *args, **kwargs): value = func(self, *args, **kwargs) if isinstance(value, tf.Tensor): value = tf_print( - value, "<{}.{}>".format(self.name, func.__name__)) + value, "<{}.{}>".format(self.name, func.__name__), + "tensorval") else: value = func(self, *args, **kwargs) setattr(self, attribute_name, value) diff --git a/neuralmonkey/tf_utils.py b/neuralmonkey/tf_utils.py index cbdc36979..3af3da72e 100644 --- a/neuralmonkey/tf_utils.py +++ b/neuralmonkey/tf_utils.py @@ -50,7 +50,9 @@ def get_variable(name: str, **kwargs) -def tf_print(tensor: tf.Tensor, message: str = None) -> tf.Tensor: +def tf_print(tensor: tf.Tensor, + message: str = None, + debug_label: str = None) -> tf.Tensor: """Print the value of a tensor to the debug log. Better than tf.Print, logs to console only when the "tensorval" debug @@ -68,13 +70,13 @@ def tf_print(tensor: tf.Tensor, message: str = None) -> tf.Tensor: def print_tensor(x: np.ndarray) -> tf.Tensor: if message is not None: debug( - "{}, shape: {}:\n{}".format(message, x.shape, x), "tensorval") + "{}, shape: {}:\n{}".format(message, x.shape, x), debug_label) else: - debug("Shape: {}\n{}".format(x.shape, x), "tensorval") + debug("Shape: {}\n{}".format(x.shape, x), debug_label) return x # To save time, check if debug will print something - if not debug_enabled("tensorval"): + if not debug_enabled(debug_label): return tensor log_op = tf.py_func(print_tensor, [tensor], [tensor.dtype])[0]