Esempio n. 1
0
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
Esempio n. 2
0
    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']))