Несколько входов изображений в одну сеть ResNet, что приводит к несопоставимым входам

#python #tensorflow #keras #input #tensorflow2.0

Вопрос:

Я пытаюсь построить сеть, в которой ResNet выполняет обнаружение функций отдельно на трех входных изображениях. После обнаружения объектов три параллельные ветви объединяются с плотными слоями. При попытке ввести некоторые данные в модель возникает ошибка.

 #basis model

in1 = Input(shape=(224, 224, 3), name='base_image')
in2 = Input(shape=(224, 224, 3), name='image1')
in3 = Input(shape=(224, 224, 3), name='image2')

ResNet = ResNet50(
    include_top=False,
    weights="imagenet",
    input_shape=(224, 224, 3)
)
ResNet.trainable = False

out1 = ResNet(in1)
out2 = ResNet(in2)
out3 = ResNet(in3)

basis1 = GlobalAveragePooling2D()(out1)
basis1 = Dropout(0.7)(basis1)
basis1 = Flatten()(basis1)

basis2 = GlobalAveragePooling2D()(out2)
basis2 = Dropout(0.7)(basis2)
basis2 = Flatten()(basis2)

basis3 = GlobalAveragePooling2D()(out3)
basis3 = Dropout(0.7)(basis3)
basis3 = Flatten()(basis3)


#own model
concat = Concatenate()([basis1, basis2, basis3])
dense_1 = Dense(2048, activation='relu')(concat)
dense_2 = Dense(1024, activation='relu')(dense_1)
output = Dense(1, activation='softmax')(dense_2)

my_model = Model(inputs = [in1, in2, in3], outputs=output)
 

Вот как выглядит модель:
модель, произведенная

Массив изображений (определенно) возвращает изображение с формой (224, 224, 3)

 testX = [
    [images[0], images[1], images[2]],
    [images[3], images[4], images[5]],
    [images[6], images[7], images[8]]
]

testY = [
    [1.0],
    [0.0],
    [1.0]
]


my_model.compile(optimizer=SGD(learning_rate=0.001, momentum=0.9, nesterov=True), loss='binary_crossentropy', metrics=['binary_accuracy'])
my_model.fit(testX, y=testY, epochs = 5,  verbose=2)
 

Приводит к следующей ошибке в fit():

 ValueError: Data cardinality is ambiguous:
  x sizes: 224, 224, 224, 224, 224, 224, 224, 224, 224
  y sizes: 1, 1, 1
Make sure all arrays contain the same number of samples.
 

Похоже, что первые подмассивы игнорируются этим методом? Я застрял на этом надолго.

Комментарии:

1. у вас есть 9 изображений, но только 3 основных, это ваша проблема; если каждая строка представляет собой 3-канальное изображение, если это так, объедините их.

Ответ №1:

При использовании model.fit() , по моему опыту, всегда лучше иметь один вход, а не список. Позже вручную проиндексируйте входной тензор, чтобы получить отдельные изображения. В вашем случае форма ввода будет такой (Batch Size, 3, 224, 224, 3) .

 inputs = Input(shape=(3, 224, 224, 3), name='images')

ResNet = ResNet50(
    include_top=False,
    weights="imagenet",
    input_shape=(224, 224, 3)
)
ResNet.trainable = False

out1 = ResNet(inputs[:, 0])
out2 = ResNet(inputs[:, 1])
out3 = ResNet(inputs[:, 2])

...

my_model = Model(inputs=inputs, outputs=output)
 

Кроме того, всегда лучше создавать входные и выходные массивы с использованием numpy, а не оставлять их в виде списков python, чтобы иметь более точный контроль над конвейером:

 testX = np.stack([
    np.stack([images[0], images[1], images[2]], axis=0),
    np.stack([images[3], images[4], images[5]], axis=0),
    np.stack([images[6], images[7], images[8]], axis=0)
], axis=0) # Shape: (3, 3, 224, 224, 3)

testY = np.stack([1.0, 0.0, 1.0], axis=0)[:, None] # Shape: (3, 1)
 

Комментарии:

1. Спасибо, все получилось. Но вы уверены, что это out1 = ResNet(inputs[:, 0]) так, а не out1 = ResNet(inputs[0, :]) иначе ? Так как я хотел бы получить одно изображение на сетку, а размеры входных данных следующие: (imageNr, pixels_height, pixels_width, RGB)

2. Моя беда, в пакете есть 3 последовательности из трех изображений, и форма такая (batch, 3, height, width, RGB) . Индексация остается прежней, но я исправил комментарии к форме. Спасибо.

Ответ №2:

Я думаю, тебе нужно иметь

 ResNet1 = ResNet50(include_top=False,  weights="imagenet",  input_shape=(224, 224, 3)
ResNet2 = ResNet50(include_top=False,  weights="imagenet",  input_shape=(224, 224, 3)
ResNet3 = ResNet50(include_top=False,  weights="imagenet",  input_shape=(224, 224, 3)
out1 = ResNet1(in1)
out2 = ResNet2(in2)
out3 = ResNet3(in3)
basis1 = GlobalAveragePooling2D()(out1) # this make a vector so you don't need flatten layer                                 
basis1 = Dropout(0.7)(basis1)
basis2 = GlobalAveragePooling2D()(out2) # this make a vector so you don't need flatten layer                                 
basis2 = Dropout(0.7)(basis2)
basis3 = GlobalAveragePooling2D()(out3) # this make a vector so you don't need flatten layer                                 
basis3 = Dropout(0.7)(basis3)
concat = Concatenate()([basis1, basis2, basis3])
dense_1 = Dense(2048, activation='relu')(concat) # I would reduce nodes t0 256
# I would add a dropout layer here Dropout(.3)
dense_2 = Dense(1024, activation='relu')(dense_1)# I would reduce nodes to 32
output = Dense(1, activation='softmax')(dense_2)
 

Если вы посмотрите на график вашей модели, все входные данные входили в единую модель сети.
Кроме того, поскольку вы используете binary_crossentropy, я думаю, что ваша метка должна быть просто 1 или 0.

Комментарии:

1. Спасибо, что ответили. Хотя создать экземпляр ResNet несколько раз невозможно, потому что при компиляции модели возникает ошибка (несколько слоев имеют одно и то же имя). Поскольку имена слоев не могут быть названы, это тупик. Подход другого ответа сработал, но я включу ваш совет о слое отсева. Спасибо вам 🙂

2. О, забыл, что это было бы проблемой