Я не могу заставить keras fit_generator работать со смешанным вводом (изображения и числа)

#tensorflow #keras #deep-learning

#tensorflow #keras #глубокое обучение

Вопрос:

Я ломаю голову над этим уже 3 дня.

Я в основном следовал по этой ссылке, чтобы создать свой собственный генератор данных. Но так или иначе, я делаю что-то не так, и я не могу понять, почему. Моя ошибка:

* Ошибка значения: ошибка при проверке ввода: ожидаемый dense_4_input должен иметь 2 измерения, но получен массив с формой (5, 128, 128, 3) *

Сеть для числа:

 def create_mlp(dim, regress=False):
    # define our MLP network
    model = Sequential()
    model.add(Dense(8, input_dim=dim, activation="relu"))
    model.add(Dense(4, activation="relu"))
    # check to see if the regression node should be added
    if regress:
        model.add(Dense(1, activation="linear"))
    return model
  

CNN для изображения:

 def create_cnn(inputshape, filters=(16, 32, 64), regress=True):
    chanDim = -1

    # define the model input
    inputs = Input(shape=inputshape)

    # loop over the number of filters
    for (i, f) in enumerate(filters):
        # if this is the first CONV layer then set the input
        # appropriately
        if i == 0:
            x= inputs

        # CONV => RELU => BN => POOL
        x = Conv2D(f, (3, 3), padding="same")(x)
        x = Activation("relu")(x)
        x = BatchNormalization(axis=chanDim)(x)
        x = MaxPooling2D(pool_size=(2, 2))(x)

# flatten the volume, then FC => RELU => BN => DROPOUT
x = Flatten()(x)
x = Dense(16)(x)
x = Activation("relu")(x)
x = BatchNormalization(axis=chanDim)(x)
x = Dropout(0.5)(x)

# apply another FC layer, this one to match the number of nodes
# coming out of the MLP
x = Dense(4)(x)
x = Activation("relu")(x)

# check to see if the regression node should be added
if regress:
    x = Dense(1, activation="linear")(x)

# construct the CNN
model = Model(inputs, x)

# return the CNN
return model
  

Мой собственный генератор:

 def aux_generator(img="todo", aux_input="todo", batch_size=3):
    while True:
        # Select files (paths/indices) for the batch
        # todo make this random
        img_path, gridnum, batch_output = get_batch_path()



        batch_input_img = []
        batch_input_sattelite = []

        # Read in each input, perform preprocessing and get labels
        for input_path in img_path:
            input_img = get_input_image(input_path)
            input = preprocess_input(image=input_img)
            batch_input_img  = [input]

        for GridNum in gridnum:
            # append is not good!
            batch_input_sattelite.append(get_input_sattelite(GridNum))

        # Return a tuple of (input,output) to feed the network
        batch_x1 = np.array(batch_input_img)
        batch_x2 = np.array(batch_input_sattelite)
        batch_y = np.array(batch_output)

        print("image shape : ", batch_x1.shape) #(5, 128, 128, 3)
        print("Aux shape: ", batch_x2.shape, batch_x2) #(5,)
        yield [batch_x1, batch_x2], batch_y
def get_batch_path():
    # use the df we produced in downloadMpas to know where the images are and what their NO2 concentration is
    img_info_df = pd.read_csv(r"Small/mappingTest.csv", delimiter=',', header=None,
                              names=['GridNum', 'id', 'score', 'lat', 'lon'])
    img_info_df = img_info_df[img_info_df.score != "score"]
    # the keras network needs float for the score (not object which is default when he reads in)
    img_info_df = img_info_df.astype({"GridNum": 'float64', "id": 'object', "score": 'float64'})
    return img_info_df['id'].head(n=5), img_info_df['GridNum'].head(n=5), img_info_df['score'].head(n=5)


def get_input_image(path):
    # get image
    img = image.load_img(r"Small/"   path)
    img = image.img_to_array(img)
    # get the corresponding value of the sattelite data
    return img


def get_input_sattelite(GridNum):
    sattelite_no2 = sattelite_df[sattelite_df['GridNum'] == GridNum]['sattelite'].values[0]
    print("sattelite no2:", sattelite_no2)
    return sattelite_no2


def preprocess_input(image):
    # do whatever we want to the images
    return (image)
  

Основной:

 sattelite_df = pd.read_csv(r"Small/sattelite.csv", delimiter=',', header=None,
                           names=['GridNum', 'id', 'score', 'lat', 'lon', 'sattelite'])

input_img_shape = (128, 128, 3)
input_aux_shape = (1)

img_model = create_cnn(input_img_shape)
aux_model = create_mlp(input_aux_shape, regress=False)

combinedInput = concatenate([aux_model.output, img_model.output])

# our final FC layer head will have two dense layers, the final one
# being our regression head
x = Dense(4, activation="relu")(combinedInput)
x = Dense(1, activation="linear")(x)

# our final model will accept categorical/numerical data on the MLP
# input and images on the CNN input, outputting a single value (the
# predicted price of the house)
model = Model(inputs=[aux_model.input, img_model.input], outputs=x)

opt = Adam(lr=1e-3, decay=1e-3 / 200)
model.compile(loss="mean_absolute_percentage_error", optimizer=opt)

batch_size = 2

early = EarlyStopping(monitor='val_loss', patience=3, verbose=1, restore_best_weights=True)

ImageFile.LOAD_TRUNCATED_IMAGES = True

model.fit_generator(
    aux_generator(batch_size=batch_size),
    steps_per_epoch=10 // batch_size,
    epochs=2,
    validation_data=aux_generator(batch_size=3),
    validation_steps=20 // batch_size,
    callbacks=[early])
  

Любая помощь приветствуется, поскольку я не знаю, что я делаю не так?

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

1. Вход вашей модели — [aux, img], но, похоже, ваш генератор выдает [img, aux], так что просто порядок не согласован.

2. Спасибо за ваш ответ! Это та строка, о которой вы говорите: combinedInput = объединить ([aux_model.output, img_model.output])? Я не думаю, что это имеет какое-либо значение, попробовал, хотя без какой-либо удачи …? У вас есть какие-либо другие предложения? Я могу выслать вам полный код, если это легче воспроизвести.

3. Нет, я говорю о model = Модель (входы = [aux_model.input, img_model.input], выходы = x) и выводе [batch_x1, batch_x2], batch_y, где x1, по-видимому, является изображением, а x2 — массивом.

4. Боже мой! Это действительно была моя проблема, я все время ее упускал! большое спасибо!!!