简体   繁体   English

训练多输出Keras模型

[英]training a multi-output keras model

I have 10,000 images, each of which are labeled with 20 tags. 我有10,000张图片,每张图片都标有20个标签。 For each image, the tag is either true or false. 对于每个图像,标签为true或false。 I'm trying to train a multi-output model to perform all these 20 binary classifications with one network. 我正在尝试训练一种多输出模型,以便通过一个网络执行所有这20种二进制分类。

The network is a Residual Network. 该网络是残留网络。 After the flatten layer, the network branches out into 20 branches. 在扁平化层之后,网络分支为20个分支。 Each branch has 2 fully connected layers, each of which are followed by a drop out layer. 每个分支具有2个完全连接的层,每个层之后是一个退出层。 And finally a dense layer with one node and sigmoid activation in the end. 最后是一个只有一个节点并最终被乙状结肠激活的致密层。

The labels for each image and the image name are stored in a text file, for both train and validation set. 每个图像的标签和图像名称都存储在文本文件中,用于训练集和验证集。 Like this: 1.jpg 1 -1 1 -1 -1 1 -1......... 像这样:1.jpg 1 -1 1 -1 -1 1 -1 ......

I wrote my own generator, but I can't get them to work. 我编写了自己的生成器,但无法使它们工作。 I keep getting this 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.

Function explanations: get_input function reads an image and resizes it. 函数说明: get_input函数读取图像并调整其大小。 get_output prepares the labels for each image. get_output为每个图像准备标签。 The labels are stored in a list and returned in the end. 标签存储在列表中,最后返回。 preprocess_input performs preprocessing and converting images into arrays. preprocess_input执行预处理并将图像转换为数组。 train_generator and validation_generator generate batches with size 32 to be fed to the model. train_generatorvalidation_generator生成大小为32的批次,以将其馈送到模型。

Here's my code: 这是我的代码:

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)

Edit: One quick question. 编辑:一个简单的问题。 What's the difference between this loop and the one in your answer: 此循环与答案中的循环有什么区别:

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

yield(x_batch, ys)

If your model has 20 outputs then you must provide a list of 20 arrays as target. 如果模型有20个输出,则必须提供20个数组的列表作为目标。 One way of doing this is to modify the generator (for both training and validation): 一种方法是修改生成器(用于训练和验证):

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

yield(x_batch, ys)

As a side note, you mentioned that you have 20 tags per sample then why have you specified 40 in the input shape? 作为附带说明,您提到每个样本有20个标签,然后为什么在输入形状中指定40个标签?

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

Further, I don't know about the specific problem you are working on but alternatively you could only have one output of size 20 instead of 20 outputs with size one. 此外,我不知道您正在处理的具体问题,但是或者,您只能有一个20号输出,而不是20个1号输出。

You can test the generator output dimensions initializing the generator and call the function next() to check the dimensions. 您可以测试初始化​​发电机的发电机输出尺寸,并调用函数next()来检查尺寸。 For example with the train_generator: 例如,使用train_generator:

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

Then check x_batch and y_batch dimensions and datatype 然后检查x_batch和y_batch的尺寸和数据类型

I would make the generator in this way: 我将以这种方式生成发电机:

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))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM