def testConvertWeightsFromSimpleModelNoSplitByLayer(self): input_tensor = keras.layers.Input((3,)) dense1 = keras.layers.Dense( 4, use_bias=True, kernel_initializer='ones', bias_initializer='zeros', name='MyDense10')(input_tensor) output = keras.layers.Dense( 2, use_bias=False, kernel_initializer='ones', name='MyDense20')(dense1) model = 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. groups = conversion.h5_weights_to_tfjs_format(h5py.File(h5_path)) # Check the loaded weights. # Due to the default `split_by_layer=True`, there should be only one weight # group. self.assertEqual(1, len(groups)) self.assertEqual(3, len(groups[0])) kernel1 = groups[0][0] self.assertEqual('MyDense10/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('MyDense10/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 = groups[0][2] self.assertEqual('MyDense20/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 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 testConvertWeightsFromSequentialModelNoSplitByLayer(self): sequential_model = keras.models.Sequential([ keras.layers.Dense( 3, input_shape=(2,), use_bias=True, kernel_initializer='ones', name='Dense10'), 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) # Load the saved weights as a JSON string. groups = conversion.h5_weights_to_tfjs_format(h5py.File(h5_path)) # Check the loaded weights. # Due to the default `split_by_layer=False`, there should be only one weight # group. self.assertEqual(1, len(groups)) self.assertEqual(3, len(groups[0])) kernel1 = groups[0][0] self.assertEqual('Dense10/kernel', kernel1['name']) self.assertEqual('float32', kernel1['data'].dtype) self.assertEqual((2, 3), kernel1['data'].shape) self.assertTrue(np.allclose(np.ones([2, 3]).tolist(), kernel1['data'])) bias1 = groups[0][1] self.assertEqual('Dense10/bias', bias1['name']) self.assertEqual('float32', bias1['data'].dtype) self.assertEqual((3,), bias1['data'].shape) self.assertTrue(np.allclose(np.zeros([3]).tolist(), bias1['data'])) kernel2 = groups[0][2] self.assertEqual('Dense20/kernel', kernel2['name']) self.assertEqual('float32', kernel2['data'].dtype) self.assertEqual((3, 1), kernel2['data'].shape) self.assertTrue(np.allclose(np.ones([3, 1]).tolist(), kernel2['data']))