TensorFlow - обнаружение ключевых точек дает тепловую карту нулей - PullRequest
0 голосов
/ 18 мая 2018

Я использую основанную на обнаружении 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 неверна или что-то важное отсутствует?

Ответы [ 2 ]

0 голосов
/ 20 марта 2019

Извините за воскрешение старого потока, но у меня почти такая же проблема.

За исключением моего случая, я беру почти точно такую ​​же структуру, которую использует проект OpenPose (т. е. VGG плюс несколько разветвленных этапов), но с меньшим количеством этапов, с глубиной изображения в качестве входных данных и только тремя ключевыми точками (для моего проекта мне нужны только руки и лицо).

Изображение глубины - это вход , а вывод - это тепловая карта с уменьшением (1, ч / 8, ш / 8, 3)-стек с пиками Гаусса вместо ключевых точек (выглядит примерно так: enter image description here).

Потери рассчитываются так же, как в посте выше, с разницей между GT-heatmap ипредсказанная тепловая карта.

И да, во время тренировок, в значительной степени после первых 2-3 эпох, я вижу, что на выходе получается просто пустое изображение, полное нулей (и, возможно, небольшой пик в [0; 0]) и остается таким всегда (у меня хватило терпения примерно на 1500 эпох).

Кстати, я использую Keras для обучения.

0 голосов
/ 28 августа 2018

Можете ли вы также загрузить свои обучающие коды?

Кроме того, имеет ли земная истинная тепловая карта форму (партия, высота, ширина, 16), и каждый канал представляет собой гауссовский пик вокруг координаты ключевой точки?Если это так, то это проблема оценки позы.

А пока попробуйте эти 2 предложения для начала.

  1. Попробуйте модель на 1 тренировочном образе без регуляризации и увеличения изображения.Затем примените другую шкалу скорости обучения.Посмотрите, уменьшается ли потеря, и предсказание тренировочного образа похоже на наземную карту истинности.
  2. Ваша функция потерь выглядит нормально, хотя я бы просто использовал: tf.reduce_sum(tf.square(heatmaps - heat_ground_truth, 2) , name='heat_loss')

Если это не поможет, я бы посоветовал попробовать некоторые методы оценки позы, поскольку FPN - это скорее метод определения объекта и семантической сегментации. Сверточные машины представления может быть хорошей бумагой для начала.

Convolutional Pose Machines использует масштабированную тепловую карту в качестве наземной истинности и выхода сети.После магистрали CNN, VGG в газете, но я думаю, что res-net тоже работает.Например, после 16 шагов объединения, форма тепловой карты (партия, высота / 16, ширина / 16, 16).Затем используйте ту же функцию потерь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...