#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. О, забыл, что это было бы проблемой