Я использую основанную на обнаружении CNN для оценки позы рук (нахождение суставов рук на глубине изображения одной руки).Мой план состоял в том, чтобы сначала использовать FCN, чтобы найти 2D-координаты всех 16 ключевых точек.Основой является ResNet-50-FPN, и график вычислений можно увидеть здесь .Структура res2a ~ res5c показана здесь .
Когда я тренирую эту модель с набором данных положения руки ICVL, карты выходных объектов сходятся в виде полных черных изображений, где все значения пикселей почти равны нулю.Основными истинами являются карты глубины и тепловые карты типа this .Если я добавлю функцию активации сигмоида после последнего сверточного слоя (как показано на рисунке), выходная тепловая карта будет напоминать белый шум.В любом случае, обнаружение FCN было абсолютно бесполезным, в то время как потери не будут уменьшаться вообще.
Моя модель CNN может быть кратко продемонстрирована с помощью кода ниже:
heat_chain = TensorChain(image_tensor) \
.convolution_layer_2d(3, 16, 1, 'conv1') \
.batch_normalization() \
.relu('relu1') \
.max_pooling_layer_2d(2, 'pool1') \
.bottleneck_2d(64, 256, 'res2a') \
.bottleneck_2d(64, 256, 'res2b') \
.bottleneck_2d(64, 256, 'res2c') \
.branch_identity_mapping() \
.bottleneck_2d(128, 512, 'res3a', stride=2) \
.bottleneck_2d(128, 512, 'res3b') \
.bottleneck_2d(128, 512, 'res3c') \
.bottleneck_2d(128, 512, 'res3d') \
.branch_identity_mapping() \
.bottleneck_2d(256, 1024, 'res4a', stride=2) \
.bottleneck_2d(256, 1024, 'res4b') \
.bottleneck_2d(256, 1024, 'res4c') \
.bottleneck_2d(256, 1024, 'res4d') \
.bottleneck_2d(256, 1024, 'res4e') \
.bottleneck_2d(256, 1024, 'res4f') \
.branch_identity_mapping() \
.bottleneck_2d(512, 2048, 'res5a', stride=2) \
.bottleneck_2d(512, 2048, 'res5b') \
.bottleneck_2d(512, 2048, 'res5c') \
.upsampling_block_2d(2, [-1, 30, 40, 512], 'upsample1') \
.merge_identity_mapping_2d('merge1') \
.upsampling_block_2d(2, [-1, 60, 80, 256], 'upsample2') \
.merge_identity_mapping_2d('merge2') \
.upsampling_block_2d(2, [-1, 120, 160, 64], 'upsample3') \
.merge_identity_mapping_2d('merge3') \
.upsampling_block_2d(2, [-1, 240, 320, 16], 'upsample4') \
.convolution_layer_2d(3, 16, 1, 'conv2') \
.convolution_layer_2d(3, 16, 1, 'conv3')
heatmaps = tf.identity(heat_chain.output_tensor, name='heatmaps')
heat_loss = tf.reduce_mean(
tf.reduce_sum(tf.pow(heatmaps - heat_ground_truth, 2), axis=[1, 2, 3]), name='heat_loss')
В котором branch_identity_mapping () помещает последний тензор в стек и merge_identity_mapping_2d () извлекает сохраненный тензор и добавляет его в текущий тензор (может также соответствовать измерениям со сверточным слоем 1x1).
Я совершенно не понимаю, что не так,Может быть, моя реализация ResNet-50-FPN неверна или что-то важное отсутствует?