Repository: intel/dffml

Issue:
model: tensorflow: dnnr: Tests failing frequently
After the TF 1.X -> 2.X transition `dnnr` has been behaving erratically.

Currently trying to figure out what's up...


Discussion:

Resolving patch:
diff --git a/model/tensorflow/dffml_model_tensorflow/dnnc.py b/model/tensorflow/dffml_model_tensorflow/dnnc.py
--- a/model/tensorflow/dffml_model_tensorflow/dnnc.py
+++ b/model/tensorflow/dffml_model_tensorflow/dnnc.py
@@ -10,19 +10,21 @@
 from typing import List, Dict, Any, AsyncIterator, Tuple, Optional, Type
 
 import numpy as np
-import tensorflow
+
+os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
+import tensorflow as tf
 
 from dffml.repo import Repo
-from dffml.feature import Feature, Features
-from dffml.source.source import Sources
-from dffml.model.model import ModelConfig, ModelContext, Model, ModelNotTrained
-from dffml.accuracy import Accuracy
-from dffml.util.entrypoint import entrypoint
 from dffml.base import BaseConfig
 from dffml.util.cli.arg import Arg
-from dffml.feature.feature import Feature, Features
-from dffml.util.cli.parser import list_action
+from dffml.accuracy import Accuracy
 from dffml.base import config, field
+from dffml.source.source import Sources
+from dffml.feature import Feature, Features
+from dffml.util.entrypoint import entrypoint
+from dffml.util.cli.parser import list_action
+from dffml.feature.feature import Feature, Features
+from dffml.model.model import ModelConfig, ModelContext, Model, ModelNotTrained
 
 
 class TensorflowModelContext(ModelContext):
@@ -65,7 +67,7 @@ def _feature_feature_column(self, feature: Feature):
             or dtype is float
             or issubclass(dtype, float)
         ):
