当前位置: 首页 > 知识库问答 >
问题:

自定义数据生成器

仲孙宇定
2023-03-14

我有一个自定义文件,其中包含我所有图像的路径及其标签,我在一个数据框中加载使用:

MyIndex=pd.read_table('./MySet.txt')

MyIndex有两列感兴趣的ImagePath和ClassName

接下来我做一些训练测试拆分和编码输出标签为:

images=[]
for index, row in MyIndex.iterrows():
    img_path=basePath+row['ImageName']
    img = image.load_img(img_path, target_size=(299, 299))
    img_path=None
    img_data = image.img_to_array(img)
    img=None
    images.append(img_data)
    img_data=None


images[0].shape

Classes=Sample['ClassName']
OutputClasses=Classes.unique().tolist()

labels=Sample['ClassName']
images=np.array(images, dtype="float") / 255.0
(trainX, testX, trainY, testY) = train_test_split(images,labels, test_size=0.10, random_state=42)
trainX, valX, trainY, valY = train_test_split(trainX, trainY, test_size=0.10, random_state=41)

images=None
labels=None

encoder = LabelEncoder()
encoder=encoder.fit(OutputClasses)
encoded_Y = encoder.transform(trainY)
# convert integers to dummy variables (i.e. one hot encoded)
trainY = to_categorical(encoded_Y, num_classes=len(OutputClasses))

encoded_Y = encoder.transform(valY)
# convert integers to dummy variables (i.e. one hot encoded)
valY = to_categorical(encoded_Y, num_classes=len(OutputClasses))

encoded_Y = encoder.transform(testY)
# convert integers to dummy variables (i.e. one hot encoded)
testY = to_categorical(encoded_Y, num_classes=len(OutputClasses))

datagen=ImageDataGenerator(rotation_range=90,horizontal_flip=True,vertical_flip=True,width_shift_range=0.25,height_shift_range=0.25)
datagen.fit(trainX,augment=True)

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])


