def dispatch_keras_h5_to_tfjs_layers_model_conversion( h5_path, output_dir=None, quantization_dtype=None, split_weights_by_layer=False, weight_shard_size_bytes=1024 * 1024 * 4): """Converts a Keras HDF5 saved-model file to TensorFlow.js format. Auto-detects saved_model versus weights-only and generates the correct json in either case. This function accepts Keras HDF5 files in two formats: - A weights-only HDF5 (e.g., generated with Keras Model's `save_weights()` method), - A topology+weights combined HDF5 (e.g., generated with `tf.keras.model.save_model`). Args: h5_path: path to an HDF5 file containing keras model data as a `str`. output_dir: Output directory to which the TensorFlow.js-format model JSON file and weights files will be written. If the directory does not exist, it will be created. quantization_dtype: The quantized data type to store the weights in (Default: `None`). split_weights_by_layer: Whether to split the weights into separate weight groups (corresponding to separate binary weight files) layer by layer (Default: `False`). weight_shard_size_bytes: Shard size (in bytes) of the weight files. The size of each weight file will be <= this value. Returns: (model_json, groups) model_json: a json dictionary (empty if unused) for model topology. If `h5_path` points to a weights-only HDF5 file, this return value will be `None`. groups: an array of weight_groups as defined in tfjs weights_writer. """ if not os.path.exists(h5_path): raise ValueError('Nonexistent path to HDF5 file: %s' % h5_path) if os.path.isdir(h5_path): raise ValueError( 'Expected path to point to an HDF5 file, but it points to a ' 'directory: %s' % h5_path) h5_file = h5py.File(h5_path, 'r') if 'layer_names' in h5_file.attrs: model_json = None groups = conversion.h5_weights_to_tfjs_format( h5_file, split_by_layer=split_weights_by_layer) else: model_json, groups = conversion.h5_merged_saved_model_to_tfjs_format( h5_file, split_by_layer=split_weights_by_layer) if output_dir: if os.path.isfile(output_dir): raise ValueError( 'Output path "%s" already exists as a file' % output_dir) if not os.path.isdir(output_dir): os.makedirs(output_dir) conversion.write_artifacts( model_json, groups, output_dir, quantization_dtype, weight_shard_size_bytes=weight_shard_size_bytes) return model_json, groups
def testConvertMergedModelFromSimpleModelSplitByLayer(self): 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 = tf.keras.layers.Dense(2, use_bias=False, kernel_initializer='ones', name='MergedDense40')(dense1) model = tf.keras.models.Model(inputs=[input_tensor], outputs=[output]) h5_path = os.path.join(self._tmp_dir, 'MyModelMerged.h5') model.save(h5_path) if six.PY3: config_json = json.loads(model.to_json()) else: config_json = json.loads(model.to_json(), encoding='utf8') # Load the saved weights as a JSON string. out, groups = conversion.h5_merged_saved_model_to_tfjs_format( h5py.File(h5_path), split_by_layer=True) saved_topology = out['model_config'] # check the model topology was stored self.assertEqual(config_json['class_name'], saved_topology['class_name']) self.assertEqual(config_json['config'], saved_topology['config']) # Check the loaded weights. # Due to `split_by_layer=True`, there ought to be two weight groups, # because the model has two layers. self.assertEqual(2, len(groups)) self.assertEqual(tf.keras.__version__, out['keras_version']) self.assertEqual('tensorflow', out['backend']) self.assertEqual(2, len(groups[0])) kernel1 = groups[0][0] self.assertEqual('MergedDense30/kernel', kernel1['name']) self.assertEqual('float32', kernel1['data'].dtype) self.assertEqual((3, 4), kernel1['data'].shape) self.assertTrue(np.allclose(np.ones([3, 4]), kernel1['data'])) bias1 = groups[0][1] self.assertEqual('MergedDense30/bias', bias1['name']) self.assertEqual('float32', bias1['data'].dtype) self.assertEqual((4, ), bias1['data'].shape) self.assertTrue(np.allclose(np.zeros([4]), bias1['data'])) self.assertEqual(1, len(groups[1])) kernel2 = groups[1][0] self.assertEqual('MergedDense40/kernel', kernel2['name']) self.assertEqual('float32', kernel2['data'].dtype) self.assertEqual((4, 2), kernel2['data'].shape) self.assertTrue(np.allclose(np.ones([4, 2]), kernel2['data']))
def testConvertMergedModelFromSimpleModelNoSplitByLayer(self): input_tensor = keras.layers.Input((3, )) dense1 = keras.layers.Dense(4, use_bias=True, kernel_initializer='ones', bias_initializer='zeros', name='MergedDense10')(input_tensor) output = keras.layers.Dense(2, use_bias=False, kernel_initializer='ones', name='MergedDense20')(dense1) model = 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') # Load the saved weights as a JSON string. out, groups = conversion.h5_merged_saved_model_to_tfjs_format( h5py.File(h5_path)) saved_topology = out['model_config'] # check the model topology was stored self.assertEqual(config_json['class_name'], saved_topology['class_name']) self.assertEqual(config_json['config'], saved_topology['config']) # Check the loaded weights. # 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('tensorflow', out['backend']) weight_group = groups[0] self.assertEqual(3, len(weight_group)) kernel1 = weight_group[0] self.assertEqual('MergedDense10/kernel', kernel1['name']) self.assertEqual('float32', kernel1['data'].dtype) self.assertEqual((3, 4), kernel1['data'].shape) self.assertTrue(np.allclose(np.ones([3, 4]), kernel1['data'])) bias1 = weight_group[1] self.assertEqual('MergedDense10/bias', bias1['name']) self.assertEqual('float32', bias1['data'].dtype) self.assertEqual((4, ), bias1['data'].shape) self.assertTrue(np.allclose(np.zeros([4]), bias1['data'])) kernel2 = weight_group[2] self.assertEqual('MergedDense20/kernel', kernel2['name']) self.assertEqual('float32', kernel2['data'].dtype) self.assertEqual((4, 2), kernel2['data'].shape) self.assertTrue(np.allclose(np.ones([4, 2]), kernel2['data']))