训练多输出Keras模型

时间:2018-10-07 18:22:58

标签: python tensorflow machine-learning keras deep-learning

我有10,000张图片,每个图片都带有20个标签。对于每个图像,标签为true或false。我正在尝试训练一种多输出模型,以便通过一个网络执行所有这20种二进制分类。

该网络是残留网络。在扁平化层之后,网络分支为20个分支。每个分支具有2个完全连接的层,每个层之后是一个退出层。最后是一个只有一个结点并最终被乙状结肠激活的致密层。

每个图像的标签和图像名称都存储在文本文件中,用于训练集和验证集。像这样: 1.jpg 1 -1 1 -1 -1 1 -1 .........

我编写了自己的生成器,但无法使它们工作。我不断收到此错误:

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.

函数说明:get_input函数读取图像并调整其大小。 get_output为每个图像准备标签。标签存储在列表中,最后返回。 preprocess_input执行预处理并将图像转换为数组。 train_generatorvalidation_generator生成大小为32的批次,将其馈送到模型。

这是我的代码:

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)

编辑: 一个快速的问题。此循环与答案中的循环有什么区别?

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

yield(x_batch, ys)

2 个答案:

答案 0 :(得分:1)

如果模型有20个输出,则必须提供20个数组的列表作为目标。一种方法是修改生成器(用于训练和验证):

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

yield(x_batch, ys)

作为旁注,您提到每个样本有20个标签,那么为什么要在输入形状中指定40个标签?

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

此外,我不知道您正在处理的特定问题,但是或者您只能有一个20号输出,而不是20个1号输出。

答案 1 :(得分:0)

您可以测试初始化​​发电机的发电机输出尺寸,并调用函数next()来检查尺寸。例如,使用train_generator:

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

然后检查x_batch和y_batch的尺寸和数据类型

我将以这种方式制造发电机:

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