Рубрики
Без рубрики

Как классифицировать бабочки с глубоким обучением в Кере

Автор оригинала: Bert Carremans.

Данное назад я прочитал интересный пост блога на сайте голландской организации Vlinderstichting Отказ Каждый год они организуют количество бабочек. Добровольцы помогают определить различные виды бабочек в их саду. Вклонестихтинг собирается и анализирует результаты.

Поскольку определение видов бабочек осуществляется добровольцами, неизбежно этот процесс подвержен ошибкам. В результате ВЛиндерстичтинг имеет Чтобы вручную проверить представления, которые требуют много времени.

В частности, существует три бабочки, для которых VlinderderTicting принимает многие неправильные определения. Эти

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

Для подготовки сверточной нейронной сети мне нужно найти изображения бабочек с правильной меткой. Конечно, я мог бы сфотографировать сам бабочек, которые я хочу классифицировать. Они иногда летают в моем саду …

Просто шучу, это займет возраст. Для этого мне нужен автоматический способ получить изображения. Для этого я использую API Flickr через Python.

Настройка API Flickr

Во-первых, я устанавливаю Пакет Flickrapi с пивом. Тогда я создаю необходимую API Ключи на веб-сайте Flickr подключиться к API Flickr.

Помимо пакета Flickrapi, я импортирую пакеты ОС и Urllib для загрузки изображений и создании каталогов.

from flickrapi import FlickrAPI
import urllib
import os
import config

В модуле конфигурации я определяю публичные и секретные ключевые ключи для API Flickr. Так что это просто скрипт Python (config.py) с кодом ниже:

API_KEY = 'XXXXXXXXXXXXXXXXX'  // replace with your key
API_SECRET = 'XXXXXXXXXXXXXXXXX'  // replace with your secret
IMG_FOLDER = 'XXXXXXXXXXXXXXXXX'  // replace with your folder to store the images

Я держу эти ключи в отдельном файле по соображениям безопасности. В результате вы можете сохранить код в публичном хранилище, таким как GitHub или BitBucket, и положить Config.py в .gitignore. Следовательно, вы можете поделиться своим кодом с другими, не заботясь о том, чтобы кто-то имел доступ к вашим учетным данным.

Чтобы извлечь изображения разных видов бабочек, я написал функцию Download_flickr_Photos. Я объясню эту функцию шаг за шагом. Кроме того, я сделал полный код доступен на Github Отказ

Входные параметры

Прежде всего, я проверяю, являются ли входные параметры правильного типа или значений. Если нет, я вызываю ошибку. Объяснение параметров можно найти в DOCSTRING функции.

if not (isinstance(keywords, str) or isinstance(keywords, list)):
    raise AttributeError('keywords must be a string or a list of strings')
if not (size in ['thumbnail', 'square', 'medium', 'original']):
    raise AttributeError('size must be "thumbnail", "square", "medium" or "original"')
if not (max_nb_img == -1 or (max_nb_img > 0 and isinstance(max_nb_img, int))):
    raise AttributeError('max_nb_img must be an integer greater than zero or equal to -1')

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

if isinstance(keywords, str):
    keywords_list = []
    keywords_list.append(keywords)
else:
    keywords_list = keywords
if size == 'thumbnail':
    size_url = 'url_t'
elif size == 'square':
    size_url = 'url_q'
elif size == 'medium':
    size_url = 'url_c'
elif size == 'original':
    size_url = 'url_o'

Подключение к API Flickr

Далее я подключаюсь к API Flickr. В вызове Flickrapi я использую клавиши API, определенные в модуле конфигурации.

flickr = FlickrAPI(config.API_KEY, config.API_SECRET)

Создание подпапок на бабочко

Я сохраняю изображения каждого вида бабочек в отдельной подпапке. Имя каждой подпапки – это имя вида бабочки, данное ключевое слово. Если подпапка еще не существует, я создаю его.

results_folder = config.IMG_FOLDER + keyword.replace(" ", "_") + "/"
if not os.path.exists(results_folder):
    os.makedirs(results_folder)

Ходить в библиотеке Flickr

photos = flickr.walk(
    text=keyword,
    extras='url_m',
    license='1,2,4,5',
    per_page=50)

Я использую метод Walk of Flickr API для поиска изображений для указанного ключевого слова. Этот метод Walk имеет те же параметры, что и Метод поиска в API Flickr.

