2D сверточные нейронные сети с изображениями переменного размера

Я реализовал сверточный автокодировщик с Keras, используя бэкэнд Theano. Я меняю свой подход, пытаясь работать с изображениями разных размеров. Пока я использую функцию numpy stack для создания набора данных (изображения одинакового размера), я золотой. Однако для изображений разного размера мы не можем использовать stack, а fit ожидает массив numpy. Поэтому я перешел на fit_generator, чтобы избежать проверки размера. Проблема в том, что последний слой ожидает 16 в качестве последнего измерения на входе, и я не могу понять, почему он получает размеры исходного изображения.

Взгляните на приведенный ниже код и вывод ошибок.


import numpy as np
import keras
from keras.models import Sequential, Model
from keras.layers import Input, Conv2D, MaxPooling2D, UpSampling2D

AE_EPOCHS = 10
VERB = 1
batchsz = 16
outfun = 'sigmoid'

data = []
dimensions = [(10, 15), (12, 15), (7,15), (20,15), (25,15)]

for d in dimensions:
    dd = np.random.rand(*d)
    dd = dd.reshape((1,)+dd.shape)
    data.append(dd)

input_img = Input(shape=(1, None, 15))
filtersz = 3
pad_it = 'same'
size1 = 16
size2 = 8
x = Conv2D(size1, (filtersz, filtersz), activation='relu', padding=pad_it)(input_img)
x = MaxPooling2D((2, 2), padding=pad_it)(x)
x = Conv2D(size2, (filtersz, filtersz), activation='relu', padding=pad_it)(x)
x = MaxPooling2D((2, 2), padding=pad_it)(x)
x = Conv2D(size2, (filtersz, filtersz), activation='relu', padding=pad_it)(x)
encoded = MaxPooling2D((2, 2), padding=pad_it)(x)

x = Conv2D(size2, (filtersz, filtersz), activation='relu', padding=pad_it)(encoded)
x = UpSampling2D((2, 2), data_format="channels_first")(x)
x = Conv2D(size2, (filtersz, filtersz), activation='relu', padding=pad_it)(x)
x = UpSampling2D((2, 2), data_format="channels_first")(x)
x = Conv2D(size1, (filtersz, filtersz), activation='relu', padding=pad_it)(x)
x = UpSampling2D((2, 2), data_format="channels_first")(x)
decoded = Conv2D(1, (filtersz, filtersz), activation=outfun, padding=pad_it)(x)

autoencoder = Model(input_img, decoded)
autoencoder.compile(optimizer='adadelta', loss= 'binary_crossentropy')

x_train = data[1:]
x_test= data[0].reshape((1,)+ data[0].shape)

def mygen(xx, *args, **kwargs):
    for i in xx:
        yield (i,i)

thegen = mygen(x_train)
#If I use this generator somehow None is returned so it is not used
thegenval = mygen(np.array([x_test]))

hist = autoencoder.fit_generator(thegen,
                epochs=AE_EPOCHS,
                steps_per_epoch=4,
                verbose=VERB,
                validation_data=(x_test, x_test),
                validation_steps=1
                )

Отслеживание (последний вызов последний):

Файл "stacko.py", строка 107, в validation_steps = 1

Файл "/usr/local/lib/python3.5/dist-packages/keras/legacy/interfaces.py", строка 88, в оболочке return func (* args, ** kwargs)

Файл "/usr/local/lib/python3.5/dist-packages/keras/engine/training.py", строка 1847, в fit_generator val_x, val_y, val_sample_weight)

Файл "/usr/local/lib/python3.5/dist-packages/keras/engine/training.py", строка 1315, в _standardize_user_data exception_prefix = 'target')

Файл "/usr/local/lib/python3.5/dist-packages/keras/engine/training.py", строка 139, в строке _standardize_input_data (array.shape))

ValueError: Ошибка при проверке цели: ожидалось, что conv2d_7 будет иметь форму (None, 1, None, 16), но получил массив с формой (1, 1, 10, 15)


person rll    schedule 11.07.2017    source источник


Ответы (1)


В приведенном выше коде есть две проблемы: во-первых, размер оси изображений должен быть кратным наименьшему количеству фильтров на слой (в данном случае 8); во-вторых, генераторы для fit_generator должны возвращать пакеты (массивы 4D numpy).

Генератор реализован с помощью itertools.cycle и преобразует фигуры в один образец пакета (при работе с несколькими изображениями общих размеров можно иметь пакеты переменного размера для каждой группы измерений). Рабочий пример ниже.


import numpy as np
from itertools import cycle

import keras
from keras.models import Sequential, Model
from keras.layers import Input, Dense, Conv2D, MaxPooling2D, UpSampling2D

AE_EPOCHS = 10
VERB = 1
outfun = 'sigmoid'

data = []
dimensions = [(16, 32), (24, 32), (8,32), (32,32)]
for d in dimensions:
    dd = np.random.rand(*d)
    dd = dd.reshape((1,)+dd.shape)
    data.append(dd)

input_img = Input(shape=(1, None, 32))
filtersz = 3
pad_it = 'same'
size1 = 16
size2 = 8
x = Conv2D(size1, (filtersz, filtersz), activation='relu', padding=pad_it)(input_img)
x = MaxPooling2D((2, 2), padding=pad_it)(x)
x = Conv2D(size2, (filtersz, filtersz), activation='relu', padding=pad_it)(x)
x = MaxPooling2D((2, 2), padding=pad_it)(x)
x = Conv2D(size2, (filtersz, filtersz), activation='relu', padding=pad_it)(x)
encoded = MaxPooling2D((2, 2), padding=pad_it)(x)

x = Conv2D(size2, (filtersz, filtersz), activation='relu', padding=pad_it)(encoded)
x = UpSampling2D((2, 2), data_format="channels_first")(x)
x = Conv2D(size2, (filtersz, filtersz), activation='relu', padding=pad_it)(x)
x = UpSampling2D((2, 2), data_format="channels_first")(x)
x = Conv2D(size1, (filtersz, filtersz), activation='relu', padding=pad_it)(x)
x = UpSampling2D((2, 2), data_format="channels_first")(x)
decoded = Conv2D(1, (filtersz, filtersz), activation=outfun, padding=pad_it)(x)

autoencoder = Model(input_img, decoded)
autoencoder.compile(optimizer='adadelta', loss= 'binary_crossentropy')


x_train = data[1:]
x_test= [data[0]]

def mygen(xx, *args, **kwargs):
    for i in cycle(xx):
        ii = i.reshape((1,)+i.shape)
        yield ii,ii

thegen = mygen(x_train)
thegenval = mygen(x_test)

hist = autoencoder.fit_generator(
                thegen,
                epochs=AE_EPOCHS,
                steps_per_epoch=3,
                verbose=VERB,
                validation_data=thegenval,
                validation_steps=1
                )

person rll    schedule 15.07.2017