Как сделать генератор данных более эффективным? - PullRequest
5 голосов
/ 29 мая 2020

Чтобы обучить нейронную сеть, я изменил код, который нашел на 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

Теперь я попытался обучить нейронную сеть с помощью этого кода, размер выборки поезда составляет 105000 (файлы изображений, которые содержат 8 символов из 37 возможных, AZ, 0-9 и пустое пространство). Я использовал относительно небольшой размер партии (32, я думаю, что это уже слишком мало), чтобы сделать его более эффективным, но, тем не менее, тренировка четверти первой эпохи длилась вечно (у меня было 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 вне генератора, чтобы генератору не приходилось каждый раз горячо кодировать метки.

Как вы думаете? Или мне следует go для совершенно другого подхода?

1 Ответ

3 голосов
/ 22 июня 2020

Я нашел ваш вопрос очень интригующим, потому что вы даете только подсказки. Итак, вот мое расследование.

Используя ваши фрагменты, я нашел репозиторий GitHub и трехчастный видеоурок на YouTube, в котором основное внимание уделяется преимуществам использования функций генератора в Python. Данные основаны на this kaggle (я бы порекомендовал проверить разные ядра по этой проблеме, чтобы сравнить подход, который вы уже пробовали, с другими сетями CNN, и просмотреть используемый API).

Вам не нужно писать генератор данных с нуля, хотя это несложно, но изобретать колесо непродуктивно.

Тем не менее, чтобы решить задачу kaggle, модель должна воспринимать только отдельные изображения, следовательно, модель представляет собой простую глубокую CNN. Но насколько я понимаю, вы объединяете 8 случайных символов (классов) в одно изображение, чтобы распознавать сразу несколько классов . Для этой задачи вам понадобится R-CNN или YOLO в качестве модели. Я недавно открыл для себя YOLO v4 , и можно очень быстро заставить его работать для конкретной задачи c.

Общие советы по вашему дизайну и коду.

  • Убедитесь, что библиотека использует графический процессор. Это экономит много времени. (Хотя я очень быстро повторил эксперимент с цветами из репозитория на ЦП - около 10 минут, но полученные прогнозы не лучше, чем случайное предположение. Таким образом, полное обучение требует много времени на ЦП.)
  • Сравните разные версии, чтобы найти узкое место. Попробуйте набор данных с 48 изображениями (по одному на класс), увеличьте количество изображений на класс и сравните. Уменьшите размер изображения, измените структуру модели и т. Д. c.
  • Тестируйте новые модели на небольших искусственных данных, чтобы подтвердить идею, или используйте итеративный процесс, начав с проектов, которые можно преобразовать в вашу задачу ( распознавание рукописного ввода ?).
...