Модификация SSD MobileNet 1 PPN для создания SSD MobileNet 2 PPN - PullRequest
0 голосов
/ 28 февраля 2019

Предоставленная конфигурация SSD MobileNet 1 PPN работает очень хорошо, но мне любопытно посмотреть, может ли «магистральная сеть» быть реально заменена на MobileNet 2.

Я сделал это в некоторой степени, иМои конфигурации PPN V2 хорошо работают по сравнению с соответствующими конфигурациями PPN V1 , которые также сходятся плавно и быстро (т. е. полезный график с шагом 10 тыс. [по моим собственным данным]).

Я экспериментировал с различными конечными точками и просматривал полученные графики в Tensorboard, в частности, рассматривая форму соединения между последним слоем MNet2 и первым слоем PPN MaxPool.

Для существующего PPN MNet1 с размером изображения 512x288:

  • PPN MNet1: 1x18x32x512

Для моего случая (т.е. 320 жестко запрограммированы в файле ниже)

  • PPN MNet2: 1x9x16x320

Другие конечные точки MNet2, которые я выбрал, создавали жизнеспособные графики, но с очень разными размерами файлов, когда были заморожены.Слои PPN MaxPool создаются на основе формы последнего слоя MNet2, поэтому я скопировал метод из примеров FPN, который добавляет окончательную свертку для манипулирования этим.

Я хотел бы понять следующее:

  1. Должен ли уровень конечной точки из MNet2 быть расширенным слоем или сжатым слоем?
  2. Какой PPN лучше всего подходит в качестве входного слоя и нужно ли его создавать дополнительно (например, как FPN)MNet2 - см. _create_modified_mobilenet_config)?

ssd_mobilenet_v2_ppn

Я взял код из примеров SSD PPN и FPN.

  1. Создать новый файл ssd_mobilenet_v2_ppn_feature_extractor.py in object_detection / models путем копирования и изменения значения для v1 .
  2. Редактирование файла model_builder.py в object_detection / builders до зарегистрируйте новый экстрактор функций.
  3. Ссылка на новый экстрактор функций PPN V2 в файле конфигурации обучения графов иустановите глубину box_detector равной значению, которое вы выбрали для num_outputs в новом экстракторе возможностей.

Я показал весь файл экстрактора объектов, так как он не большой, и это единственный важный код, необходимый:

import tensorflow as tf

from object_detection.meta_architectures import ssd_meta_arch
from object_detection.models import feature_map_generators
from object_detection.utils import context_manager
from object_detection.utils import ops
from object_detection.utils import shape_utils

import copy
import functools
from nets.mobilenet import mobilenet
from nets.mobilenet import mobilenet_v2

slim = tf.contrib.slim

# should num_outputs match ssd.box_predictor.depth?
def _create_modified_mobilenet_config( num_outputs=320 ):
    conv_op = functools.partial( slim.separable_conv2d, depth_multiplier=1 )
    #conv_op = slim.conv2d    
    conv_defs = copy.deepcopy( mobilenet_v2.V2_DEF )    
    conv_defs['spec'][-1] = mobilenet.op( conv_op, stride=1, kernel_size=[1, 1], num_outputs=num_outputs )
    return conv_defs

class SSDMobileNetV2PpnFeatureExtractor(ssd_meta_arch.SSDFeatureExtractor):

    def __init__( 
            self,
            is_training,
            depth_multiplier,
            min_depth,
            pad_to_multiple,
            conv_hyperparams_fn,
            reuse_weights=None,
            use_explicit_padding=False,
            use_depthwise=False,
            override_base_feature_extractor_hyperparams=False
        ):

        super( SSDMobileNetV2PpnFeatureExtractor, self ).__init__(
            is_training=is_training,
            depth_multiplier=depth_multiplier,
            min_depth=min_depth,
            pad_to_multiple=pad_to_multiple,
            conv_hyperparams_fn=conv_hyperparams_fn,
            reuse_weights=reuse_weights,
            use_explicit_padding=use_explicit_padding,
            use_depthwise=use_depthwise,
            override_base_feature_extractor_hyperparams=override_base_feature_extractor_hyperparams)  

        self._conv_defs = None
        if self._use_depthwise:
            self._conv_defs = _create_modified_mobilenet_config()         

    def preprocess(self, resized_inputs):
        return (2.0 / 255.0) * resized_inputs - 1.0

    def extract_features(self, preprocessed_inputs):

        preprocessed_inputs = shape_utils.check_min_image_dim( 33, preprocessed_inputs )

        final_endpoint = 'layer_19'
        feature_endpoint = 'layer_19'

        with tf.variable_scope( 'MobilenetV2', reuse=self._reuse_weights ) as scope:
            # NB: checked all other MNet feature extractors have: is_training=None            
            with slim.arg_scope( mobilenet_v2.training_scope( is_training=None, bn_decay=0.9997 ) ), \
                 slim.arg_scope( [ mobilenet.depth_multiplier ], min_depth=self._min_depth ):

                with (
                        slim.arg_scope( self._conv_hyperparams_fn() )
                        if self._override_base_feature_extractor_hyperparams 
                        else context_manager.IdentityContextManager()
                    ):

                    _, image_features = mobilenet_v2.mobilenet_base( 
                        ops.pad_to_multiple( preprocessed_inputs, self._pad_to_multiple ),
                        final_endpoint=final_endpoint,
                        min_depth=self._min_depth,
                        depth_multiplier=self._depth_multiplier,
                        conv_defs=self._conv_defs,
                        use_explicit_padding=self._use_explicit_padding,
                        scope=scope
                    )                

                with slim.arg_scope( self._conv_hyperparams_fn() ):
                    feature_maps = feature_map_generators.pooling_pyramid_feature_maps(
                        base_feature_map_depth=0,
                        num_layers=6,
                        image_features={
                            'image_features': image_features[ feature_endpoint ]
                        }
                    )
        return feature_maps.values()
...