API для обнаружения объектов использовал tf-slim для построения моделей. Tf-slim - это API тензорного потока, который содержит множество предопределенных CNN и предоставляет строительные блоки CNN.
В API обнаружения объектов используемые CNN называются экстракторами объектов, для этих экстракторов объектов существуют классы-обертки, и они предоставляют единый интерфейс для различных архитектур моделей.
Например, модель faster_rcnn_resnet101
использовала resnet101 в качестве экстрактора возможностей, поэтому в файле faster_rcnn_resnet_v1_feature_extractor.py
в каталоге models
имеется соответствующий класс оболочки FasterRCNNResnetV1FeatureExtractor
.
from nets import resnet_utils
from nets import resnet_v1
slim = tf.contrib.slim
В этом классе вы обнаружите, что они использовали slim
для создания экстракторов функций. nets
- это модуль из slim
, который содержит много предопределенных CNN. Что касается вашей модели, определяющей код (слои), вы должны быть в состоянии найти его в модуле nets, вот класс resnet_v1
.
def resnet_v1_block(scope, base_depth, num_units, stride):
"""Helper function for creating a resnet_v1 bottleneck block.
Args:
scope: The scope of the block.
base_depth: The depth of the bottleneck layer for each unit.
num_units: The number of units in the block.
stride: The stride of the block, implemented as a stride in the last unit.
All other units have stride=1.
Returns:
A resnet_v1 bottleneck block.
"""
return resnet_utils.Block(scope, bottleneck, [{
'depth': base_depth * 4,
'depth_bottleneck': base_depth,
'stride': 1
}] * (num_units - 1) + [{
'depth': base_depth * 4,
'depth_bottleneck': base_depth,
'stride': stride
}])
def resnet_v1_50(inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
spatial_squeeze=True,
store_non_strided_activations=False,
min_base_depth=8,
depth_multiplier=1,
reuse=None,
scope='resnet_v1_50'):
"""ResNet-50 model of [1]. See resnet_v1() for arg and return description."""
depth_func = lambda d: max(int(d * depth_multiplier), min_base_depth)
blocks = [
resnet_v1_block('block1', base_depth=depth_func(64), num_units=3,
stride=2),
resnet_v1_block('block2', base_depth=depth_func(128), num_units=4,
stride=2),
resnet_v1_block('block3', base_depth=depth_func(256), num_units=6,
stride=2),
resnet_v1_block('block4', base_depth=depth_func(512), num_units=3,
stride=1),
]
return resnet_v1(inputs, blocks, num_classes, is_training,
global_pool=global_pool, output_stride=output_stride,
include_root_block=True, spatial_squeeze=spatial_squeeze,
store_non_strided_activations=store_non_strided_activations,
reuse=reuse, scope=scope)
В приведенном выше примере кода поясняется, как создается модель resnet50 (выберите resnet50, поскольку та же концепция, что и для resnet101, но с меньшим количеством слоев). Примечательно, что resnet50 имеет 4 блока, каждый из которых содержит [3,4,6,3] единиц. А вот диаграмма resnet50 , там вы видите 4 блока.
* * 1030
Итак, мы закончили с частью resnet, эти функции, извлеченные экстрактором функций первого этапа (resnet101), будут поданы в генератор предложений , и он будет генерировать регионы, эти регионы вместе с объектами, затем будет передан в коробочный классификатор для прогнозирования класса и регрессии bbox.
Часть faster_rcnn
, указанная как meta_architectures
, meta_architectures
- это рецепт преобразования архитектур классификации в архитектуры обнаружения, в данном случае от resnet101
до faster_rcnn
. Вот диаграмма faster_rcnn_meta_architecture
( источник ).
![enter image description here](https://i.stack.imgur.com/xFUUt.png)
Здесь вы видите в части классификатора блока также есть операции объединения (для обрезанной области) и сверточные операции (для извлечения элементов из обрезанной области) . И в классе faster_rcnn_meta_arch
, эта строка является операцией maxpool, и более поздняя операция свертки выполняется в классе снова и снова, но для второго этапа. И вы можете четко видеть, как используется другой блок.
def _extract_box_classifier_features(self, proposal_feature_maps, scope):
"""Extracts second stage box classifier features.
Args:
proposal_feature_maps: A 4-D float tensor with shape
[batch_size * self.max_num_proposals, crop_height, crop_width, depth]
representing the feature map cropped to each proposal.
scope: A scope name (unused).
Returns:
proposal_classifier_features: A 4-D float tensor with shape
[batch_size * self.max_num_proposals, height, width, depth]
representing box classifier features for each proposal.
"""
with tf.variable_scope(self._architecture, reuse=self._reuse_weights):
with slim.arg_scope(
resnet_utils.resnet_arg_scope(
batch_norm_epsilon=1e-5,
batch_norm_scale=True,
weight_decay=self._weight_decay)):
with slim.arg_scope([slim.batch_norm],
is_training=self._train_batch_norm):
blocks = [
resnet_utils.Block('block4', resnet_v1.bottleneck, [{
'depth': 2048,
'depth_bottleneck': 512,
'stride': 1
}] * 3)
]
proposal_classifier_features = resnet_utils.stack_blocks_dense(
proposal_feature_maps, blocks)
return proposal_classifier_features