uber/neuropod

Tensorflow 2.x support in neuropod.backends.*.packager

vkuzmin-uber opened this issue · 0 comments

Feature

Currently neuropod.backends.keras.packager and neuropod.backends.tensorflow.packager supports Tensorflow 1.x interface.

It should provide support for Tensorflow 2.x, ideally it should be generic interface that allows client to work with 1.x and 2.x in the same way.

Is your feature request related to a problem? Please describe.

Tensorflow 2 doesn't recommend using session anymore but supports workaround if this is necessary. Keras backend session is necessary and caller should use the following workaround:

sess = None
if tf.__version__[0] == "2":
    import tensorflow.compat.v1 as tf
    tf.disable_v2_behavior()

    import tensorflow.python.keras.backend as K
    sess = K.get_session()
else:
    import tensorflow as tf
    sess = keras.backend.get_session()

...

create_keras_neuropod(
    neuropod_path=neuropod_path,
    model_name='keras_simple',
    sess=sess,
    model=model,
    default_input_tensor_device="CPU",
    test_input_data=input_data,
    test_expected_out=expected,
    package_as_zip=True
)

Describe the solution you'd like

New interface create_keras_neuropod (or create_keras_neuropod_tf2) that allows to create keras neuropod for TF2 without workaround mentioned above.

Describe alternatives you've considered

We may still use workaround if there is no other way. In this case we should describe it as recommended solution and maybe add some helpers.

Additional context

tf.placeholders are also deprecated in TF2.x. This was used in neuropod (within node name mapping).
Example:

def create_tf_addition_model():
    """
    A simple addition model
    """
    g = tf.Graph()
    with g.as_default():
        with tf.name_scope("some_namespace"):
            x_float = tf.placeholder(tf.float32, name="x_float")
            y_float = tf.placeholder(tf.float32, name="y_float")
            x_double = tf.placeholder(tf.float64, name="x_double")
            y_double = tf.placeholder(tf.float64, name="y_double")
            x_vec = tf.placeholder(tf.float64, name="x_vec")
            y_vec = tf.placeholder(tf.float64, name="y_vec")
            str_input = tf.placeholder(tf.string, name="str_input")

            sum_float = tf.add(x_float, y_float, name="sum_float")
            sum_double = tf.add(x_double, y_double, name="sum_double")
            sum_vec = tf.add(x_vec, y_vec, name="sum_vec")
            str_len = tf.strings.length(str_input, name="str_len")

   if __name__=='__main__':
    neuropod_path="example/tensorflow_addition/neuropod"
 
    if tf.__version__[0] == "2":
        import tensorflow.compat.v1 as tf
        tf.disable_v2_behavior()

    create_tensorflow_neuropod(
        neuropod_path=neuropod_path,
        model_name="tf_addition_model",
        graph_def=create_tf_addition_model(),
        node_name_mapping={
            "x_float": "some_namespace/x_float:0",
            "y_float": "some_namespace/y_float:0",
            "x_double": "some_namespace/x_double:0",
            "y_double": "some_namespace/y_double:0",
            "x_vec": "some_namespace/x_vec:0",
            "y_vec": "some_namespace/y_vec:0",
            "str_input": "some_namespace/str_input:0",

            "sum_float": "some_namespace/sum_float:0",
            "sum_double": "some_namespace/sum_double:0",
            "sum_vec": "some_namespace/sum_vec:0",
            "str_len": "some_namespace/str_len:0",
        },
...
    )