Как работать с изображением переменного размера в CNN, используя Keras?
В настоящее время я работаю над CNN над изображением для извлечения объектов с использованием керас. Все изображения в виде 276 строк, x столбцов и 3 цветовых измерений (RGB). Количество столбцов равно длине вектора выходного объекта, который он должен сгенерировать.
Представление входных данных - редактировать:
Входные данные, данные для изображения, состоят из срезов изображения по столбцам. это означает, что фактический входной сигнал для изображения равен (276,3), а количество столбцов равно длине объекта, которую он должен сгенерировать.
Моя начальная модель такова:
print "Model Definition"
model = Sequential()
model.add(Convolution2D(64,row,1,input_shape=(row,None,3)))
print model.output_shape
model.add(MaxPooling2D(pool_size=(1,64)))
print model.output_shape
model.add(Dense(1,activation='relu'))
Мои отпечатки между печатями output.shape
и я, кажется, немного смущен на выходе.
Model Definition
(None, 1, None, 64)
(None, 1, None, 64)
Как получилось, что 3D-данные стали 4d? И так будет после слоя maxpoolling2d?
Мой плотный слой / полностью связанный слой вызывает у меня некоторые проблемы с размерами здесь:
Traceback (most recent call last):
File "keras_convolutional_feature_extraction.py", line 466, in <module>
model(0,train_input_data,output_data_train,test_input_data,output_data_test)
File "keras_convolutional_feature_extraction.py", line 440, in model
model.add(Dense(1,activation='relu'))
File "/usr/local/lib/python2.7/dist-packages/keras/models.py", line 324, in add
output_tensor = layer(self.outputs[0])
File "/usr/local/lib/python2.7/dist-packages/keras/engine/topology.py", line 474, in __call__
self.assert_input_compatibility(x)
File "/usr/local/lib/python2.7/dist-packages/keras/engine/topology.py", line 415, in assert_input_compatibility
str(K.ndim(x)))
Exception: Input 0 is incompatible with layer dense_1: expected ndim=2, found ndim=4
Так почему же я не могу получить данные до одного значения из трехмерного изображения.?
1 ответ
Вы работаете на 276 x None x 3
изображение с использованием 64 сверточных фильтров, каждый размером 276 x 1
(при условии, rows = 276
). Один сверточный фильтр выведет матрицу размера 1 x None
, Прочтите это подробно, если вы не знаете, как работают сверточные фильтры. Таким образом, для 64 фильтров (в бэкэнде Theano) вы получите матрицу размера 64 x 1 x None
, В бэкенде Tensorflow, думаю, будет 1 x None x 64
, Теперь первое измерение для Keras-Theano - это всегда образцы. Итак, ваша конечная форма будет None x 64 x 1 x None
, Для Tensorflow это будет None x 1 x None x 64
, Прочитайте это для получения дополнительной информации о различных бэкэндах в Keras.
Чтобы убрать ошибку плотного слоя, я думаю, вам нужно сгладить вывод, введя следующую строку перед добавлением Dense
слой.
model.add(Flatten())
Тем не менее, я не очень понимаю использование плотного слоя здесь. Как вы должны знать, плотный слой принимает только фиксированный размер ввода и обеспечивает вывод фиксированного размера. Так что ваши None
измерение будет в основном ограничено одним значением, если вы хотите, чтобы ваша сеть работала без ошибок. Если вы хотите иметь вывод формы 1 x None
тогда не стоит включать плотные слои и использовать average
объединение в конце, чтобы свернуть ответ на 1 x 1 x None
выход.
Изменить: если у вас есть изображение размера 276 x n x 3
где он имеет переменное количество столбцов и если вы хотите, чтобы вывод размера 1 x n
Тогда вы можете сделать следующее:
model = Sequential()
model.add(Convolution2D(64,row,1,input_shape=(row,None,3)))
model.add(Convolution2D(1,1,1))
print model.output_shape # this should print `None x 1 x None x 1`
model.add(flatten())
Теперь я сомневаюсь, что эта сеть будет работать очень хорошо, поскольку в ней всего один слой из 64 фильтров. Чувствительное поле также слишком велико (например, 276 - высота изображения). Вы можете сделать две вещи:
- Уменьшите рецептивное поле, то есть вместо того, чтобы сворачивать весь столбец изображения одновременно, вы можете свертывать только 3 пикселя столбца за раз.
- Есть несколько сверточных слоев.
В дальнейшем я буду считать, что высота изображения равна 50. Затем вы можете написать сеть следующим образом:
model = Sequential()
model.add(Convolution2D(32,3,1,activation='relu',
init='he_normal',input_shape=(row,None,3))) # row = 50
model.add(Convolution2D(32,3,1,activation='relu',init='he_normal'))
model.add(MaxPooling2D(pool_size=(2,1), strides=(2,1), name='pool1'))
model.add(Convolution2D(64,3,1,activation='relu',init='he_normal'))
model.add(Convolution2D(64,3,1,activation='relu',init='he_normal'))
model.add(MaxPooling2D(pool_size=(2,1), strides=(2,1), name='pool2'))
model.add(Convolution2D(128,3,1,activation='relu',init='he_normal'))
model.add(Convolution2D(128,3,1,activation='relu',init='he_normal'))
model.add(Convolution2D(128,3,1,activation='relu',init='he_normal'))
model.add(MaxPooling2D(pool_size=(2,1), strides=(2,1), name='pool3'))
model.add(Convolution2D(1,1,1), name='squash_channels')
print model.output_shape # this should print `None x 1 x None x 1`
model.add(flatten(), name='flatten_input')
Вы должны убедиться, что все эти слои сверточного и максимального пула уменьшают входную высоту с 50 до 1 после последнего максимального пула.
Как работать с изображениями переменного размера
Один из способов - сначала определить общий размер для вашего набора данных, например 224. Затем построить сеть для 224 x n
изображение, как показано выше (может быть, немного глубже). Теперь позвольте нам сказать, что вы получите изображение с другим размером, скажем, p x n'
где p > 224
а также n' != n
, Вы можете взять центральную часть изображения размером 224 x n'
и передать его через изображение. У вас есть свой вектор признаков.
Если вы считаете, что большая часть информации не сконцентрирована вокруг центра, вы можете взять несколько культур, а затем усреднить (или макс-пул) полученный вектор нескольких признаков. Используя эти методы, я думаю, вы сможете обрабатывать вводы переменного размера.
Редактировать:
Смотрите CNN, который я определил, используя 3 x 3
извилины. Предположим, что вход имеет размер 50 x n x 3
, Допустим, мы передаем ввод размера p x q x r
через сверточный слой, который имеет f
фильтры каждого размера 3 x 3
, шаг 1. Вход не имеет отступов. Тогда выход сверточного слоя будет иметь размер (p-2) x (q-2) x f
т.е. высота и ширина на выходе будут вдвое меньше, чем на входе. Наши объединяющие слои имеют размер (2,1)
и шагать (2,1)
, Они будут вдвое уменьшать входные данные в направлении y (или уменьшать вдвое высоту изображения). Имея это в виду, следующее легко вывести (обратите внимание на названия слоев, которые я дал в моем CNN, они указаны ниже).
Вход CNN: None x 50 x n x 3
Ввод pool1
слой: None x 46 x n x 32
Выход из pool1
слой: None x 23 x n x 32
Ввод pool2
слой: None x 19 x n x 64
Выход из pool2
слой: None x 9 x n x 64
(Я думаю, что объединение Keras занимает слово, т.е. слово (19/2) = 9)
Ввод pool3
слой: None x 3 x n x 128
Выход из pool3
слой: None x 1 x n x 128
Ввод squash_channels
слой: None x 1 x n x 128
Выход из squash_channels
слой: None x 1 x n x 1
Ввод flatten_input
слой: None x 1 x n x 1
Выход из flatten_input
слой: None x n
Я думаю, что это то, что вы хотели. Я надеюсь, теперь все ясно.