具有图像和标量的keras生成器

时间:2019-06-06 09:19:58

标签: tensorflow keras python-3.6

我正在尝试训练网络的某些层,这些层的输入是图像和标量。请参阅下图以更好地了解。 enter image description here

如您所见,只会训练深黄色的层。因此,我需要冻结其余部分,以供稍后使用。

此体系结构的目的是将图像(胸部X射线)映射到14种疾病。

图像存储在以下目录中: / home / akde / chexnet / CheXNet-Keras / data / images

图像名称是图像ID。

数据帧将图像(图像称为图像ID)映射到类(疾病)dataframe 如您所见,图像可以映射到多个类别(疾病)。

另一个数据框将图像(图像ID)映射到患者年龄。您可以在下面看到它。 dataframe

图像是第一输入,患者年龄是第二输入。

简而言之,对于每个图像ID,我都有一个图像和age值,它们分别位于2个单独的数据框中。

我已经可以使用以下代码进行测试(由于网络没有经过训练,因此得出了荒谬的结果,但仍然证明网络接受了输入并给出了一些结果)。

res3 = model3.predict( [test_image, a] )

其中a是标量输入,而test_image是图像输入。

我的训练数据存储在多个数据框中,在阅读了that帖子后,我推断应该使用 flow_from_dataframe

我做的第一件事是看this帖子,它解释了如何使用混合输入。这给了我一些背景知识,但是由于它不使用fit_generator(而是使用fit),因此无法解决我的问题。

然后,我读了this帖子,该帖子不使用多个输入。再次没有线索。

然后,我看到了this post,它以2张图像作为输入(而不是1张图像和一个标量)。再次没有帮助。

尽管我还没有找到解决问题的方法,但是我还是写了下面的代码来解决问题。

datagen=ImageDataGenerator(rescale=1./255., validation_split=0.25)

train_generator = datagen.flow_from_dataframe(traindf,
                                              directory="/home/akde/chexnet/CheXNet-Keras/data/images",
                                              class_mode="other",
                                              x_col="Image Index",
                                              y_col=["Atelectasis", "Cardiomegaly", "Effusion", "Infiltration", "Mass",
                                                     "Nodule", "Pneumonia", "Pneumothorax", "Consolidation", "Edema",
                                                     "Emphysema", "Fibrosis", "Pleural_Thickening", "Hernia"],
                                              color_mode="rgb",
                                              batch_size=32,
                                              target_size=(224, 224)
                                                     )

STEP_SIZE_TRAIN=train_generator.n//train_generator.batch_size

model3.compile(optimizers.rmsprop(lr=0.0001, decay=1e-6),loss="categorical_crossentropy",metrics=["accuracy"])

model3.fit_generator(generator=train_generator,
                    steps_per_epoch=STEP_SIZE_TRAIN,
                    epochs=10
)

我知道这段代码离解决方案还很远。

那么我该如何创建一个使用2个数据帧的生成器,这两个数据帧已在前面进行了解释(一个将图像映射到疾病,另一个将图像ID映射到年龄)。

换句话说,考虑到图像和标量值均在数据帧中表示的事实,编写以图像和标量值作为输入的生成器的方式是什么。如何编写下面以粗体显示的生成器。

model3.fit_generator(**generator=train_generator**,
                    steps_per_epoch=STEP_SIZE_TRAIN,
                    epochs=10
)

1 个答案:

答案 0 :(得分:1)

出于您的目的,您需要创建一个自定义生成器。

我建议您深入了解此链接:
https://blog.ml6.eu/training-and-serving-ml-models-with-tf-keras-3d29b41e066c

尤其是这段代码:

import ast
import numpy as np
import math
import os
import random
from tensorflow.keras.preprocessing.image import img_to_array as img_to_array
from tensorflow.keras.preprocessing.image import load_img as load_img

def load_image(image_path, size):
    # data augmentation logic such as random rotations can be added here
    return img_to_array(load_img(image_path, target_size=(size, size))) / 255.

class KagglePlanetSequence(tf.keras.utils.Sequence):
    """
    Custom Sequence object to train a model on out-of-memory datasets. 
    """

    def __init__(self, df_path, data_path, im_size, batch_size, mode='train'):
        """
        df_path: path to a .csv file that contains columns with image names and labels
        data_path: path that contains the training images
        im_size: image size
        mode: when in training mode, data will be shuffled between epochs
        """
        self.df = pd.read_csv(df_path)
        self.im_size = im_size
        self.batch_size = batch_size
        self.mode = mode

        # Take labels and a list of image locations in memory
        self.wlabels = self.df['weather_labels'].apply(lambda x: ast.literal_eval(x)).tolist()
        self.glabels = self.df['ground_labels'].apply(lambda x: ast.literal_eval(x)).tolist()
        self.image_list = self.df['image_name'].apply(lambda x: os.path.join(data_path, x + '.jpg')).tolist()

    def __len__(self):
        return int(math.ceil(len(self.df) / float(self.batch_size)))

    def on_epoch_end(self):
        # Shuffles indexes after each epoch
        self.indexes = range(len(self.image_list))
        if self.mode == 'train':
            self.indexes = random.sample(self.indexes, k=len(self.indexes))

    def get_batch_labels(self, idx): 
        # Fetch a batch of labels
        return [self.wlabels[idx * self.batch_size: (idx + 1) * self.batch_size],
                self.glabels[idx * self.batch_size: (idx + 1) * self.batch_size]]

    def get_batch_features(self, idx):
        # Fetch a batch of images
        batch_images = self.image_list[idx * self.batch_size: (1 + idx) * self.batch_size]
        return np.array([load_image(im, self.im_size) for im in batch_images])

    def __getitem__(self, idx):
        batch_x = self.get_batch_features(idx)
        batch_y = self.get_batch_labels(idx)
return batch_x, batch_y

希望这将有助于找到您的解决方案!