В текстовом параметре , Я использую ключевое слово для поиска изображений, связанных с этим ключевым словом. Во-вторых, в дополнении параметра , Я указываю URL_M для небольшого среднего размера изображений. Больше объяснения размеров изображений и их соответствующего URL-адреса приведено в этом Flickcurl C Библиотека Отказ

В-третьих, в лицензионном параметре , Я выбираю изображения с некоммерческой лицензией. Больше на лицензионные коды и их значение можно найти на Flickr Платформа API Отказ Наконец, параметр per_page указывает, сколько изображений я разрешу на страницу.

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

Загрузка Flickr изображений

С помощью генератора фотографий я могу загрузить все изображения, найденные для поискового запроса. Сначала я получаю определенный URL, на котором я скачу изображение. Затем я увеличиваю переменную подсчет и использую этот счетчик для создания файлов изображений.

С методом URLRETROVE я загружаю изображение и сохраняю его в папке для видов бабочки. Если возникает ошибка, я распечатаю сообщение об ошибке.

for photo in photos:
    try:
        url=photo.get('url_m')
        print(url)
        count += 1
        urllib.request.urlretrieve(url,  results_folder + str(count) +".jpg")
    except Exception as e:
        print(e, 'Download failure')

Чтобы загрузить несколько видов бабочек, я создаю список и вызови функцию Download_flickr_Photos в цикле. Для простоты я только загружаю два вида бабочек из трех упомянутых выше.

butterflies = ['meadow brown butterfly', 'gatekeeper butterfly']
for butterfly in butterflies:
    download_flickr_photos(butterfly)

Обучение конвертю на небольшом количестве изображений приведет к переоценке. Следовательно, модель сделает ошибки в классификации новых, невидимых изображений. Увеличение данных может помочь избежать этого. К счастью, Keras есть несколько хороших инструментов для легко преобразования изображений.

Я хотел бы сравнить его с тем, как мой сын классифицирует автомобили на дороге. На данный момент ему всего 2 года и не видели столько машин как взрослых. Таким образом, вы могли бы сказать, что его тренировочный набор изображений довольно маленький. Поэтому он более вероятно, неправильно классифицирует автомобили. Например, он иногда принимает скорую помощь по ошибке для полицейского фургона.

По мере того как он станет старше, он увидит больше скорейших скорейших автомобилей и полицейских фургонов с соответствующей ярлыком, которую я дам ему. Таким образом, его учебный набор станет больше и, таким образом, он будет классифицировать их более правильно.

По этой причине нам нужно предоставить CONVNET с большим количеством образов бабочек, чем на данный момент. Простое решение для этого Увеличение данных Отказ Короче говоря, это означает нанесение набора трансформаций к изображениям Flickr.

Keras предоставляет Широкий ассортимент изображений преобразований Отказ Но сначала нам придется преобразовать изображения, чтобы Keras мог работать с ними.

Преобразование изображения на цифры

Мы начинаем, импортируя модуль KERAS. Мы продемонстрируем преобразования изображения с одним примерным изображением. Для этой цели мы используем метод Load_img.

from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
i = load_img('data/train/maniola_jurtina/1.jpg' )
x = img_to_array(i)
x = x.reshape((1,) + x.shape)

Метод Load_img создает файл библиотеки изображения Python. Нам нужно будет преобразовать это в NaMpy Array, чтобы использовать его в методе imagedatagenatorator. Это сделано с удобным методом img_to_array. В результате у нас есть массив формы 75x75x3. Эти размеры отражают ширину, высоту и значения RGB.

На самом деле каждый пиксель изображения имеет 3 значения RGB. Эти диапазон от 0 до 255 и представляют интенсивность красного, зеленого и синего. Более низкое значение обозначает более высокую интенсивность и более высокое значение для более низкой интенсивности. Например, один пиксель может быть представлен в виде списка этих трех значений [78, 136, 60]. Черный будет представлен как [0, 0, 0].

Наконец, нам нужно добавить дополнительное измерение, чтобы избежать ValueError при нанесении преобразований. Это делается с функцией Reshape.

Хорошо, теперь нам есть что работать. Давайте продолжимся с преобразованиями.

Вращение

Указав значение от 0 до 180, KERAS случайным образом выберут угол, чтобы повернуть изображение. Это сделает это по часовой стрелке или против часовой стрелки. В нашем примере изображение будет вращаться с максимумом на 90 градусов.

Имагедженатор также имеет параметр Fill_Mode. Значение по умолчанию «Ближайшее». Вращав изображение в ширину и высоту исходного изображения, мы в конечном итоге с «пустыми» пикселями. Затем Fill_Mode используются ближайшие пиксели для заполнения этого пустого пространства.