batch_size=128
model.fit_generator(datagen.flow(trainX,trainY,batch_size=batch_size), epochs=500, 
                    steps_per_epoch=trainX.shape[0]//batch_size,validation_data=(valX,valY))

我面临的问题是一次性加载的数据太大,无法放入当前的机器内存,因此我无法处理完整的数据集。

我曾尝试使用datagenerator,但不想遵循它遵循的目录约定,也无法消除增强部分。

问题是,是否有一种方法可以从磁盘加载批处理,以确保满足两个规定的条件。

共有3个答案

锺离德运
2023-03-14

如果您想从磁盘加载,使用您使用的ImageDataGenerator很方便。

有两种方法可以做到这一点。通过使用flow\u from\u directory说明数据目录。或者,您可以将flow\u from\u数据帧与熊猫数据帧一起使用

如果希望有路径列表,则不应使用生成成批图像的自定义生成器。这是一个存根:

def load_image_from_path(path):
    "Loading and preprocessing"
    ...

def my_generator():
    length = df.shape[0]
    for i in range(0, length, batch_size)
        batch = df.loc[i:min(i+batch_size, length-1)]
        x, y = map(load_image_from_path, batch['ImageName']), batch['ClassName']
        yield x, y

注意:在fit_generator有一个额外的生成器命名为validation_data,你猜对了-验证。一种选择是传递给生成器选择的索引,以便分割训练和测试(假设数据被洗牌,如果不检查这个)。

傅毅然
2023-03-14

我认为最简单的方法是每个生成器加载一部分图像,并重复调用.fit_generator()

以前的版本使用了random.random(),但是我们也可以像这个修订版一样使用开始索引和页面大小来永远循环图像列表。

import itertools


def load_images(start_index, page_size):
    images = []
    for index in range(page_size):
        # Generate index using modulo to loop over the list forever
        index = (start_index + index) % len(rows)
        row = MyIndex[index]
        img_path = basePath + row["ImageName"]
        img = image.load_img(img_path, target_size=(299, 299))
        img_data = image.img_to_array(img)
        images.append(img_data)
    return images


def generate_datagen(batch_size, start_index, page_size):
    images = load_images(start_index, page_size)

    # ... everything else you need to get from images to trainX and trainY, etc. here ...

    datagen = ImageDataGenerator(
        rotation_range=90,
        horizontal_flip=True,
        vertical_flip=True,
        width_shift_range=0.25,
        height_shift_range=0.25,
    )
    datagen.fit(trainX, augment=True)
    return (
        trainX,
        trainY,
        valX,
        valY,
        datagen.flow(trainX, trainY, batch_size=batch_size),
    )


model.compile(
    loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"]
)

page_size = (
    500
)  # load 500 images at a time; change this as suitable for your memory condition

for page in itertools.count():  # Count from zero to forever.
    batch_size = 128
    trainX, trainY, valX, valY, generator = generate_datagen(
        128, page * page_size, page_size
    )
    model.fit_generator(
        generator,
        epochs=5,
        steps_per_epoch=trainX.shape[0] // batch_size,
        validation_data=(valX, valY),
    )
    # TODO: add a `break` clause with a suitable condition

郎意
2023-03-14

我想你应该看看这篇文章

您正在寻找的是Keras flow_from_数据框,它允许您通过在数据框中提供文件名及其标签,并提供包含所有图像的顶级目录路径,从磁盘加载批处理。

在代码中制作一些midifications,并从共享链接中借用一些midifications:

MyIndex=pd.read_table('./MySet.txt')

Classes=MyIndex['ClassName']
OutputClasses=Classes.unique().tolist()

trainDf=MyIndex[['ImageName','ClassName']]
train, test = train_test_split(trainDf, test_size=0.10, random_state=1)


#creating a data generator to load the files on runtime
traindatagen=ImageDataGenerator(rotation_range=90,horizontal_flip=True,vertical_flip=True,width_shift_range=0.25,height_shift_range=0.25,
    validation_split=0.1)
train_generator=traindatagen.flow_from_dataframe(
    dataframe=train,
    directory=basePath,#the directory containing all your images
    x_col='ImageName',
    y_col='ClassName',
    class_mode='categorical',
    target_size=(299, 299),
    batch_size=batch_size,
    subset='training'
)
#Also a generator for the validation data
val_generator=traindatagen.flow_from_dataframe(
    dataframe=train,
    directory=basePath,#the directory containing all your images
    x_col='ImageName',
    y_col='ClassName',
    class_mode='categorical',
    target_size=(299, 299),
    batch_size=batch_size,
    subset='validation'
)


STEP_SIZE_TRAIN=train_generator.n//train_generator.batch_size
STEP_SIZE_VALID=val_generator.n//val_generator.batch_size
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

model.fit_generator(generator=train_generator, steps_per_epoch=STEP_SIZE_TRAIN,
                    validation_data=val_generator,
                    validation_steps=STEP_SIZE_VALID,
                    epochs=500)

另外请注意,现在您不需要像在原始代码中那样对标签进行编码,并且还省略了图像加载代码。

我没有尝试过这段代码本身,所以请尝试修复您可能遇到的任何错误,因为主要的重点是向您提供基本的想法。

作为对你评论的回应:如果你有不同目录中的所有文件,那么一个解决方案是让你的ImagesName存储相对路径,包括路径中的中间目录。/Dir/File.jpg',然后将所有目录移动到一个文件夹,并使用一个作为基本路径,其他一切保持不变。另外,查看加载文件的代码段,看起来您已经在ImageName列中存储了文件路径,因此建议的方法应该适用于您。

images=[]
for index, row in MyIndex.iterrows():
    img_path=basePath+row['ImageName']
    img = image.load_img(img_path, target_size=(299, 299))
    img_path=None
    img_data = image.img_to_array(img)
    img=None
    images.append(img_data)
    img_data=None

如果仍然存在一些含糊之处,请随时再次询问。

 类似资料:
  • 我使用的是SpringBoot(1.4)、SpringData和jpa。使用我的表/实体之一的ID列(crudepository),我想生成自定义字符串。从一些特定的字符串加上创建数据和时间开始,以db中的下一个值结束。所以这里我不能使用,我需要一些本地查询,比如“selectnextvalue” 有没有更好的方法可以做到这一点。

  • 我正在使用 Scala,并希望构建自己的数据帧函数。例如,我想将一列视为数组,循环访问每个元素并进行计算。 首先,我尝试实现自己的getMax方法。因此列x的值为[3,8,2,5,9],该方法的预期输出为9。 下面是它在Scala中的样子 这是我目前所知道的,并得到这个错误 我不知道如何迭代该列。 } 一旦我能够实现自己的方法,我将创建一个列函数 然后我希望能够在SQL的陈述中使用它 给定输入列[

  • 是否有方法重写build方法返回SampleClass以避免执行build.build?

  • 当我试图使用数据绑定和绑定布局中的自定义XML标记运行项目时,遇到以下描述的构建错误:

  • 有没有办法为自定义生成的代码? 考虑以下简单类: 我希望Lombok为生成Setter,就像我在上面的示例中实现的那样。这应该只在用注释的类和作为的属性上完成。其他属性的Setter,在本例中应该像往常一样生成。 是否有办法根据这些标准定制Setter代码的生成?

  • 我想训练自己的模型,以便在中使用。 搜索了很多,最终找到了一个训练模型的工作代码,但并不准确。文件还说,你需要15000个句子才能有一个准确的模型。 所以你需要有15000个句子,每个句子都有一个好的上下文和名字