diff --git a/tfjs-converter/python/tensorflowjs/converters/BUILD b/tfjs-converter/python/tensorflowjs/converters/BUILD index e56ece7c954..17c0673f7ae 100644 --- a/tfjs-converter/python/tensorflowjs/converters/BUILD +++ b/tfjs-converter/python/tensorflowjs/converters/BUILD @@ -129,6 +129,7 @@ py_test( srcs_version = "PY2AND3", deps = [ ":fuse_depthwise_conv2d", + ":tf_saved_model_conversion_v2", "//tensorflowjs:expect_numpy_installed", "//tensorflowjs:expect_tensorflow_installed", ], diff --git a/tfjs-converter/python/tensorflowjs/converters/converter_test.py b/tfjs-converter/python/tensorflowjs/converters/converter_test.py index 2870a8cb37c..749d7621c58 100644 --- a/tfjs-converter/python/tensorflowjs/converters/converter_test.py +++ b/tfjs-converter/python/tensorflowjs/converters/converter_test.py @@ -426,7 +426,7 @@ def testConvertTfKerasSequentialSavedAsSavedModel(self): model = self._createSimpleSequentialModel() old_model_json = json.loads(model.to_json()) old_weights = model.get_weights() - tf.keras.models.save_model(model, self._tmp_dir) + tf.keras.models.save_model(model, self._tmp_dir, save_format='tf') # Convert the keras SavedModel to tfjs format. tfjs_output_dir = os.path.join(self._tmp_dir, 'tfjs') @@ -457,7 +457,7 @@ def testConvertTfKerasSequentialCompiledAndSavedAsSavedModel(self): old_model_json = json.loads(model.to_json()) old_weights = model.get_weights() - tf.keras.models.save_model(model, self._tmp_dir) + tf.keras.models.save_model(model, self._tmp_dir, save_format='tf') # Convert the keras SavedModel to tfjs format. tfjs_output_dir = os.path.join(self._tmp_dir, 'tfjs') @@ -485,7 +485,7 @@ def testConvertTfKerasSequentialCompiledAndSavedAsSavedModel(self): def testWrongConverterRaisesCorrectErrorMessage(self): with tf.Graph().as_default(), tf.compat.v1.Session(): model = self._createSimpleSequentialModel() - tf.keras.models.save_model(model, self._tmp_dir) + tf.keras.models.save_model(model, self._tmp_dir, save_format='tf') # Convert the keras SavedModel to tfjs format. tfjs_output_dir = os.path.join(self._tmp_dir, 'tfjs') @@ -532,7 +532,7 @@ def testConvertTfKerasFunctionalModelWithWeightsSavedAsSavedModel(self): model = self._createFunctionalModelWithWeights() old_model_json = json.loads(model.to_json()) old_weights = model.get_weights() - tf.keras.models.save_model(model, self._tmp_dir) + tf.keras.models.save_model(model, self._tmp_dir, save_format='tf') # Convert the keras SavedModel to tfjs format. tfjs_output_dir = os.path.join(self._tmp_dir, 'tfjs') @@ -560,7 +560,7 @@ def testConvertTfKerasFunctionalModelWithWeightsSavedAsSavedModel(self): def testConvertTfKerasSequentialSavedAsSavedModelWithQuantization(self): with tf.Graph().as_default(), tf.compat.v1.Session(): model = self._createSimpleSequentialModel() - tf.keras.models.save_model(model, self._tmp_dir) + tf.keras.models.save_model(model, self._tmp_dir, save_format='tf') # Convert the keras SavedModel to tfjs format. tfjs_output_dir = os.path.join(self._tmp_dir, 'tfjs') diff --git a/tfjs-converter/python/tensorflowjs/converters/generate_test_model.py b/tfjs-converter/python/tensorflowjs/converters/generate_test_model.py index 41ec10e73a6..03e21867945 100644 --- a/tfjs-converter/python/tensorflowjs/converters/generate_test_model.py +++ b/tfjs-converter/python/tensorflowjs/converters/generate_test_model.py @@ -65,4 +65,4 @@ def compute(self, x): if __name__ == '__main__': args, unparsed = parse_args() - tf.app.run(main=main, argv=[sys.argv[0]] + unparsed) + tf.compat.v1.app.run(main=main, argv=[sys.argv[0]] + unparsed) diff --git a/tfjs-converter/python/tensorflowjs/converters/keras_h5_conversion_test.py b/tfjs-converter/python/tensorflowjs/converters/keras_h5_conversion_test.py index 871364aef52..d20b6153b9b 100644 --- a/tfjs-converter/python/tensorflowjs/converters/keras_h5_conversion_test.py +++ b/tfjs-converter/python/tensorflowjs/converters/keras_h5_conversion_test.py @@ -27,7 +27,6 @@ import h5py import numpy as np import tensorflow.compat.v2 as tf -from tensorflow.compat.v2 import keras from tensorflowjs import version from tensorflowjs.converters import keras_h5_conversion as conversion @@ -45,13 +44,13 @@ def tearDown(self): super(ConvertH5WeightsTest, self).tearDown() def testConvertWeightsFromSimpleModelNoSplitByLayer(self): - input_tensor = keras.layers.Input((3,)) - dense1 = keras.layers.Dense( + input_tensor = tf.keras.layers.Input((3,)) + dense1 = tf.keras.layers.Dense( 4, use_bias=True, kernel_initializer='ones', bias_initializer='zeros', name='MyDense10')(input_tensor) - output = keras.layers.Dense( + output = tf.keras.layers.Dense( 2, use_bias=False, kernel_initializer='ones', name='MyDense20')(dense1) - model = keras.models.Model(inputs=[input_tensor], outputs=[output]) + model = tf.keras.models.Model(inputs=[input_tensor], outputs=[output]) h5_path = os.path.join(self._tmp_dir, 'MyModel.h5') model.save_weights(h5_path) @@ -80,13 +79,13 @@ def testConvertWeightsFromSimpleModelNoSplitByLayer(self): self.assertTrue(np.allclose(np.ones([4, 2]), kernel2['data'])) def testConvertWeightsFromSimpleModelSplitByLayer(self): - input_tensor = keras.layers.Input((3,)) - dense1 = keras.layers.Dense( + input_tensor = tf.keras.layers.Input((3,)) + dense1 = tf.keras.layers.Dense( 4, use_bias=True, kernel_initializer='ones', bias_initializer='zeros', name='MyDense30')(input_tensor) - output = keras.layers.Dense( + output = tf.keras.layers.Dense( 2, use_bias=False, kernel_initializer='ones', name='MyDense40')(dense1) - model = keras.models.Model(inputs=[input_tensor], outputs=[output]) + model = tf.keras.models.Model(inputs=[input_tensor], outputs=[output]) h5_path = os.path.join(self._tmp_dir, 'MyModel.h5') model.save_weights(h5_path) @@ -118,13 +117,13 @@ def testConvertWeightsFromSimpleModelSplitByLayer(self): self.assertTrue(np.allclose(np.ones([4, 2]), kernel2['data'])) def testConvertModelWithNestedLayerNames(self): - model = keras.Sequential() + model = tf.keras.Sequential() # Add a layer with a nested layer name, i.e., a layer name with slash(es) # in it. - model.add(keras.layers.Dense(2, input_shape=[12], name='dense')) - model.add(keras.layers.Dense(8, name='foo/dense')) - model.add(keras.layers.Dense(4, name='foo/bar/dense')) + model.add(tf.keras.layers.Dense(2, input_shape=[12], name='dense')) + model.add(tf.keras.layers.Dense(8, name='foo/dense')) + model.add(tf.keras.layers.Dense(4, name='foo/bar/dense')) tfjs_path = os.path.join(self._tmp_dir, 'nested_layer_names_model') conversion.save_keras_model(model, tfjs_path) @@ -135,7 +134,7 @@ def testConvertModelWithNestedLayerNames(self): # Check meta-data in the artifact JSON. self.assertEqual(model_json['format'], 'layers-model') self.assertEqual(model_json['generatedBy'], - 'keras v%s' % keras.__version__) + 'keras v%s' % tf.keras.__version__) self.assertEqual( model_json['convertedBy'], 'TensorFlow.js Converter v%s' % version.version) @@ -159,14 +158,14 @@ def testConvertModelWithNestedLayerNames(self): self.assertEqual([4], weight_shapes['foo/bar/dense/bias']) def testConvertMergedModelFromSimpleModelNoSplitByLayer(self): - input_tensor = keras.layers.Input((3,)) - dense1 = keras.layers.Dense( + input_tensor = tf.keras.layers.Input((3,)) + dense1 = tf.keras.layers.Dense( 4, use_bias=True, kernel_initializer='ones', bias_initializer='zeros', name='MergedDense10')(input_tensor) - output = keras.layers.Dense( + output = tf.keras.layers.Dense( 2, use_bias=False, kernel_initializer='ones', name='MergedDense20')(dense1) - model = keras.models.Model(inputs=[input_tensor], outputs=[output]) + model = tf.keras.models.Model(inputs=[input_tensor], outputs=[output]) h5_path = os.path.join(self._tmp_dir, 'MyModelMerged.h5') model.save(h5_path) config_json = json.loads(model.to_json(), encoding='utf8') @@ -184,7 +183,7 @@ def testConvertMergedModelFromSimpleModelNoSplitByLayer(self): # By default, all weights of the model ought to be put in the same group. self.assertEqual(1, len(groups)) - self.assertEqual(keras.__version__, out['keras_version']) + self.assertEqual(tf.keras.__version__, out['keras_version']) self.assertEqual('tensorflow', out['backend']) weight_group = groups[0] self.assertEqual(3, len(weight_group)) @@ -205,14 +204,14 @@ def testConvertMergedModelFromSimpleModelNoSplitByLayer(self): self.assertTrue(np.allclose(np.ones([4, 2]), kernel2['data'])) def testConvertMergedModelFromSimpleModelSplitByLayer(self): - input_tensor = keras.layers.Input((3,)) - dense1 = keras.layers.Dense( + input_tensor = tf.keras.layers.Input((3,)) + dense1 = tf.keras.layers.Dense( 4, use_bias=True, kernel_initializer='ones', bias_initializer='zeros', name='MergedDense30')(input_tensor) - output = keras.layers.Dense( + output = tf.keras.layers.Dense( 2, use_bias=False, kernel_initializer='ones', name='MergedDense40')(dense1) - model = keras.models.Model(inputs=[input_tensor], outputs=[output]) + model = tf.keras.models.Model(inputs=[input_tensor], outputs=[output]) h5_path = os.path.join(self._tmp_dir, 'MyModelMerged.h5') model.save(h5_path) config_json = json.loads(model.to_json(), encoding='utf8') @@ -231,7 +230,7 @@ def testConvertMergedModelFromSimpleModelSplitByLayer(self): # because the model has two layers. self.assertEqual(2, len(groups)) - self.assertEqual(keras.__version__, out['keras_version']) + self.assertEqual(tf.keras.__version__, out['keras_version']) self.assertEqual('tensorflow', out['backend']) self.assertEqual(2, len(groups[0])) kernel1 = groups[0][0] @@ -252,11 +251,11 @@ def testConvertMergedModelFromSimpleModelSplitByLayer(self): self.assertTrue(np.allclose(np.ones([4, 2]), kernel2['data'])) def testConvertWeightsFromSequentialModelNoSplitByLayer(self): - sequential_model = keras.models.Sequential([ - keras.layers.Dense( + sequential_model = tf.keras.models.Sequential([ + tf.keras.layers.Dense( 3, input_shape=(2,), use_bias=True, kernel_initializer='ones', name='Dense10'), - keras.layers.Dense( + tf.keras.layers.Dense( 1, use_bias=False, kernel_initializer='ones', name='Dense20')]) h5_path = os.path.join(self._tmp_dir, 'SequentialModel.h5') sequential_model.save_weights(h5_path) @@ -286,11 +285,11 @@ def testConvertWeightsFromSequentialModelNoSplitByLayer(self): self.assertTrue(np.allclose(np.ones([3, 1]).tolist(), kernel2['data'])) def testConvertWeightsFromSequentialModelSplitByLayer(self): - sequential_model = keras.models.Sequential([ - keras.layers.Dense( + sequential_model = tf.keras.models.Sequential([ + tf.keras.layers.Dense( 3, input_shape=(2,), use_bias=True, kernel_initializer='ones', name='Dense30'), - keras.layers.Dense( + tf.keras.layers.Dense( 1, use_bias=False, kernel_initializer='ones', name='Dense40')]) h5_path = os.path.join(self._tmp_dir, 'SequentialModel.h5') sequential_model.save_weights(h5_path) @@ -323,10 +322,10 @@ def testConvertWeightsFromSequentialModelSplitByLayer(self): self.assertTrue(np.allclose(np.ones([3, 1]).tolist(), kernel2['data'])) def testSaveModelSucceedsForNonSequentialModel(self): - t_input = keras.Input([2]) - dense_layer = keras.layers.Dense(3) + t_input = tf.keras.Input([2]) + dense_layer = tf.keras.layers.Dense(3) t_output = dense_layer(t_input) - model = keras.Model(t_input, t_output) + model = tf.keras.Model(t_input, t_output) conversion.save_keras_model(model, self._tmp_dir) # Verify the content of the artifacts output directory. @@ -346,12 +345,12 @@ def testSaveModelSucceedsForNonSequentialModel(self): self.assertIn('paths', weights_manifest[0]) def testSaveModelSucceedsForTfKerasNonSequentialModel(self): - t_input = keras.Input([2]) - dense_layer = keras.layers.Dense(3) + t_input = tf.keras.Input([2]) + dense_layer = tf.keras.layers.Dense(3) t_output = dense_layer(t_input) - model = keras.Model(t_input, t_output) + model = tf.keras.Model(t_input, t_output) - # `keras.Model`s must be compiled before they can be saved. + # `tf.keras.Model`s must be compiled before they can be saved. model.compile(loss='mean_squared_error', optimizer='sgd') conversion.save_keras_model(model, self._tmp_dir) @@ -373,12 +372,12 @@ def testSaveModelSucceedsForTfKerasNonSequentialModel(self): self.assertIn('paths', weights_manifest[0]) def testSaveModelSucceedsForNestedKerasModel(self): - inner_model = keras.Sequential([ - keras.layers.Dense(4, input_shape=[3], activation='relu'), - keras.layers.Dense(3, activation='tanh')]) - outer_model = keras.Sequential() + inner_model = tf.keras.Sequential([ + tf.keras.layers.Dense(4, input_shape=[3], activation='relu'), + tf.keras.layers.Dense(3, activation='tanh')]) + outer_model = tf.keras.Sequential() outer_model.add(inner_model) - outer_model.add(keras.layers.Dense(1, activation='sigmoid')) + outer_model.add(tf.keras.layers.Dense(1, activation='sigmoid')) conversion.save_keras_model(outer_model, self._tmp_dir) @@ -402,9 +401,9 @@ def testSaveModelSucceedsForNestedKerasModel(self): self.assertEqual(6, len(weight_entries)) def testSaveModelSucceedsForTfKerasSequentialModel(self): - model = keras.Sequential([keras.layers.Dense(1, input_shape=[2])]) + model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=[2])]) - # `keras.Model`s must be compiled before they can be saved. + # `tf.keras.Model`s must be compiled before they can be saved. model.compile(loss='mean_squared_error', optimizer='sgd') conversion.save_keras_model(model, self._tmp_dir) @@ -428,8 +427,8 @@ def testSaveModelSucceedsForTfKerasSequentialModel(self): def testSavedModelSucceedsForExistingDirAndSequential(self): artifacts_dir = os.path.join(self._tmp_dir, 'artifacts') os.makedirs(artifacts_dir) - model = keras.Sequential() - model.add(keras.layers.Dense(3, input_shape=[2])) + model = tf.keras.Sequential() + model.add(tf.keras.layers.Dense(3, input_shape=[2])) conversion.save_keras_model(model, artifacts_dir) # Verify the content of the artifacts output directory. @@ -452,10 +451,10 @@ def testSavedModelRaisesErrorIfArtifactsDirExistsAsAFile(self): artifacts_dir = os.path.join(self._tmp_dir, 'artifacts') with open(artifacts_dir, 'wt') as f: f.write('foo\n') - t_input = keras.Input([2]) - dense_layer = keras.layers.Dense(3) + t_input = tf.keras.Input([2]) + dense_layer = tf.keras.layers.Dense(3) t_output = dense_layer(t_input) - model = keras.Model(t_input, t_output) + model = tf.keras.Model(t_input, t_output) with self.assertRaisesRegexp( # pylint: disable=deprecated-method ValueError, r'already exists as a file'): conversion.save_keras_model(model, artifacts_dir) @@ -478,8 +477,8 @@ def testTranslateBatchNormalizationV1ClassName(self): self.assertEqual(json_object['config']['layers'][2]['class_name'], 'Dense') # Assert that converted JSON can be reconstituted as a model object. - model = keras.models.model_from_json(json.dumps(json_object)) - self.assertIsInstance(model, keras.Sequential) + model = tf.keras.models.model_from_json(json.dumps(json_object)) + self.assertIsInstance(model, tf.keras.Sequential) self.assertEqual(model.input_shape, (None, 3)) self.assertEqual(model.output_shape, (None, 1)) self.assertEqual(model.layers[0].units, 10) @@ -503,8 +502,8 @@ def testTranslateUnifiedGRUAndLSTMClassName(self): self.assertEqual(json_object['config']['layers'][1]['class_name'], 'LSTM') # Assert that converted JSON can be reconstituted as a model object. - model = keras.models.model_from_json(json.dumps(json_object)) - self.assertIsInstance(model, keras.Sequential) + model = tf.keras.models.model_from_json(json.dumps(json_object)) + self.assertIsInstance(model, tf.keras.Sequential) self.assertEqual(model.input_shape, (None, 4, 3)) self.assertEqual(model.output_shape, (None, 2))