imgGen = ImageDataGenerator(rotation_range = 90)
i = 1
for batch in imgGen.flow(x, batch_size=1, save_to_dir='example_transformations', save_format='jpeg', save_prefix='trsf'):
    i += 1
    if i > 3:
        break

В методе потока мы указываем, где сохранить трансформированные изображения. Убедитесь, что этот каталог существует! Мы также префикс вновь созданные изображения для удобства. Метод потока будет работать бесконечно, но для этого примера мы создаем только три изображения. Поэтому, когда наш счетчик достигает этой ценности, мы нарушаем для цикла. Вы можете увидеть результат ниже.

Ширина Shift.

В параметре width_shift_range вы указываете соотношение исходной ширины, с помощью которого изображение может быть смещено влево или вправо. Опять же, Fill_Mode заполнит вновь созданные пустые пиксели. Для оставшихся примеров я только покажу только, как создать интерактивность imagedatatagenerator с соответствующим параметром. Код для генерации изображений такой же, как в примере вращения.

imgGen = ImageDataGenerator(width_shift_range = 90)

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

То же самое можно сделать для смещения вверх или вниз, указав значение для параметра heathe_shift_range.

Вскакивание

Рекалирование изображения будет умножать значения RGB каждого пикселя выбранным значением перед любой другой предварительной обработкой. В нашем примере мы применяем Min-Max Caxing к значениям. В результате эти значения определяют между 0 и 1. Это делает значения меньше и легче для модели для обработки модели.

imgGen = ImageDataGenerator(rescale = 1./255)

Сдвиг

С параметром SHEAR_RANGE мы можем указать, как должны применяться преобразования сдвига. Это преобразование может производить довольно странные изображения, когда значение устанавливается слишком высоким. Так что не устанавливайте это слишком высоко.

imgGen = ImageDataGenerator(shear_range = 0.2)

Zoom.

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

imgGen = ImageDataGenerator(zoom_range = 0.2)

Горизонтальный флип

Это преобразование переворачивает изображение по горизонтали. Жизнь может быть простой иногда …

imgGen = ImageDataGenerator(horizontal_flip = True)

Все преобразования вместе взятые

Теперь, когда мы видели влияние каждого преобразования отдельно, мы применяем все комбинации вместе.

imgGen = ImageDataGenerator(
    rotation_range = 40,
    width_shift_range = 0.2,
    height_shift_range = 0.2,
    rescale = 1./255,
    shear_range = 0.2,
    zoom_range = 0.2,
    horizontal_flip = True)
i = 1
for batch in imgGen.flow(x, batch_size=1, save_to_dir='example_transformations', save_format='jpeg', save_prefix='all'):
    i += 1
    if i > 3:
        break

Настройка структуры папки

Нам нужно хранить эти изображения в определенной структуре папки. Таким образом, мы можем использовать метод flow_from_directory для увеличения изображений и создать соответствующие метки. Эта структура папки должна выглядеть так:

  • тренироваться
  • Маниола Юртина
  • 0.jpg.
  • 1.jpg.
  • Пиродья Титонус
  • 0.jpg.
  • 1.jpg.
  • Проверка
  • Маниола Юртина
  • 0.jpg.
  • 1.jpg.
  • Пиродья Титонус
  • 0.jpg.
  • 1.jpg.

Чтобы создать эту структуру папки, я создал гистор img_train_test_split.py . Отказ Не стесняйтесь использовать его в ваших проектах.

Создание генераторов

Как и прежде, мы указываем параметры конфигурации для генератора обучения. Изображения валидации не будут преобразованы в качестве тренировочных изображений. Мы только разделяем значения RGB, чтобы сделать их меньше.

Метод flow_from_directory принимает изображения из папки поезда или валидации и генерирует партии 32 преобразованных изображений. Установив Class_Mode на «двоичный» одномерную метку, создается на основе имени папки изображения.

train_datagen = ImageDataGenerator(
    rotation_range = 40,
    width_shift_range = 0.2,
    height_shift_range = 0.2,
    rescale = 1./255,
    shear_range = 0.2,
    zoom_range = 0.2,
    horizontal_flip = True)
validation_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
    'data/train',
    batch_size=32,
    class_mode='binary')
validation_generator = validation_datagen.flow_from_directory(
    'data/validation',
    batch_size=32,
    class_mode='binary')

Как насчет разных размеров изображений?

