Циклы и конкатенация в последовательном API Keras - PullRequest
0 голосов
/ 04 марта 2020

Допустим, у меня определена модель, подобная этой:

from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import (BatchNormalization, concatenate,
                                     Conv2D, Conv2DTranspose, DepthwiseConv2D,
                                     Dropout, Input, MaxPooling2D,
                                     ReLU, ZeroPadding2D)

input_layer = Input((64, 64, 3))

conv1 = Conv2D(16, (3, 3), padding="same")(input_layer)
conv1 = BatchNormalization()(conv1)
conv1 = ReLU()(conv1)
pool1 = MaxPooling2D((2,2))(conv1)

conv2 = Conv2D(32, (3, 3), padding="same")(pool1)
conv2 = BatchNormalization()(conv2)
conv2 = ReLU()(conv2)
pool2 = MaxPooling2D((2,2))(conv2)

conv3 = Conv2D(64, (3, 3), padding="same")(pool2)
conv3 = BatchNormalization()(conv3)
conv3 = ReLU()(conv3)
pool3 = MaxPooling2D((2,2))(conv3)

mid = Conv2D(128, (3, 3), padding="same")(pool3)
mid = BatchNormalization()(mid)
mid = ReLU()(mid)

dconv3 = Conv2DTranspose(64, (3, 3), strides=(2, 2), padding="same")(mid)
cat3 = concatenate([dconv3, conv3])

dconv2 = Conv2DTranspose(32, (3, 3), strides=(2, 2), padding="same")(dconv3)
cat2 = concatenate([dconv2, conv2])

dconv1 = Conv2DTranspose(16, (3, 3), strides=(2, 2), padding="same")(dconv2)
cat1 = concatenate([dconv1, conv1])

output_layer = Conv2D(1, (1,1), padding="same", activation="sigmoid")(dconv1)

model = Model(input_layer, output_layer)

Модель очень проста UNET, которая требует объединения нижних выборочных блоков с повышающими выборками. Теперь давайте представим, что я хочу определить эту точную модель, но с некоторой произвольной глубиной, такой как 2, 3, 4, 5 и т. Д. Вместо того, чтобы go вводить и вручную изменять параметры, я хотел бы автоматизировать построение модели.

Я очень близок к выполнению этого, но у меня не получается во время объединения. См. ниже.

class configurable_model():
    def __init__(self, csize, channels, start_neurons, depth):
        self.csize = csize
        self.channels = channels
        self.start_neurons = start_neurons
        self.depth = depth

    def _convblock(self, factor, name):
        layer = Sequential(name=name)
        layer.add(Conv2D(self.start_neurons * factor, (3, 3), padding="same"))
        layer.add(BatchNormalization())
        layer.add(ReLU())
        return layer

    def build_model(self):
        model = Sequential()
        model.add(Input((self.csize, self.csize, self.channels), name='input'))

        factor = 1
        for idx in range(self.depth):
            model.add(self._convblock(factor, f'downblock{idx}'))
            model.add(MaxPooling2D((2,2)))
            factor *= 2

        model.add(self._convblock(factor, name='middle'))

        for idx in reversed(range(self.depth)):
            factor //= 2
            model.add(Conv2DTranspose(self.start_neurons * factor, (3, 3),
                                      strides=(2, 2), padding="same",
                                      name=f'upblock{idx}'))
            #how do I do the concatenation??
            model.add(concatenate([model.get_layer(f'upblock{idx}'),
                                   model.get_layer(f'downblock{idx}')]))

        model.add(Conv2D(1, (1,1), padding="same",
                         activation="sigmoid", name='output'))

        return model

test = configurable_model(64, 3, 16, 3)
model = test.build_model()

Я пытался перейти на функциональный API, но столкнулся с проблемой «именования» слоев и отслеживания их в циклах for. Я попробовал Конкатенацию вместо конкатенации. Я попробовал model.get_layer ('layername'). Output и model.get_layer ('layername'). Output () в операторе concatenate, et c ... ничего не работает. Приведенный выше код выдает ошибку: ValueError: слой Concatenate должен вызываться в списке как минимум из 2 входов.

1 Ответ

0 голосов
/ 04 марта 2020

Мне удалось заставить работать функциональную версию, сохранив блоки в словаре, на который я ссылаюсь позже во время конкатенации. Смотрите ниже:

class configurable_model():
    def __init__(self, csize, channels, start_neurons, depth):
        self.csize = csize
        self.channels = channels
        self.start_neurons = start_neurons
        self.depth = depth

    def _convblock(self, factor, name=None):
        block = Sequential(name=name)
        block.add(Conv2D(self.start_neurons * factor, (3, 3), padding="same"))
        block.add(BatchNormalization())
        block.add(ReLU())
        block.add(Conv2D(self.start_neurons * factor, (3, 3), padding="same"))
        block.add(BatchNormalization())
        block.add(ReLU())

        return block

    def build_model(self):
        input_layer = Input((self.csize, self.csize, self.channels), name='input')
        x = input_layer

        factor = 1
        downblocks = {}
        for idx in range(self.depth):
            x = self._convblock(factor, f'downblock{idx}')(x)
            downblocks[f'downblock{idx}'] = x
            x = MaxPooling2D((2, 2), name=f'maxpool{idx}')(x)
            factor *= 2

        x = self._convblock(factor, 'Middle')(x)

        for idx in reversed(range(self.depth)):
            factor //= 2
            x = Conv2DTranspose(self.start_neurons * factor, (3, 3),
                                strides=(2, 2), padding="same",
                                name=f'upsample{idx}')(x)
            cat = concatenate([x, downblocks[f'downblock{idx}']])
            x = self._convblock(factor, f'upblock{idx}')(cat)

        output_layer = Conv2D(1, (1, 1), padding="same",
                              activation="sigmoid", name='output')(x)

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