FCN для бинарной сегментации semanti c изображений с несбалансированным распределением классов - PullRequest
0 голосов
/ 24 февраля 2020

Я использую реализацию FCN-8 на основе VGG16 в Keras с Tensorflow в качестве Backend для выполнения сегментации c на изображениях. Цель состоит в том, чтобы выделить железнодорожную колею на изображении, взятом из кабины, что по существу делает ее проблемой двоичной сегментации: колея является передним планом (класс 1), а все остальное относится к фону (класс 0). Результат должен быть похож на на следующем изображении , где результирующая сегментация накладывается на исходное изображение (я пока не могу публиковать изображения).

Я адаптировал FCN, указанный в это сообщение в блоге путем изменения следующих частей:

  • Уменьшено количество ядер на каждом слое, поскольку FCN выглядело излишне большим.
  • Изменена функция потерь в binary_crossentropy , так как я имею дело с двумя различными классами.
  • Удален импорт VGG16, поскольку я хочу обучить модель на моих данных с самого начала.

Это дало следующую модель:

Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_33 (InputLayer)           (None, 224, 224, 3)  0                                            
__________________________________________________________________________________________________
block1_conv1 (Conv2D)           (None, 224, 224, 2)  56          input_33[0][0]                   
__________________________________________________________________________________________________
block1_conv2 (Conv2D)           (None, 224, 224, 2)  38          block1_conv1[0][0]               
__________________________________________________________________________________________________
block1_pool (MaxPooling2D)      (None, 112, 112, 2)  0           block1_conv2[0][0]               
__________________________________________________________________________________________________
block2_conv1 (Conv2D)           (None, 112, 112, 4)  76          block1_pool[0][0]                
__________________________________________________________________________________________________
block2_conv2 (Conv2D)           (None, 112, 112, 4)  148         block2_conv1[0][0]               
__________________________________________________________________________________________________
block2_pool (MaxPooling2D)      (None, 56, 56, 4)    0           block2_conv2[0][0]               
__________________________________________________________________________________________________
block3_conv1 (Conv2D)           (None, 56, 56, 8)    296         block2_pool[0][0]                
__________________________________________________________________________________________________
block3_conv2 (Conv2D)           (None, 56, 56, 8)    584         block3_conv1[0][0]               
__________________________________________________________________________________________________
block3_conv3 (Conv2D)           (None, 56, 56, 8)    584         block3_conv2[0][0]               
__________________________________________________________________________________________________
block3_pool (MaxPooling2D)      (None, 28, 28, 8)    0           block3_conv3[0][0]               
__________________________________________________________________________________________________
block4_conv1 (Conv2D)           (None, 28, 28, 16)   1168        block3_pool[0][0]                
__________________________________________________________________________________________________
block4_conv2 (Conv2D)           (None, 28, 28, 16)   2320        block4_conv1[0][0]               
__________________________________________________________________________________________________
block4_conv3 (Conv2D)           (None, 28, 28, 16)   2320        block4_conv2[0][0]               
__________________________________________________________________________________________________
block4_pool (MaxPooling2D)      (None, 14, 14, 16)   0           block4_conv3[0][0]               
__________________________________________________________________________________________________
block5_conv1 (Conv2D)           (None, 14, 14, 16)   2320        block4_pool[0][0]                
__________________________________________________________________________________________________
block5_conv2 (Conv2D)           (None, 14, 14, 16)   2320        block5_conv1[0][0]               
__________________________________________________________________________________________________
block5_conv3 (Conv2D)           (None, 14, 14, 16)   2320        block5_conv2[0][0]               
__________________________________________________________________________________________________
block5_pool (MaxPooling2D)      (None, 7, 7, 16)     0           block5_conv3[0][0]               
__________________________________________________________________________________________________
conv6 (Conv2D)                  (None, 7, 7, 128)    100480      block5_pool[0][0]                
__________________________________________________________________________________________________
pool4_11 (Conv2D)               (None, 14, 14, 2)    34          block4_pool[0][0]                
__________________________________________________________________________________________________
conv7 (Conv2D)                  (None, 7, 7, 128)    16512       conv6[0][0]                      
__________________________________________________________________________________________________
conv2d_transpose_98 (Conv2DTran (None, 28, 28, 2)    16          pool4_11[0][0]                   
__________________________________________________________________________________________________
pool3_11 (Conv2D)               (None, 28, 28, 2)    18          block3_pool[0][0]                
__________________________________________________________________________________________________
conv2d_transpose_97 (Conv2DTran (None, 28, 28, 2)    4096        conv7[0][0]                      
__________________________________________________________________________________________________
add (Add)                       (None, 28, 28, 2)    0           conv2d_transpose_98[0][0]        
                                                                 pool3_11[0][0]                   
                                                                 conv2d_transpose_97[0][0]        
__________________________________________________________________________________________________
conv2d_transpose_99 (Conv2DTran (None, 224, 224, 2)  256         add[0][0]                        
__________________________________________________________________________________________________
activation_33 (Activation)      (None, 224, 224, 2)  0           conv2d_transpose_99[0][0]        
==================================================================================================
Total params: 135,962
Trainable params: 135,962
Non-trainable params: 0
__________________________________________________________________________________________________

Однако результаты недостаточно точны, как видно здесь . В то время как часть, близкая к поезду, кажется более или менее нормальной, часть пути, которая находится дальше, вообще не распознается.

Проблема заключается в том, что путь становится более узким в направлении горизонт, но отдаленная часть также содержит более актуальную информацию о кривизне дорожки. На всех изображениях ближняя часть выглядит очень похоже.

Мой вопрос: как я могу заставить данную модель FCN-8 также распознавать детали, которые находятся на ie дальше?

Поскольку очевидно, что фона намного больше, чем переднего плана (в ~ 40 раз), я попытался использовать параметр class_weights функции model.fit(). Однако, поскольку мои цели закодированы в горячем виде, они являются трехмерными (высота изображения х ширина изображения х количество классов). Для этой фигуры Keras, похоже, не поддерживает веса классов:

`class_weight` not supported for 3+ dimensional targets.

Я также пытался следовать инструкциям, приведенным в в этом выпуске , и использовать веса выборок вместо весов классов, но как Я очень новичок в Keras и Deep Learning в целом, я не понимал, какие части моей модели мне нужно настроить, чтобы заставить это работать. Более того, я даже не уверен, решит ли это мою проблему.

Уменьшение изображения до соответствующей части дало следующий результат , который определенно является более точным и "плавным". Соотношение между классами 0 и 1 в этом случае составляет около 4: 1, что может указывать на то, что соотношение между классами в исходном изображении действительно отрицательно влияет на результат. Однако поиск соответствующей области на изображении добавляет дополнительный процесс к процессу, который я хочу избежать, чтобы он оставался общим.

Наконец, увеличение количества эпох не кажется решением, так как видел в этом графике потерь . Не было заметной разницы при использовании 30 или 3000 изображений.

Итак, чтобы подвести итог моего вопроса: Если модель FCN-8 теоретически способна удовлетворительно решить мою задачу, что я могу изменить обнаружить важные детали дальше? Если это модель, ограничивающая точность, какая другая модель будет лучше для поставленной задачи? И если решение действительно вводит выборочные веса, какую форму они должны были бы применить? Поскольку я очень новичок в Keras, я бы хотел пока не писать собственные функции потерь и вместо этого просто передавать веса в качестве параметра функции model.fit(), если только эту проблему не решить очень легко.

Спасибо!

...