API Flickr позволяет загружать изображения определенных размеров. Однако в реальных приложениях размеры изображения не всегда постоянны. Если соотношение сторон изображений одинаково, мы можем просто изменить размер изображения. В противном случае мы можем обрезать изображения. К сожалению, сложно обрезать изображение, сохраняя объект, который мы хотим классифицировать нетронутыми.

KERAS может иметь дело с различными размерами изображения. При настройке модели вы можете указать None для ширины и высоты в Inport_shape.

input_shape=(3, None, None)  # Theano
input_shape=(None, None, 3)  # Tensorflow

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

  • Не все слои (например, сплит) будут работать без в качестве входного измерения
  • Это может быть вычислительно тяжело работать

Для оставшейся части этой статьи я буду обсуждать структуру сверточной нейронной сети, проиллюстрированной с некоторыми примерами для нашего проекта бабочки. В конце этой статьи мы будем наши первые результаты классификации.

Из каких слоев состоит из сверточной нейронной сети?

Конечно, вы можете выбрать, сколько слоев и их типа, чтобы добавить в свою сверточную нейронную сеть (также называемую CNN или CONGNET). В этом проекте мы начнем со следующей структурой:

Давайте понять, что делает каждый слой и как мы создаем их с KERAS.

Входной слой

Эти разные версии изображений были изменены через несколько преобразований. Затем эти изображения преобразуются в числовое представление или матрицу.

Размеры этой матрицы будут шириной x высоты x количество (цветных) каналов Отказ Для изображений RGB количество каналов будет три. Для изображений в оттенках серого это равно одному. Ниже вы можете увидеть числовое представление изображения 7 × 7 RGB.

Поскольку наши изображения имеют размеры 75 × 75, нам нужно указать, что в параметре INPUT_SHAPE при добавлении первого сверкального слоя.

cnn = Sequential()
cnn.add(Conv2D(32,(3,3), input_shape = (3 ,75 ,75)))

Сверточный слой

В первых слоях сверточная нейронная сеть будет искать более низкие функции, такие как горизонтальные или вертикальные края. Чем дальше мы идем в сеть, он будет поискать функции более высокого уровня, например крыло бабочки, например. Но как он обнаруживает функции, когда он получает только номера в качестве ввода? Вот где приходят фильтры.

Фильтры (или ядра)

Вы можете подумать о фильтре в качестве прожектора определенного размера, который сканирует на изображение. Пример фильтра ниже имеет размеры 3x3x3 и содержат вес, которые будут обнаруживать вертикальный край. Для изображения в середине серого размеры были бы 3x3x1. Обычно фильтр имеет меньшие размеры, чем изображение, которое мы хотим классифицировать. Обычно используются 3 × 3, 5 × 5 или 7 × 7. Третье измерение всегда должно быть равно количеству каналов.

При сканировании изображения значения RGB преобразуются. Это делает это преобразование путем умножения значений RGB с весами фильтра. Наконец, умноженные значения затем суммируются по всем каналам. В нашем примере изображения 7x7x3 и фильтр 3x3x3 это приведет к исходу 5x5x1.

Анимация ниже иллюстрирует эту сверточную операцию. Для простоты мы только ищите вертикальный край в красном канале. Таким образом, веса для зеленых и синих каналов равны нулю. Но вы должны помнить, что результаты умножения для этих каналов добавляются к результату красного канала.

Как показано ниже, как показано ниже, сверточный слой будет производить числовые результаты. Когда у вас есть более высокие числа, это означает, что фильтр наткнулся на эту функцию, которую он искал. В нашем примере вертикальный край.

Мы можем указать, что мы хотим более одного фильтра. Эти фильтры могут иметь свою собственную функцию для поиска на изображении. Предположим, мы используем 32 фильтры размера 3x3x3. Результат всех фильтров сложен, и мы в конечном итоге с объемом 5x5x32 в нашем примере. В фрагменте кода выше мы добавили 32 фильтра размером 3x3x3.

Шайд

В приведенном выше примере мы видели, что фильтр поднимает один пиксель за раз. Это так называемый шаг. Мы могли бы увеличить количество пикселей, которые двигается фильтр. Увеличение шага уменьшит размеры исходного изображения намного быстрее. В приведенном ниже примере вы видите, как фильтр перемещается с шагом 2, что приведет к появлению 3x3x1 для фильтра 3x3x3 и изображения 7x7x3.

Прокладка

