【问题标题】:How to get Data Generator more efficient?如何让数据生成器更高效?
【发布时间】:2020-09-17 07:35:25
【问题描述】:

为了训练神经网络,我修改了在 YouTube 上找到的代码。它看起来如下:

def data_generator(samples, batch_size, shuffle_data = True, resize=224):
  num_samples = len(samples)
  while True:
    random.shuffle(samples)

    for offset in range(0, num_samples, batch_size):
      batch_samples = samples[offset: offset + batch_size]

      X_train = []
      y_train = []

      for batch_sample in batch_samples:
        img_name = batch_sample[0]
        label = batch_sample[1]
        img = cv2.imread(os.path.join(root_dir, img_name))

        #img, label = preprocessing(img, label, new_height=224, new_width=224, num_classes=37)
        img = preprocessing(img, new_height=224, new_width=224)
        label = my_onehot_encoded(label)

        X_train.append(img)
        y_train.append(label)

      X_train = np.array(X_train)
      y_train = np.array(y_train)

      yield X_train, y_train

现在,我尝试使用此代码训练神经网络,训练样本大小为 105.000(图像文件包含 37 个可能性中的 8 个字符,A-Z、0-9 和空格)。 我使用了一个相对较小的批量大小(32,我认为这已经太小了)以提高效率,但是仍然花了很长时间来训练第一个 epoch 的四分之一(我每个 epoch 有 826 步,花了 90 分钟199 步...steps_per_epoch = num_train_samples // batch_size)。

数据生成器中包含以下功能:

def shuffle_data(data):
  data=random.shuffle(data)
  return data

我不认为我们可以让这个函数更高效或将它排除在生成器之外。

def preprocessing(img, new_height, new_width):
  img = cv2.resize(img,(new_height, new_width))
  img = img/255
  return img

为了预处理/调整数据大小,我使用此代码将图像设置为唯一大小,例如(224, 224, 3)。我认为,生成器的这一部分花费的时间最多,但我看不到将其从生成器中排除的可能性(因为如果我们在批次之外调整图像大小,我的内存会满)。

#One Hot Encoding of the Labels
from numpy import argmax
# define input string

def my_onehot_encoded(label):
    # define universe of possible input values
    characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ '
    # define a mapping of chars to integers
    char_to_int = dict((c, i) for i, c in enumerate(characters))
    int_to_char = dict((i, c) for i, c in enumerate(characters))
    # integer encode input data
    integer_encoded = [char_to_int[char] for char in label]
    # one hot encode
    onehot_encoded = list()
    for value in integer_encoded:
        character = [0 for _ in range(len(characters))]
        character[value] = 1
        onehot_encoded.append(character)

    return onehot_encoded 

我认为,在这一部分中,可能有一种方法可以提高效率。我正在考虑从生成器中排除这段代码,并在生成器之外生成数组 y_train,这样生成器就不必每次都对标签进行一次热编码。

你怎么看?还是我应该采用完全不同的方法?

【问题讨论】:

    标签: python tensorflow neural-network resize


    【解决方案1】:

    我发现您的问题非常有趣,因为您只提供了线索。所以这是我的调查。

    使用您的 sn-ps,我在 YouTube 上找到了 GitHub repository 和 3 部分视频教程,主要关注 on the benefits 在 Python 中使用生成器函数。 数据基于this kaggle(我建议检查该问题的不同内核,以将您已经尝试过的方法与其他 CNN 网络进行比较,并查看使用中的 API)。

    您不需要从头开始编写数据生成器,虽然这并不难,但发明轮子并不高效。

    然而,为了解决 kaggle 的任务,该模型只需要感知单个图像,因此该模型是一个简单的深度 CNN。但据我了解,您将 8 个随机字符(类)组合成一张图像,一次发送到 recognize multiple classes。对于该任务,您需要 R-CNN 或 YOLO 作为模型。我最近刚刚为自己打开了YOLO v4,它可以很快地用于特定任务。

    关于您的设计和代码的一般建议。

    • 确保库使用 GPU。它节省了很多时间。 (尽管我在 CPU 上非常快地从存储库中重复了花实验 - 大约 10 分钟,但结果预测并不比随机猜测好。所以完整的训练需要大量的 CPU 时间。)
    • 比较不同的版本以找到瓶颈。尝试一个包含 48 张图像(每类 1 张)的数据集,增加每类图像的数量,然后进行比较。减小图像大小、更改模型结构等。
    • 在小型人工数据上测试全新模型以证明想法或使用迭代过程,从可以转换为您的任务的项目开始 (handwriting recognition?)。

    【讨论】:

    • 非常感谢您的全面回答! :-) 特别是您对 DataGenerator 序列类的回答非常有帮助!关于 DataGenerator,我在 Stack Overflow 上提出了另一个问题。或许你可以看看这个问题..是关于GPU的使用:stackoverflow.com/questions/62468830/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多