提问者:小点点

多输出keras模型的训练


我有10000张图片,每张图片都贴有20个标签。对于每个图像,标签要么为真,要么为假。我试图训练一个多输出模型,用一个网络执行所有这20个二进制分类。

网络是一个剩余网络。在平坦层之后,网络分支为20个分支。每个分支有2个完全连接的层,每个层后面都有一个退出层。最后是一个致密层,有一个节点,最后是乙状结肠激活。

每个图像的标签和图像名称存储在文本文件中,用于序列和验证集。像这样:1。jpg 1-11-1-11-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个答案

匿名用户

如果您的模型有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的输出。

匿名用户

您可以在初始化生成器时测试生成器输出维度,并调用函数next()检查维度。例如,列车发电机:

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