-            return tensorflow.feature_column.numeric_column(
+            return tf.feature_column.numeric_column(
                 feature.NAME, shape=feature.length()
             )
         self.logger.warning(
@@ -112,7 +114,7 @@ async def predict_input_fn(self, repos: AsyncIterator[Repo], **kwargs):
         self.logger.info("------ Repo Data ------")
         self.logger.info("x_cols:    %d", len(list(x_cols.values())[0]))
         self.logger.info("-----------------------")
-        input_fn = tensorflow.estimator.inputs.numpy_input_fn(
+        input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn(
             x_cols, shuffle=False, num_epochs=1, **kwargs
         )
         return input_fn, ret_repos
@@ -206,7 +208,7 @@ def model(self):
             len(self.classifications),
             self.classifications,
         )
-        self._model = tensorflow.estimator.DNNClassifier(
+        self._model = tf.compat.v1.estimator.DNNClassifier(
             feature_columns=list(self.feature_columns.values()),
             hidden_units=self.parent.config.hidden,
             n_classes=len(self.parent.config.classifications),
@@ -247,7 +249,7 @@ async def training_input_fn(
         self.logger.info("x_cols:    %d", len(list(x_cols.values())[0]))
         self.logger.info("y_cols:    %d", len(y_cols))
         self.logger.info("-----------------------")
-        input_fn = tensorflow.estimator.inputs.numpy_input_fn(
+        input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn(
             x_cols,
             y_cols,
             batch_size=self.parent.config.batchsize,
@@ -287,7 +289,7 @@ async def accuracy_input_fn(
         self.logger.info("x_cols:    %d", len(list(x_cols.values())[0]))
         self.logger.info("y_cols:    %d", len(y_cols))
         self.logger.info("-----------------------")
-        input_fn = tensorflow.estimator.inputs.numpy_input_fn(
+        input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn(
             x_cols,
             y_cols,
             batch_size=self.parent.config.batchsize,
diff --git a/model/tensorflow/dffml_model_tensorflow/dnnr.py b/model/tensorflow/dffml_model_tensorflow/dnnr.py
--- a/model/tensorflow/dffml_model_tensorflow/dnnr.py
+++ b/model/tensorflow/dffml_model_tensorflow/dnnr.py
@@ -6,19 +6,21 @@
 from typing import List, Dict, Any, AsyncIterator
 
 import numpy as np
-import tensorflow
+
+os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
+import tensorflow as tf
 
 from dffml.repo import Repo
-from dffml.source.source import Sources
+from dffml.util.cli.arg import Arg
 from dffml.model.model import Model
 from dffml.accuracy import Accuracy
+from dffml.source.source import Sources
 from dffml.util.entrypoint import entrypoint
+from dffml.util.cli.parser import list_action
 from dffml.base import BaseConfig, config, field
-from dffml.util.cli.arg import Arg
 from dffml.feature.feature import Feature, Features
-from dffml.util.cli.parser import list_action
 
-from dffml_model_tensorflow.dnnc import TensorflowModelContext
+from .dnnc import TensorflowModelContext
 
 
 @config
@@ -64,9 +66,7 @@ def model(self):
             return self._model
         self.logger.debug("Loading model ")
 
-        _head = tensorflow.contrib.estimator.regression_head()
-        self._model = tensorflow.estimator.DNNEstimator(
-            head=_head,
+        self._model = tf.compat.v1.estimator.DNNRegressor(
             feature_columns=list(self.feature_columns.values()),
             hidden_units=self.parent.config.hidden,
             model_dir=self.model_dir_path,
@@ -102,7 +102,7 @@ async def training_input_fn(
         self.logger.info("x_cols:    %d", len(list(x_cols.values())[0]))
         self.logger.info("y_cols:    %d", len(y_cols))
         self.logger.info("-----------------------")
-        input_fn = tensorflow.estimator.inputs.numpy_input_fn(
+        input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn(
             x_cols,
             y_cols,
             batch_size=batch_size,
@@ -138,7 +138,7 @@ async def evaluate_input_fn(
         self.logger.info("x_cols:    %d", len(list(x_cols.values())[0]))
         self.logger.info("y_cols:    %d", len(y_cols))
         self.logger.info("-----------------------")
-        input_fn = tensorflow.estimator.inputs.numpy_input_fn(
+        input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn(
             x_cols,
             y_cols,
             batch_size=batch_size,
diff --git a/model/tensorflow/setup.py b/model/tensorflow/setup.py
--- a/model/tensorflow/setup.py
+++ b/model/tensorflow/setup.py
@@ -18,7 +18,7 @@
 with open(os.path.join(self_path, "README.md"), "r", encoding="utf-8") as f:
     readme = f.read()
 
-INSTALL_REQUIRES = ["tensorflow==1.14.0"] + (
+INSTALL_REQUIRES = ["tensorflow>=2.0.0"] + (
     ["dffml>=0.3.1"]
     if not any(
         list(


Test patch:
diff --git a/model/tensorflow/tests/test_dnnc.py b/model/tensorflow/tests/test_dnnc.py
--- a/model/tensorflow/tests/test_dnnc.py
+++ b/model/tensorflow/tests/test_dnnc.py
@@ -54,7 +54,7 @@ def setUpClass(cls):
             DNNClassifierModelConfig(
                 directory=cls.model_dir.name,
                 steps=1000,
-                epochs=30,
+                epochs=40,
                 hidden=[10, 20, 10],
                 predict=DefFeature("string", str, 1),
                 classifications=["a", "not a"],
diff --git a/model/tensorflow/tests/test_dnnr.py b/model/tensorflow/tests/test_dnnr.py
--- a/model/tensorflow/tests/test_dnnr.py
+++ b/model/tensorflow/tests/test_dnnr.py
@@ -50,14 +50,14 @@ def setUpClass(cls):
             DNNRegressionModelConfig(
                 directory=cls.model_dir.name,
                 steps=1000,
-                epochs=30,
+                epochs=40,
                 hidden=[10, 20, 10],
                 predict=DefFeature("TARGET", float, 1),
                 features=cls.features,
             )
         )
         # Generating data f(x1,x2) = 2*x1 + 3*x2
-        _n_data = 1000
+        _n_data = 2000
         _temp_data = np.random.rand(2, _n_data)
         cls.repos = [
             Repo(