entrenando un modelo keras multi-salida

Tengo 10.000 imágenes, cada una de las cuales está etiquetada con 20 tags. Para cada imagen, la etiqueta es verdadera o falsa. Estoy tratando de entrenar un modelo de múltiples salidas para realizar todas estas 20 clasificaciones binarias con una red.

La red es una red residual. Después de la capa plana, la red se ramifica en 20 twigs. Cada twig tiene 2 capas totalmente conectadas, cada una de las cuales está seguida por una capa que se puede quitar. Y finalmente una capa densa con un nodo y activación sigmoide al final.

Las tags para cada imagen y el nombre de la imagen se almacenan en un archivo de texto, tanto para el tren como para el conjunto de validación. Así: 1.jpg 1 -1 1 -1 -1 1 -1 ………

Escribí mi propio generador, pero no puedo hacer que funcionen. Sigo recibiendo este error:

Error when checking model target: the list of Numpy arrays that you are passing to your model is not the size the model expected. Expected to see 20 array(s), but instead got the following list of 1 arrays. 

Explicaciones de la función: la función get_input lee una imagen y la cambia de tamaño. get_output prepara las tags para cada imagen. Las tags se almacenan en una lista y se devuelven al final. preprocess_input realiza el preprocesamiento y la conversión de imágenes en arreglos. train_generator y validation_generator generan lotes con el tamaño 32 para alimentar al modelo.

Aquí está mi código:

 def get_input(img_name): path = os.path.join("images", img_name) img = image.load_img(path, target_size=(224, 224)) return img def get_output(img_name, file_path): data = pd.read_csv(file_path, delim_whitespace=True, header=None) img_id = img_name.split(".")[0] img_id = img_id.lstrip("0") img_id = int(img_id) labels = data.loc[img_id - 1].values labels = labels[1:] labels = list(labels) label_arrays = [] for i in range(20): val = np.zeros((1)) val[0] = labels[i] label_arrays.append(val) return label_arrays def preprocess_input(img_name): img = get_input(img_name) x = image.img_to_array(img) x = np.expand_dims(x, axis=0) return x def train_generator(batch_size): file_path = "train.txt" data = pd.read_csv(file_path, delim_whitespace=True, header=None) while True: for i in range(math.floor(8000/batch_size)): x_batch = np.zeros(shape=(32, 224, 224, 3)) y_batch = np.zeros(shape=(32, 20)) for j in range(batch_size): img_name = data.loc[i * batch_size + j].values img_name = img_name[0] x = preprocess_input(img_name) y = get_output(img_name, file_path) x_batch[j, :, :, :] = x y_batch[j] = y yield(x_batch, y_batch) def val_generator(batch_size): file_path = "val.txt" data = pd.read_csv(file_path, delim_whitespace=True, header=None) while True: for i in range(math.floor(2000/batch_size)): x_batch = np.zeros(shape=(32, 224, 224, 3)) y_batch = np.zeros(shape=(32, 20)) for j in range(batch_size): img_name = data.loc[i * batch_size + j].values img_name = img_name[0] x = preprocess_input(img_name) y = get_output(img_name, file_path) x_batch[j, :, :, :] = x y_batch[j] = y yield(x_batch, y_batch) 

Edición: Una pregunta rápida. ¿Cuál es la diferencia entre este bucle y el de tu respuesta?

 ys = [] for i in range(batch_size): ys.append(y_batch[i, :]) yield(x_batch, ys) 

Si su modelo tiene 20 salidas, debe proporcionar una lista de 20 matrices como objective. Una forma de hacer esto es modificar el generador (para capacitación y validación):

 ys = [] for i in range(20): ys.append(y_batch[:,i]) yield(x_batch, ys) 

Como nota al margen, mencionó que tiene 20 tags por muestra, entonces ¿por qué ha especificado 40 en la forma de entrada?

 y_batch = np.zeros(shape=(32, 40)) 

Además, no conozco el problema específico en el que está trabajando pero, alternativamente, solo podría tener una salida de tamaño 20 en lugar de 20 salidas con tamaño uno.

Puede probar las dimensiones de salida del generador inicializando el generador y llamar a la función next () para verificar las dimensiones. Por ejemplo con el train_generator:

 train_gen = train_generator(batch_size) x_batch, y_batch = next(train_gen) 

Luego verifique las dimensiones x_batch y y_batch y el tipo de datos

Yo haría el generador de esta manera:

 def train_generator(batch_size): file_path = "train.txt" data = pd.read_csv(file_path, delim_whitespace=True, header=None) # Initialize empty list x_batch = [] y_batch = [] while True: for i in range(math.floor(8000/batch_size)): for j in range(batch_size): img_name = data.loc[i * batch_size + j].values img_name = img_name[0] x = preprocess_input(img_name) y = get_output(img_name, file_path) x_batch.append(x) y_batch.append(y) yield(np.array(x_batch), np.array(y_batch))