Spaces:
Runtime error
Runtime error
| # coding=utf-8 | |
| # Copyright 2021 The Deeplab2 Authors. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| r"""Script to export deeplab model to saved model.""" | |
| import functools | |
| from typing import Any, MutableMapping, Sequence, Text | |
| from absl import app | |
| from absl import flags | |
| import tensorflow as tf | |
| from google.protobuf import text_format | |
| from deeplab2 import config_pb2 | |
| from deeplab2.data import dataset | |
| from deeplab2.data.preprocessing import input_preprocessing | |
| from deeplab2.model import utils | |
| from deeplab2.trainer import train_lib | |
| _FLAGS_EXPERIMENT_OPTION_PATH = flags.DEFINE_string( | |
| 'experiment_option_path', | |
| default='', | |
| help='Path to the experiment option text proto.') | |
| _FLAGS_CKPT_PATH = flags.DEFINE_string( | |
| 'checkpoint_path', | |
| default='', | |
| help='Path to the saved checkpoint.') | |
| _FLAGS_OUTPUT_PATH = flags.DEFINE_string( | |
| 'output_path', | |
| default='', | |
| help='Output directory path for the exported saved model.') | |
| _FLAGS_MERGE_WITH_TF_OP = flags.DEFINE_boolean( | |
| 'merge_with_tf_op', | |
| default=False, | |
| help='Whether to use customized TF op for merge semantic and instance ' | |
| 'predictions. Set it to True to reproduce the numbers as reported in ' | |
| 'paper, but the saved model would require specifically compiled TensorFlow ' | |
| 'to run.') | |
| class DeepLabModule(tf.Module): | |
| """Class that runs DeepLab inference end-to-end.""" | |
| def __init__(self, config: config_pb2.ExperimentOptions, ckpt_path: Text, | |
| use_tf_op: bool = False): | |
| super().__init__(name='DeepLabModule') | |
| dataset_options = config.eval_dataset_options | |
| dataset_name = dataset_options.dataset | |
| crop_height, crop_width = dataset_options.crop_size | |
| config.evaluator_options.merge_semantic_and_instance_with_tf_op = use_tf_op | |
| # Disable drop path and recompute grad as they are only used in training. | |
| config.model_options.backbone.drop_path_keep_prob = 1.0 | |
| deeplab_model = train_lib.create_deeplab_model( | |
| config, | |
| dataset.MAP_NAME_TO_DATASET_INFO[dataset_name]) | |
| self._is_motion_deeplab = ( | |
| config.model_options.WhichOneof('meta_architecture') == | |
| 'motion_deeplab') | |
| # For now we only support batch size of 1 for saved model. | |
| input_shape = train_lib.build_deeplab_model( | |
| deeplab_model, (crop_height, crop_width), batch_size=1) | |
| self._input_depth = input_shape[-1] | |
| checkpoint = tf.train.Checkpoint(**deeplab_model.checkpoint_items) | |
| # Not all saved variables (e.g. variables from optimizer) will be restored. | |
| # `expect_partial()` to suppress the warning. | |
| checkpoint.restore(ckpt_path).expect_partial() | |
| self._model = deeplab_model | |
| self._preprocess_fn = functools.partial( | |
| input_preprocessing.preprocess_image_and_label, | |
| label=None, | |
| crop_height=crop_height, | |
| crop_width=crop_width, | |
| prev_label=None, | |
| min_resize_value=dataset_options.min_resize_value, | |
| max_resize_value=dataset_options.max_resize_value, | |
| resize_factor=dataset_options.resize_factor, | |
| is_training=False) | |
| def get_input_spec(self): | |
| """Returns TensorSpec of input tensor needed for inference.""" | |
| # We expect a single 3D, uint8 tensor with shape [height, width, channels]. | |
| return tf.TensorSpec(shape=[None, None, self._input_depth], dtype=tf.uint8) | |
| def __call__(self, input_tensor: tf.Tensor) -> MutableMapping[Text, Any]: | |
| """Performs a forward pass. | |
| Args: | |
| input_tensor: An uint8 input tensor of type tf.Tensor with shape [height, | |
| width, channels]. | |
| Returns: | |
| A dictionary containing the results of the specified DeepLab architecture. | |
| The results are bilinearly upsampled to input size before returning. | |
| """ | |
| input_size = [tf.shape(input_tensor)[0], tf.shape(input_tensor)[1]] | |
| if self._is_motion_deeplab: | |
| # For motion deeplab, split the input tensor to current and previous | |
| # frame before preprocessing, and re-assemble them. | |
| image, prev_image = tf.split(input_tensor, 2, axis=2) | |
| (resized_image, processed_image, _, processed_prev_image, | |
| _) = self._preprocess_fn(image=image, prev_image=prev_image) | |
| processed_image = tf.concat( | |
| [processed_image, processed_prev_image], axis=2) | |
| else: | |
| (resized_image, processed_image, _, _, _) = self._preprocess_fn( | |
| image=input_tensor) | |
| resized_size = tf.shape(resized_image)[0:2] | |
| # Making input tensor to 4D to fit model input requirements. | |
| outputs = self._model(tf.expand_dims(processed_image, 0), training=False) | |
| # We only undo-preprocess for those defined in tuples in model/utils.py. | |
| return utils.undo_preprocessing(outputs, resized_size, | |
| input_size) | |
| def main(argv: Sequence[str]) -> None: | |
| if len(argv) > 1: | |
| raise app.UsageError('Too many command-line arguments.') | |
| config = config_pb2.ExperimentOptions() | |
| with tf.io.gfile.GFile(_FLAGS_EXPERIMENT_OPTION_PATH.value, 'r') as f: | |
| text_format.Parse(f.read(), config) | |
| module = DeepLabModule( | |
| config, _FLAGS_CKPT_PATH.value, _FLAGS_MERGE_WITH_TF_OP.value) | |
| signatures = module.__call__.get_concrete_function(module.get_input_spec()) | |
| tf.saved_model.save( | |
| module, _FLAGS_OUTPUT_PATH.value, signatures=signatures) | |
| if __name__ == '__main__': | |
| app.run(main) | |