Применяя фильтр, размеры исходного изображения быстро уменьшаются. Особенно пиксели по краям изображения используются только один раз в сверточной работе. Это приводит к потере информации. Если вы хотите избежать этого, вы можете указать прокладку. Протяженность добавляет «дополнительные пиксели» вокруг изображения.

Предположим, мы добавляем прокладку одного пикселя вокруг изображения 7x7x3. Это приводит к изображению 9x9x3. Если мы применим фильтр 3x3x3 и шаг 1, мы заканчиваем результатом 7x7x1. Итак, в этом случае мы сохраняем размеры исходного изображения, а внешние пиксели используются более одного раза.

Вы можете рассчитать результирующий результат сверточной работы со специфическими прокладками и шагом следующим образом:

1 + [(Оригинальный размер + прокладки x 2 – Размер фильтра)/Размер шага]

Например, предположим, что у нас есть эта настройка нашего SOV-слоя:

  • 7x7x3 Изображение
  • Фильтр 3x3x3
  • прокладки 1 пикселя
  • Шайд 2 пикселей

Это даст 1 + [(7 + 1 х 2-3)/

Почему нам нужны сверточные слои?

Преимущество использования конвровных слоев заключается в том, что количество параметров для оценки намного ниже. Намного ниже по сравнению с нормальным скрытым слоем. Предположим, мы продолжаем с нашим примером изображения 7x7x3 и фильтр 3x3x3 без прокладки и шага 1. Свенно-сверточный слой будет иметь 5x5x1 + 1 вес для оценки. В нейронной сети с входами 7x7x3 и нейронами 5x5x1 в скрытом слое нам нужно оценить 3,675 веса. Представьте, что это число, когда у вас есть большие изображения …

Слой RELU.

Или выпрямленный линейный слой блока. Этот слой добавляет нелинейность к сети. Сверлюционный слой представляет собой линейный слой, поскольку оно подводит подсчет мультипликаций весов фильтра и значений RGB.

Итоги функции RELU равны нулю для всех значений X. В противном случае он равен ценности x. Код в KERA, чтобы добавить слой RELU:

cnn.add(Activation('relu'))

Объединение

Объединение агрегатов входной громкости для дальнейшего уменьшения измерений. Это ускоряет время вычислений, поскольку количество оценок параметров уменьшается. Кроме того, это помогает избежать преодоления, сделав сеть более надежным. Ниже мы иллюстрируем максимальное объединение размером 2 × 2 и шага 2.

Код в KERA, чтобы добавить объединение размером 2 × 2:

cnn.add(MaxPooling2D(pool_size = (2 ,2)))

Полностью подключенный слой

В конце конверцы способны обнаруживать функции более высокого уровня на входных изображениях. Это может подать вклад в качестве ввода для полностью подключенного слоя. Прежде чем мы сможем сделать это, мы сглаживаем вывод последнего слоя RELU. Уплотнение означает, что мы преобразуем его в вектор. Значения вектора затем подключены ко всем нейронам в полностью подключенном слое. Для этого в Python мы используем следующие функции KERAS:

cnn.add(Flatten())        
cnn.add(Dense(64))

Выбывать

Также как пул, рассыпание может помочь избежать перенапряжения. Он случайным образом устанавливает указанную фракцию входных данных до нуля, во время тренировки модели. Расширение от 20 до 50% считается хорошо.

cnn.add(Dropout(0.2))

Сигмоидная активация

Поскольку мы хотим создать вероятность того, что изображение является одним из двух видов бабочек (то есть двоичная классификация), мы можем использовать слой активации SIGMoid.

cnn.add(Activation('relu'))
cnn.add(Dense(1))
cnn.add(Activation( 'sigmoid'))

Применение сверточной нейронной сети на образах бабочки

Теперь мы можем определить полную сверточную структуру нейронной сети, как показано в начале этого поста. Во-первых, нам нужно импортировать необходимые модули KERAS. Тогда мы можем начать добавлять слои, которые мы объяснены выше.

from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Flatten, Dense, Dropout
from keras.preprocessing.image import ImageDataGenerator
import time
IMG_SIZE = # Replace with the size of your images
NB_CHANNELS = # 3 for RGB images or 1 for grayscale images
BATCH_SIZE = # Typical values are 8, 16 or 32
NB_TRAIN_IMG = # Replace with the total number training images
NB_VALID_IMG = # Replace with the total number validation images

Я сделал несколько дополнительных параметров, явных для конвных слоев. Вот краткое объяснение:

  • kernel_size указывает размер фильтра. Так что для первого конвой слой это размер 2 × 2
  • Закладки означает нанесение нулевой прокладки, так как такой исходный размер изображения сохраняется.
  • Заголов означает, что мы не применяем никакой прокладки.
  • Data_Format – это просто указать, что количество цветовых каналов указывается последним в аргументе INPUT_SHAPE.
cnn = Sequential()
cnn.add(Conv2D(filters=32, 
               kernel_size=(2,2), 
               strides=(1,1),
               padding='same',
               input_shape=(IMG_SIZE,IMG_SIZE,NB_CHANNELS),
               data_format='channels_last'))
cnn.add(Activation('relu'))
cnn.add(MaxPooling2D(pool_size=(2,2),
                     strides=2))
cnn.add(Conv2D(filters=64,
               kernel_size=(2,2),
               strides=(1,1),
               padding='valid'))
cnn.add(Activation('relu'))
cnn.add(MaxPooling2D(pool_size=(2,2),
                     strides=2))
cnn.add(Flatten())        
cnn.add(Dense(64))
cnn.add(Activation('relu'))
cnn.add(Dropout(0.25))
cnn.add(Dense(1))
cnn.add(Activation('sigmoid'))
cnn.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])

