Używam Keras, aby zbudować konwluntalną sieć neuronową do segmentacji obrazu i chcę użyć "wyściółki odbicia" zamiast wyściółki "same", ale nie mogę znaleźć sposobu, aby zrobić to w Kerach.

inputs = Input((num_channels, img_rows, img_cols))
conv1=Conv2D(32,3,padding='same',kernel_initializer='he_uniform',data_format='channels_first')(inputs)

Czy istnieje sposób na wdrożenie warstwy refleksyjnej i włóż go do modelu Kerasa?

5
Akihiko 4 czerwiec 2018, 12:37

5 odpowiedzi

Najlepsza odpowiedź

Znalazłem rozwiązanie! Mamy tylko stworzyć nową klasę, która zajmuje warstwę jako wejście i używać predefiniowanej funkcji Tensorlow, aby to zrobić.

import tensorflow as tf
from keras.engine.topology import Layer
from keras.engine import InputSpec

class ReflectionPadding2D(Layer):
    def __init__(self, padding=(1, 1), **kwargs):
        self.padding = tuple(padding)
        self.input_spec = [InputSpec(ndim=4)]
        super(ReflectionPadding2D, self).__init__(**kwargs)

    def get_output_shape_for(self, s):
        """ If you are using "channels_last" configuration"""
        return (s[0], s[1] + 2 * self.padding[0], s[2] + 2 * self.padding[1], s[3])

    def call(self, x, mask=None):
        w_pad,h_pad = self.padding
        return tf.pad(x, [[0,0], [h_pad,h_pad], [w_pad,w_pad], [0,0] ], 'REFLECT')

# a little Demo
inputs = Input((img_rows, img_cols, num_channels))
padded_inputs= ReflectionPadding2D(padding=(1,1))(inputs)
conv1 = Conv2D(32, 3, padding='valid', kernel_initializer='he_uniform',
               data_format='channels_last')(padded_inputs)
3
Akihiko 25 lipiec 2018, 11:20

Akceptowana odpowiedź nie działa, jeśli mamy niezdefiniowane wymiary! Będzie błąd, gdy wymagana jest funkcja Compute_Output_Shape. Oto prosta praca do tego.

class ReflectionPadding2D(Layer):
    def __init__(self, padding=(1, 1), **kwargs):
        self.padding = tuple(padding)
        self.input_spec = [InputSpec(ndim=4)]
        super(ReflectionPadding2D, self).__init__(**kwargs)

    def compute_output_shape(self, s):
        if s[1] == None:
            return (None, None, None, s[3])
        return (s[0], s[1] + 2 * self.padding[0], s[2] + 2 * self.padding[1], s[3])

    def call(self, x, mask=None):
        w_pad, h_pad = self.padding
        return tf.pad(x, [[0, 0], [h_pad, h_pad], [w_pad, w_pad], [0, 0]], 'REFLECT')

    def get_config(self):
        config = super(ReflectionPadding2D, self).get_config()
        print(config)
        return config
0
Harshana Sumedha 7 luty 2020, 15:18

Ponieważ możesz sprawdzić w Dokumentacja nie ma takiego "odzwierciedlić" wyściółki. Tylko "taki sam" i "ważny" są realizowane w Kerach.

Może spróbujesz wdrożyć samodzielnie lub znaleźć, jeśli ktoś już to zrobił. Powinieneś oprzeć się w klasie Conv2D i sprawdzić, gdzie używany jest self.padding zmienna członkowska.

0
Daniel GL 4 czerwiec 2018, 09:55
import tensorflow as tf
from keras.layers import Lambda

inp_padded = Lambda(lambda x: tf.pad(x, [[0,0], [27,27], [27,27], [0,0]], 'REFLECT'))(inp)

Rozwiązanie z Akihiko nie działało z nową wersją Keras, więc wymyśliłem własne. Podkładki fragmentów w partii obrazów 202x202x3 do 256x256x3

2
Christof Henkel 24 sierpień 2018, 17:51

Przyjęta odpowiedź powyżej nie działa w obecnej wersji Keras. Oto wersja, która działa:

class ReflectionPadding2D(Layer):
    def __init__(self, padding=(1, 1), **kwargs):
        self.padding = tuple(padding)
        self.input_spec = [InputSpec(ndim=4)]
        super(ReflectionPadding2D, self).__init__(**kwargs)

    def compute_output_shape(self, s):
        """ If you are using "channels_last" configuration"""
        return (s[0], s[1] + 2 * self.padding[0], s[2] + 2 * self.padding[1], s[3])

    def call(self, x, mask=None):
        w_pad,h_pad = self.padding
        return tf.pad(x, [[0,0], [h_pad,h_pad], [w_pad,w_pad], [0,0] ], 'REFLECT')
6
jeevaa_v 17 listopad 2018, 09:41