---
# System prepended metadata

title: google-search kws_streaming model translation code tracing

---

# google-search kws_streaming model translation code tracing

start from directory, google-research/kws_streaming/train/

## 1. In file, ==train/model_train_eval.py==:

in function, main():

```python=268
        # convert model to TFlite
        folder_name = opt_name + 'tflite_stream_state_external'
        file_name = 'stream_state_external.tflite'
        mode = modes.Modes.STREAM_EXTERNAL_STATE_INFERENCE
        test.convert_model_tflite(flags, folder_name, mode, file_name,
                                  optimizations=optimizations)

```

go into line 272: ==test.convert_model_tflite()==

## 2. In file, ==train/test.py==:

in function, convert_model_tflite():
Line 527 shows this function convert model.

```python=521
def convert_model_tflite(flags,
                         folder,
                         mode,
                         fname,
                         weights_name='best_weights',
                         optimizations=None):
  """Convert model to streaming and non streaming TFLite.

  Args:
      flags: model and data settings
      folder: folder where converted model will be saved
      mode: inference mode
      fname: file name of converted model
      weights_name: file name with model weights
      optimizations: list of optimization options
  """
```

Line 544 shows models loading. If wanting to modify NN models, go to the folder: ==models/== and find related module file such as cnn.py, dnn.py.
```pythone=544
model = models.MODELS[flags.model_name](flags)
model.load_weights(os.path.join(flags.train_dir,
                                weights_name)).expect_partial()
```
---

```python=547
  # convert trained model to non streaming TFLite stateless
  # to finish other tests we do not stop program if exception happen here
  path_model = os.path.join(flags.train_dir, folder)
  if not os.path.exists(path_model):
    os.makedirs(path_model)
  try:
    with open(os.path.join(path_model, fname), 'wb') as fd:
      fd.write(
          utils.model_to_tflite(sess, model, flags, mode, path_model,
                                optimizations))
```

go into line 555: ==utils.model_to_tflite()==

## 3. In file, ==models/utils.py==:

Line 333 shows this function is to create tflite file.

```python=333
  """Convert non streaming model to tflite inference model.

  If mode==modes.Modes.STREAM_EXTERNAL_STATE_INFERENCE then inference graph
  will be stateless: all states will be managed outside of the model and
  will be passed to the model as additional inputs/outputs.
  If mode==modes.Modes.STREAM_INTERNAL_STATE_INFERENCE then inference graph
  will be stateful: all states will be part of the model - so model size
  can increase. Latest version of TFLite converter supports it, so
  conversion has to be done in eager mode.
```

---
Line 374 shows not only handling non-stream but streaming.

```python=373
  # convert non streaming Keras model to
  # Keras inference model (non streaming or streaming)
  model_stream = to_streaming_inference(model_non_stream, flags, mode)
```

go into line 375: ==to_streaming_inference()==

## 4. In function, to_streaming_inference:

```python=272
def to_streaming_inference(model_non_stream, flags, mode):
  """Convert non streaming trained model to inference modes.

  Args:
    model_non_stream: trained Keras model non streamable
    flags: settings with global data and model properties
    mode: it supports Non streaming inference, Streaming inference with internal
      states, Streaming inference with external states

```

---
go into line 313: ==convert_to_inference_model()==

```python=311
  quantize_stream_scope = quantize.quantize_scope()
  with quantize_stream_scope:
    model_inference = convert_to_inference_model(model_non_stream,
                                                 input_tensors, mode)
  return model_inference
```

# 5. In function, convert_to_inference_model:

```python=209
def convert_to_inference_model(model, input_tensors, mode):
  """Convert functional `Model` instance to a streaming inference.

  It will create a new model with new inputs: input_tensors.
  All weights will be copied. Internal states for streaming mode will be created
  Only functional Keras model is supported!

  Args:
      model: Instance of `Model`.
      input_tensors: list of input tensors to build the model upon.
      mode: is defined by modes.Modes

  Returns:
      An instance of streaming inference `Model` reproducing the behavior
      of the original model, on top of new inputs tensors,
      using copied weights.
```

---

Line 252 shows converting to streaming.

Line 253 shows get states.

Line 256 shows creating new model.

Line 264 ==return new_streaming_model==.

```python=247
    model = _set_mode(model, mode)
    new_model = _clone_model(model, input_tensors)

  if mode == modes.Modes.STREAM_INTERNAL_STATE_INFERENCE:
    return _copy_weights(new_model, model)
  elif mode == modes.Modes.STREAM_EXTERNAL_STATE_INFERENCE:
    input_states, output_states = _get_input_output_states(new_model)
    all_inputs = new_model.inputs + input_states
    all_outputs = new_model.outputs + output_states
    new_streaming_model = tf.keras.Model(all_inputs, all_outputs)
    new_streaming_model.input_shapes = _get_state_shapes(all_inputs)
    new_streaming_model.output_shapes = _get_state_shapes(all_outputs)

    # inference streaming model with external states
    # has the same number of weights with
    # non streaming model so we can use set_weights directly
    new_streaming_model.set_weights(model.get_weights())
    return new_streaming_model
  elif mode == modes.Modes.NON_STREAM_INFERENCE:
    new_model.set_weights(model.get_weights())
    return new_model
  else:
    raise ValueError('non supported mode ', mode)
```

---
go into Line 248: ==_clone_model()==

```python=88
def _clone_model(model, input_tensors):
  """Clone model with configs, except of weights."""
  new_input_layers = {}  # Cache for created layers.
  # pylint: disable=protected-access
  if input_tensors is not None:
    # Make sure that all input tensors come from a Keras layer.
    input_tensors = tf.nest.flatten(input_tensors)
    for i, input_tensor in enumerate(input_tensors):
      if not tf.keras.backend.is_keras_tensor(input_tensor):
        raise ValueError('Expected keras tensor but get', input_tensor)
      original_input_layer = model._input_layers[i]
      newly_created_input_layer = input_tensor._keras_history.layer
      new_input_layers[original_input_layer] = newly_created_input_layer

  model_config, created_layers = models_utils._clone_layers_and_model_config(
      model, new_input_layers, models_utils._clone_layer)
  # pylint: enable=protected-access

  # Reconstruct model from the config, using the cloned layers.
  input_tensors, output_tensors, created_layers = (
      functional.reconstruct_from_config(
          model_config, created_layers=created_layers))

  new_model = tf.keras.Model(input_tensors, output_tensors, name=model.name)
  return new_model
```