Keras层用于将图像数据切割成滑动窗口

问题描述 投票:0回答:1

我有一组图像,所有图像都有不同的宽度,但固定高度设置为100像素,3个深度通道。我的任务是分类图像中的每条垂直线是否有趣。为此,我看一下其前身和后续行的10个背景。想象一下,算法从图像的左侧扫描到右侧,检测包含感兴趣点的垂直线。

我第一次尝试这样做是在将数据输入Keras模型之前使用numpy手动切出这些滑动窗口。像这样:

# Pad left and right
s = np.repeat(D[:1], 10, axis = 0)
e = np.repeat(D[-1:], 10, axis = 0)
# D now has shape (w + 20, 100, 3)
D = np.concatenate((s, D, e))
# Sliding windows creation trick from SO question
idx = np.arange(21)[None,:] + np.arange(len(D) - 20)[:,None]
windows = D[indexer]

然后,所有图像中所有垂直线的所有窗口和所有地面实况0/1值将连接成两个非常长的数组。

我原则上证实这是有效的。我将每个窗口送到Keras层,如下所示:

Conv2D(20, (5, 5), input_shape = (21, 100, 3), padding = 'valid', ...)

但是窗口导致内存使用量增加了21倍,因此这样做变得不切实际。但我认为我的场景在机器学习中是非常常见的,所以在Keras中必须有一些标准方法才能有效地完成这项工作?例如,我想向Keras提供我的原始图像数据(w,100,80),并告诉它滑动窗口的大小是什么,让它弄清楚剩下的。我看了一些示例代码,但我是一个ml noob,所以我不明白。

keras deep-learning conv-neural-network sliding-window
1个回答
1
投票

不幸的是,这不是一个简单的问题,因为它可能涉及为您的Keras模型使用可变大小的输入。虽然我认为可以通过正确使用占位符来实现这一点,但这对于初学者来说肯定是不可能的。你的另一个选择是数据生成器。与许多计算密集型任务一样,计算速度和内存要求之间经常存在折衷,使用生成器计算量更大并且完全在您的CPU上完成(没有gpu加速),但它不会增加内存。

数据生成器的意义在于,它会将操作一次一个地应用于图像以生成批处理,然后在该批处理上进行训练,然后释放内存 - 因此您最终只能在内存中保留一批数据。随时。不幸的是,如果你有一个耗时的时间,那么这会严重影响性能。

生成器将是一个python生成器(使用'yield'关键字)并且预计会生成一批数据,keras非常擅长使用任意批量大小,因此您总是可以使一个图像产生一个批次,尤其是启动。

这是fit_generator上的keras页面 - 我警告你,这开始很快就会成为很多工作,考虑购买更多内存:https://keras.io/models/model/#fit_generator

好的,我会为你做的:P

    import numpy as np
    import pandas as pd
    import keras
    from keras.models import Model, model_from_json
    from keras.layers import Dense, Concatenate, Multiply,Add, Subtract, Input, Dropout, Lambda, Conv1D, Flatten
    from tensorflow.python.client import device_lib
    # check for my gpu 
    print(device_lib.list_local_devices())


    # make some fake image data

    # 1000 random widths
    data_widths = np.floor(np.random.random(1000)*100)

    # producing 1000 random images with dimensions w x 100 x 3
    # and a vector of which vertical lines are interesting
    # I assume your data looks like this
    images = []
    interesting = []
    for w in data_widths:
        images.append(np.random.random([int(w),100,3]))
        interesting.append(np.random.random(int(w))>0.5)

    # this is a generator
    def image_generator(images, interesting):
        num = 0
        while num < len(images):
            windows = None
            truth = None

            D = images[num]
            # this should look familiar

            # Pad left and right
            s = np.repeat(D[:1], 10, axis = 0)
            e = np.repeat(D[-1:], 10, axis = 0)
            # D now has shape (w + 20, 100, 3)
            D = np.concatenate((s, D, e))
            # Sliding windows creation trick from SO question
            idx = np.arange(21)[None,:] + np.arange(len(D) - 20)[:,None]
            windows = D[idx]
            truth = np.expand_dims(1*interesting[num],axis=1)
            yield (windows, truth)
            num+=1
            # the generator MUST loop
            if num == len(images):
                num = 0

    # basic model - replace with your own
    input_layer = Input(shape = (21,100,3), name = "input_node")
    fc = Flatten()(input_layer)
    fc = Dense(100, activation='relu',name = "fc1")(fc)
    fc = Dense(50, activation='relu',name = "fc2")(fc)
    fc = Dense(10, activation='relu',name = "fc3")(fc)
    output_layer = Dense(1, activation='sigmoid',name = "output")(fc)

    model = Model(input_layer,output_layer)
    model.compile(optimizer="adam", loss='binary_crossentropy')
    model.summary()

    #and training
    training_history = model.fit_generator(image_generator(images, interesting),
                        epochs =5,
                        initial_epoch = 0,
                        steps_per_epoch=len(images),
                        verbose=1
                       )
© www.soinside.com 2019 - 2024. All rights reserved.