def testTensorflowjsToKerasConversionSucceeds(self): with tf.Graph().as_default(), tf.compat.v1.Session(): sequential_model = keras.models.Sequential([ keras.layers.Dense(3, input_shape=(2, ), use_bias=True, kernel_initializer='ones', name='Dense1'), keras.layers.Dense(1, use_bias=False, kernel_initializer='ones', name='Dense2') ]) h5_path = os.path.join(self._tmp_dir, 'SequentialModel.h5') sequential_model.save(h5_path) converter.dispatch_keras_h5_to_tfjs_layers_model_conversion( h5_path, output_dir=self._tmp_dir) old_model_json = sequential_model.to_json() # Convert the tensorflowjs artifacts to a new H5 file. new_h5_path = os.path.join(self._tmp_dir, 'new.h5') converter.dispatch_tensorflowjs_to_keras_h5_conversion( os.path.join(self._tmp_dir, 'model.json'), new_h5_path) # Load the new H5 and compare the model JSONs. with tf.Graph().as_default(), tf.compat.v1.Session(): new_model = keras.models.load_model(new_h5_path) self.assertEqual(old_model_json, new_model.to_json())
def testConvertTfjsLayersModelWithUint8Quantization(self): with tf.Graph().as_default(), tf.compat.v1.Session(): model = self._createSimpleSequentialModel() weights = model.get_weights() total_weight_bytes = sum(np.size(w) for w in weights) * 4 # Save the keras model to a .h5 file. h5_path = os.path.join(self._tmp_dir, 'model.h5') model.save(h5_path) # Convert the keras SavedModel to tfjs format. tfjs_output_dir = os.path.join(self._tmp_dir, 'tfjs') converter.dispatch_keras_h5_to_tfjs_layers_model_conversion( h5_path, tfjs_output_dir) weight_shard_size_bytes = int(total_weight_bytes * 2) # Due to the shard size, there ought to be 1 shard after conversion. # Convert the tfjs model to another tfjs model, with quantization. sharded_model_path = os.path.join(self._tmp_dir, 'sharded_model') converter.dispatch_tensorflowjs_to_tensorflowjs_conversion( os.path.join(tfjs_output_dir, 'model.json'), sharded_model_path, quantization_dtype=np.uint8, weight_shard_size_bytes=weight_shard_size_bytes) # Check the number of quantized files and their sizes. weight_files = sorted( glob.glob(os.path.join(sharded_model_path, 'group*.bin'))) self.assertEqual(len(weight_files), 1) weight_file_size = os.path.getsize(weight_files[0]) # The size of the saved weight file should reflect the result of the # uint16 quantization. self.assertEqual(weight_file_size, total_weight_bytes / 4)
def testConvertTfjsLayersModelWithShardSizeGreaterThanTotalWeightSize(self): with tf.Graph().as_default(), tf.compat.v1.Session(): model = self._createSimpleSequentialModel() weights = model.get_weights() total_weight_bytes = sum(np.size(w) for w in weights) * 4 # Save the keras model to a .h5 file. h5_path = os.path.join(self._tmp_dir, 'model.h5') model.save(h5_path) # Convert the keras SavedModel to tfjs format. tfjs_output_dir = os.path.join(self._tmp_dir, 'tfjs') converter.dispatch_keras_h5_to_tfjs_layers_model_conversion( h5_path, tfjs_output_dir) weight_shard_size_bytes = int(total_weight_bytes * 2) # Due to the shard size, there ought to be 1 shard after conversion. # Convert the tfjs model to another tfjs model, with a specified weight # shard size. sharded_model_path = os.path.join(self._tmp_dir, 'sharded_model') converter.dispatch_tensorflowjs_to_tensorflowjs_conversion( os.path.join(tfjs_output_dir, 'model.json'), sharded_model_path, weight_shard_size_bytes=weight_shard_size_bytes) # Check the number of sharded files and their sizes. weight_files = sorted( glob.glob(os.path.join(sharded_model_path, 'group*.bin'))) self.assertEqual(len(weight_files), 1) weight_file_sizes = [os.path.getsize(f) for f in weight_files] self.assertEqual(sum(weight_file_sizes), total_weight_bytes)
def testConvertSavedKerasModeltoTfLayersModelSharded(self): with tf.Graph().as_default(), tf.compat.v1.Session(): sequential_model = tf.keras.models.Sequential([ tf.keras.layers.Dense(3, input_shape=(2, ), use_bias=True, kernel_initializer='ones', name='Dense1') ]) h5_path = os.path.join(self._tmp_dir, 'SequentialModel.h5') sequential_model.save(h5_path) weights = sequential_model.get_weights() total_weight_bytes = sum(np.size(w) for w in weights) * 4 # Due to the shard size, there ought to be 4 shards after conversion. weight_shard_size_bytes = int(total_weight_bytes * 0.3) # Convert Keras model to tfjs_layers_model format. output_dir = os.path.join(self._tmp_dir, 'sharded_tfjs') converter.dispatch_keras_h5_to_tfjs_layers_model_conversion( h5_path, output_dir, weight_shard_size_bytes=weight_shard_size_bytes) weight_files = sorted( glob.glob(os.path.join(output_dir, 'group*.bin'))) self.assertEqual(len(weight_files), 4) weight_file_sizes = [os.path.getsize(f) for f in weight_files] self.assertEqual(sum(weight_file_sizes), total_weight_bytes) self.assertEqual(weight_file_sizes[0], weight_file_sizes[1]) self.assertEqual(weight_file_sizes[0], weight_file_sizes[2]) self.assertLess(weight_file_sizes[3], weight_file_sizes[0])
def testWrongConverterRaisesCorrectErrorMessage(self): with tf.Graph().as_default(), tf.compat.v1.Session(): model = self._createSimpleSequentialModel() keras.experimental.export_saved_model(model, self._tmp_dir) # Convert the keras SavedModel to tfjs format. tfjs_output_dir = os.path.join(self._tmp_dir, 'tfjs') # Use wrong dispatcher. with self.assertRaisesRegexp( # pylint: disable=deprecated-method ValueError, r'Expected path to point to an HDF5 file, but it points to a ' r'directory'): converter.dispatch_keras_h5_to_tfjs_layers_model_conversion( self._tmp_dir, tfjs_output_dir)
def testConvertSavedKerasModelNoSplitByLayer(self): with tf.Graph().as_default(), tf.compat.v1.Session(): input_tensor = keras.layers.Input((3,)) dense1 = keras.layers.Dense( 4, use_bias=True, kernel_initializer='ones', bias_initializer='zeros', name='MergedDense1')(input_tensor) output = keras.layers.Dense( 2, use_bias=False, kernel_initializer='ones', name='MergedDense2')(dense1) model = keras.models.Model(inputs=[input_tensor], outputs=[output]) h5_path = os.path.join(self._tmp_dir, 'MyModelMerged.h5') model.save(h5_path) # Load the saved weights as a JSON string. model_json, groups = ( converter.dispatch_keras_h5_to_tfjs_layers_model_conversion( h5_path, output_dir=self._tmp_dir)) # check the model topology was stored self.assertIsInstance(model_json['model_config'], dict) self.assertIsInstance(model_json['model_config']['config'], dict) self.assertIn('layers', model_json['model_config']['config']) # Check the loaded weights. self.assertEqual(keras.__version__, model_json['keras_version']) self.assertEqual('tensorflow', model_json['backend']) self.assertEqual(1, len(groups)) self.assertEqual(3, len(groups[0])) # contents of weights are verified in tests of the library code # Check the content of the output directory. output_json = json.load( open(os.path.join(self._tmp_dir, 'model.json'), 'rt')) self.assertEqual(model_json, output_json['modelTopology']) self.assertIsInstance(output_json['weightsManifest'], list) self.assertTrue(glob.glob(os.path.join(self._tmp_dir, 'group*-*')))
def testConvertWeightsFromSequentialModel(self): with tf.Graph().as_default(), tf.compat.v1.Session(): sequential_model = keras.models.Sequential([ keras.layers.Dense( 3, input_shape=(2,), use_bias=True, kernel_initializer='ones', name='Dense1'), keras.layers.Dense( 1, use_bias=False, kernel_initializer='ones', name='Dense2')]) h5_path = os.path.join(self._tmp_dir, 'SequentialModel.h5') sequential_model.save_weights(h5_path) # Load the saved weights as a JSON string. model_json, groups = ( converter.dispatch_keras_h5_to_tfjs_layers_model_conversion( h5_path, output_dir=self._tmp_dir)) self.assertIsNone(model_json) # Check the loaded weights. self.assertEqual(1, len(groups)) self.assertEqual(3, len(groups[0])) # contents of weights are verified in tests of the library code # Check the content of the output directory. output_json = json.load( open(os.path.join(self._tmp_dir, 'model.json'), 'rt')) self.assertEqual(model_json, output_json['modelTopology']) self.assertIsInstance(output_json['weightsManifest'], list) self.assertTrue(glob.glob(os.path.join(self._tmp_dir, 'group*-*')))
def testWeightsOnly(self): with tf.Graph().as_default(), tf.compat.v1.Session(): input_tensor = tf.keras.layers.Input((3, )) dense1 = tf.keras.layers.Dense(4, use_bias=True, kernel_initializer='ones', bias_initializer='zeros', name='MyDense1')(input_tensor) output = tf.keras.layers.Dense(2, use_bias=False, kernel_initializer='ones', name='MyDense2')(dense1) 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) # Load the saved weights as a JSON string. model_json, groups = ( converter.dispatch_keras_h5_to_tfjs_layers_model_conversion( h5_path, output_dir=self._tmp_dir)) self.assertIsNone(model_json) # Check the loaded weights. self.assertEqual(1, len(groups)) self.assertEqual(3, len(groups[0])) # contents of weights are verified in tests of the library code # Check the content of the output directory. output_json = json.load( open(os.path.join(self._tmp_dir, 'model.json'), 'rt')) self.assertEqual(model_json, output_json['modelTopology']) self.assertIsInstance(output_json['weightsManifest'], list) self.assertTrue(glob.glob(os.path.join(self._tmp_dir, 'group*-*')))
def testTensorflowjsToKerasConversionFailsOnExistingDirOutputPath(self): with tf.Graph().as_default(), tf.compat.v1.Session(): sequential_model = keras.models.Sequential([ keras.layers.Dense( 3, input_shape=(2,), use_bias=True, kernel_initializer='ones', name='Dense1'), keras.layers.Dense( 1, use_bias=False, kernel_initializer='ones', name='Dense2')]) h5_path = os.path.join(self._tmp_dir, 'SequentialModel.h5') sequential_model.save(h5_path) converter.dispatch_keras_h5_to_tfjs_layers_model_conversion( h5_path, output_dir=self._tmp_dir) with self.assertRaisesRegexp( # pylint: disable=deprecated-method ValueError, r'but received an existing directory'): converter.dispatch_tensorflowjs_to_keras_h5_conversion( os.path.join(self._tmp_dir, 'model.json'), self._tmp_dir)
def testOutpuDirAsAnExistingFileLeadsToValueError(self): output_path = os.path.join(self._tmp_dir, 'foo_model') with open(output_path, 'wt') as f: f.write('\n') with tf.Graph().as_default(), tf.compat.v1.Session(): sequential_model = keras.models.Sequential([ keras.layers.Dense( 3, input_shape=(2,), use_bias=True, kernel_initializer='ones', name='Dense1')]) h5_path = os.path.join(self._tmp_dir, 'SequentialModel.h5') sequential_model.save_weights(h5_path) with self.assertRaisesRegexp( # pylint: disable=deprecated-method ValueError, r'already exists as a file'): converter.dispatch_keras_h5_to_tfjs_layers_model_conversion( h5_path, output_dir=output_path)
def testConvertModelForNonexistentDirCreatesDir(self): with tf.Graph().as_default(), tf.compat.v1.Session(): output_dir = os.path.join(self._tmp_dir, 'foo_model') sequential_model = keras.models.Sequential([ keras.layers.Dense( 3, input_shape=(2,), use_bias=True, kernel_initializer='ones', name='Dense1')]) h5_path = os.path.join(self._tmp_dir, 'SequentialModel.h5') sequential_model.save_weights(h5_path) converter.dispatch_keras_h5_to_tfjs_layers_model_conversion( h5_path, output_dir=output_dir) # Check the content of the output directory. output_json = json.load( open(os.path.join(output_dir, 'model.json'), 'rt')) self.assertIsNone(output_json['modelTopology']) self.assertIsInstance(output_json['weightsManifest'], list) self.assertTrue(glob.glob(os.path.join(output_dir, 'group*-*')))
def testConvertTfjsLayersModelToKerasSavedModel(self): with tf.Graph().as_default(), tf.compat.v1.Session(): model = self._createSimpleSequentialModel() # Save the keras model to a .h5 file. h5_path = os.path.join(self._tmp_dir, 'model.h5') model.save(h5_path) # Convert the keras SavedModel to tfjs format. tfjs_output_dir = os.path.join(self._tmp_dir, 'tfjs') converter.dispatch_keras_h5_to_tfjs_layers_model_conversion( h5_path, tfjs_output_dir) # Convert the tfjs LayersModel to tf.keras SavedModel. keras_saved_model_dir = os.path.join(self._tmp_dir, 'saved_model') converter.dispatch_tensorflowjs_to_keras_saved_model_conversion( os.path.join(tfjs_output_dir, 'model.json'), keras_saved_model_dir) # Check the files of the keras SavedModel. files = glob.glob(os.path.join(keras_saved_model_dir, '*')) self.assertIn(os.path.join(keras_saved_model_dir, 'saved_model.pb'), files) self.assertIn(os.path.join(keras_saved_model_dir, 'variables'), files) self.assertIn(os.path.join(keras_saved_model_dir, 'assets'), files)
def testTfjsLayer2TfjsLayersConversionWithExistingFilePathFails(self): with tf.Graph().as_default(), tf.compat.v1.Session(): model = self._createSimpleSequentialModel() # Save the keras model to a .h5 file. h5_path = os.path.join(self._tmp_dir, 'model.h5') model.save(h5_path) # Convert the keras SavedModel to tfjs format. tfjs_output_dir = os.path.join(self._tmp_dir, 'tfjs') converter.dispatch_keras_h5_to_tfjs_layers_model_conversion( h5_path, tfjs_output_dir) # Convert the tfjs model to another tfjs model, with a specified weight # shard size. sharded_model_path = os.path.join(self._tmp_dir, 'sharded_model') with open(sharded_model_path, 'wt') as f: # Create a fie at the path to elicit the error. f.write('hello') with self.assertRaisesRegexp( # pylint: disable=deprecated-method ValueError, r'already exists as a file'): converter.dispatch_tensorflowjs_to_tensorflowjs_conversion( os.path.join(tfjs_output_dir, 'model.json'), sharded_model_path)