Наконец, мы компилируем эту сетевую структуру и устанавливаем параметр потерь в двоичную_crossentropy, что полезно для двоичных целей и использование точности как метрика оценки.

После указания структуры сети мы создаем генераторы для образцов обучения и валидации. На учебных образцах мы применяем расширение данных, как объяснено выше. На образцах проверки мы не применяем никакого увеличения, поскольку они просто используются для оценки производительности модели.

train_datagen = ImageDataGenerator(
    rotation_range = 40,                  
    width_shift_range = 0.2,                  
    height_shift_range = 0.2,                  
    rescale = 1./255,                  
    shear_range = 0.2,                  
    zoom_range = 0.2,                     
    horizontal_flip = True)
validation_datagen = ImageDataGenerator(rescale = 1./255)
train_generator = train_datagen.flow_from_directory(
    '../flickr/img/train',
    target_size=(IMG_SIZE,IMG_SIZE),
    class_mode='binary',
    batch_size = BATCH_SIZE)
validation_generator = validation_datagen.flow_from_directory(
    '../flickr/img/validation',
    target_size=(IMG_SIZE,IMG_SIZE),
    class_mode='binary',
    batch_size = BATCH_SIZE)

С Flow_from_Directory Метод на генераторах мы можем легко пройти все изображения в указанных каталогах.

Наконец, мы можем соответствовать сверточной нейронной сети на учебные данные и оценивать с данными о проверке. Полученные веса модели могут быть сохранены и повторно использованы позже.

start = time.time()
cnn.fit_generator(
    train_generator,
    steps_per_epoch=NB_TRAIN_IMG//BATCH_SIZE,
    epochs=50,
    validation_data=validation_generator,
    validation_steps=NB_VALID_IMG//BATCH_SIZE)
end = time.time()
print('Processing time:',(end - start)/60)
cnn.save_weights('cnn_baseline.h5')

Количество эпохи произвольно устанавливается на 50. Эпоха является циклом пропаганды вперед, проверяя ошибку, а затем регулировка весов во время обратной передачи.

STAPES_PER_EPOCH устанавливается на количество учебных изображений, разделенных на размер партии (кстати, символ двойного разделения удостоверится, что результат – это целое число, а не поплавок). Указание размера партии больше 1 будет ускорить процесс. IDEM для параметра Validation_steps.

Полученные результаты

После запуска 50 эпох мы имеем точность обучения 0,8091 и точность валидации 0,7359. Таким образом, сверточная нейронная сеть по-прежнему страдает от довольно устойчивости. Мы также видим, что точность валидации варьируется довольно много. Это потому, что у нас есть небольшой набор образцов валидации. Было бы лучше сделать K-Fold Cross-Vavilation для каждой оценки. Но это займет довольно некоторое время.

Чтобы решить переизложение, которое мы могли бы:

  • Увеличьте скорость отсева
  • Применить выпадение на каждом слое
  • Найти больше учебных данных

Мы посмотрим на первые два варианта и следите за результатом. Результаты нашей первой модели будут служить базовым уровнем. После нанесения дополнительного выпадающего слоя и увеличения скорости выпадания модель немного менее переопределена.

Я надеюсь, что вы все понравились читать этот пост и узнали что-то новое. Полный код доступен на Github Отказ Ваше здоровье!