Как спроектировать сеть Auto-Encoder с общим весом и несколькими входами/выходами?

У меня есть два разных типа изображений (изображение с камеры и соответствующий эскиз). Цель сети — найти сходство между обоими изображениями.

Сеть состоит из одного кодера и одного декодера. Мотивация одного кодера-декодера состоит в том, чтобы разделить веса между ними.

input_img = Input(shape=(img_width,img_height, channels))

def encoder(input_img):
    # Photo-Encoder Code
    pe = Conv2D(96, kernel_size=11, strides=(4,4), padding = 'SAME')(left_input) # (?, 64, 64, 96)
    pe = BatchNormalization()(pe)
    pe = Activation('selu')(pe)
    pe = MaxPool2D((3, 3), strides=(2, 2), padding = 'VALID')(pe) # (?, 31, 31, 96)

    pe = Conv2D(256, kernel_size=5, strides=(1,1), padding = 'SAME')(pe) # (?, 31, 31, 256)
    pe = BatchNormalization()(pe)
    pe = Activation('selu')(pe)
    pe = MaxPool2D((3, 3), strides=(2, 2), padding = 'VALID')(pe) #(?, 15, 15, 256)

    pe = Conv2D(384, kernel_size=3, strides=(1,1), padding = 'SAME')(pe) # (?, 15, 15, 384)
    pe = BatchNormalization()(pe)
    pe = Activation('selu')(pe)

    pe = Conv2D(384, kernel_size=3, strides=(1,1), padding = 'SAME')(pe) # (?, 15, 15, 384)
    pe = BatchNormalization()(pe)
    pe = Activation('selu')(pe)

    pe = Conv2D(256, kernel_size=3, strides=(1,1), padding = 'SAME')(pe) # (?, 15, 15, 256)
    pe = BatchNormalization()(pe)
    pe = Activation('selu')(pe)
    encoded = MaxPool2D((3, 3), strides=(2, 2), padding = 'VALID')(pe) # (?, 7, 7, 256)

    return encoded

def decoder(pe):
    pe = Conv2D(1024, kernel_size=7, strides=(1, 1), padding = 'VALID')(pe)
    pe = BatchNormalization()(pe)
    pe = Activation('selu')(pe)

    p_decoder_inp = Reshape((2,2,256))(pe)   

    pd = Conv2DTranspose(128, kernel_size=5, strides=(2, 2), padding='SAME')(p_decoder_inp)
    pd = Activation("selu")(pd)

    pd = Conv2DTranspose(64, kernel_size=5, strides=(2, 2), padding='SAME')(pd) 
    pd = Activation("selu")(pd)

    pd = Conv2DTranspose(32, kernel_size=5, strides=(2, 2), padding='SAME')(pd)
    pd = Activation("selu")(pd)

    pd = Conv2DTranspose(16, kernel_size=5, strides=(2, 2), padding='SAME')(pd) 
    pd = Activation("selu")(pd)

    pd = Conv2DTranspose(8, kernel_size=5, strides=(2, 2), padding='SAME')(pd)
    pd = Activation("selu")(pd)

    pd = Conv2DTranspose(4, kernel_size=5, strides=(2, 2), padding='SAME')(pd)
    pd = Activation("selu")(pd)

    decoded = Conv2DTranspose(3, kernel_size=5, strides=(2, 2), padding='SAME', activation='sigmoid')(pd) # (?, ?, ?, 3)

    return decoded


siamsese_net = Model([camera_img, sketch_img], [decoder(encoder(camera_img)), decoder(encoder(sketch_img))])

siamsese_net.summary()

Когда я визуализирую сеть, она показывает две разные сети.

введите здесь описание изображения

Но мне нужна сеть, которая принимает два входа, например, изображение с камеры и эскизное изображение, и возвращает те же изображения, используя один кодер-декодер.

Где я делаю неправильно?


person Ali R. Memon    schedule 17.02.2020    source источник


Ответы (1)


Ваши «функции» — это не «модели», они «создатели».

Обновите обе свои функции, например:

def create_encoder(): #no arguments!!!
    pe = Input(shape=(img_width,img_height, channels))
    ....
    encoded = ...

    encoder = Model(pe, encoded)
    return encoder

def create_decoder():
    pe = Input(shape=(7,7,256))
     ....
    decoded = ....

    decoder = Model(pe, decoded)
    return decoder

Теперь создайте модели:

encoder = create_encoder()
decoder = create_decoder()

siamsese_net = Model([camera_img, sketch_img],
                     [decoder(encoder(camera_img)), decoder(encoder(sketch_img))])

#where camera_img and sketch_image are 'Input' objects.
person Daniel Möller    schedule 17.02.2020
comment
Получение ошибки от декодера: ValueError: общий размер нового массива должен быть неизменным. Часть кодировщика изменилась следующим образом: img = Input(shape=(img_width,img_height, каналы)), pe = Conv2D(96, kernel_size=11, strides=(4,4), padding = 'SAME')(img). ...... В то время как часть декодера теперь выглядит так: pe = Input(shape=(img_width,img_height,channels)); pe = Conv2D(1024, kernel_size=7, strides=(1, 1), padding = 'VALID')(pe) ....... - person Ali R. Memon; 17.02.2020
comment
Конечно, моя ошибка. Внутри create_decoder начальный pe должен иметь форму закодированного вектора, который, по вашим комментариям, кажется (7, 7, 256). - person Daniel Möller; 17.02.2020