Обзор

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

Задача

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

  1. Создание набора данных изображений (мы сделали это за вас)
  2. Загрузка набора данных изображения для эффективного обучения
  3. Построение модели классификатора изображений
  4. Обучение модели с использованием облачных графических процессоров
  5. Проверка обученной модели

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

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

Начиная

Выполните следующие действия, чтобы попробовать этот код:

  1. Open JupyterLabс предустановленным TensorFlow 1.11.
  2. Откройте Terminal в открывшейся лаборатории.
  3. Клонируйте репозиторий Github этого проекта с помощью: $ git clone https://github.com/PeterChauYEG/animal_classifier.git
  4. Откройте Animal Classifier.pynb в каталоге animal_classifier. Это откроет блокнот Jupyter.
  5. Запустите всю записную книжку, используя меню Run и выбрав Run All Cells
  6. Прокрутите вниз, чтобы увидеть обучение в действии. Первая часть обучения происходит в cell 20.

Загрузка зависимостей

Нам нужно импортировать ряд зависимостей Python.

# Allows division to return a float
from __future__ import division
# Allows access to the file system
import os
# Provides an API for scientific computing
import numpy as np
# Allows use to timestamp the training run
from datetime import datetime
# Allows us to render images and plot data
from keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img
import math
import matplotlib.pyplot as plt
# Machine learning framework that provides an abstract API on top of Tensorflow
import keras
from keras.callbacks import TensorBoard
from keras.layers import Conv2D, Dense, Flatten, MaxPooling2D
from keras.models import Sequential
from keras import optimizers

Конфигурации

Поскольку мы строим графики в Jupyter Lab, нам нужно настроить matplotlib для рендеринга графиков в реальном времени.

# configure the matplotlib for Jupyter Lab used for rendering the images
%matplotlib inline

Каталоги наборов данных

dataset содержит все изображения. Отдельный каталог должен быть создан для каждого из следующего:

  1. Набор обучающих данных: изображения, которые используются во время обучения модели.
  2. Набор данных проверки: изображения, которые используются во время проверки модели.

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

# Paths to datasets to be used
train_dir = 'dataset/train'
validate_dir = 'dataset/validate'

Гиперпараметры

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

  1. Размер изображения будет уменьшен до 200x200x3. Это означает, что каждое изображение будет размером 200 пикселей на 200 пикселей с 3 цветовыми каналами (красный, зеленый, синий). Чем больше пикселей, тем лучше модель, так как это может увеличить детализацию изображения.
  2. Скорость обучения - это скорость, с которой модель будет обновлять градиенты, которые она пытается оптимизировать.
  3. Размер пакета - это количество изображений, которые будут загружены в модель за одну итерацию.
  4. Эпоха - это количество раз, которое модель должна перебирать по всему набору данных и обновлять веса модели. В какое-то количество эпох выигрыш от обучения приближается к нулю. Можно перетренировать модель.
  5. Часто рекомендуется разделить набор данных в соотношении 80:20. Это общее правило, которое работает достаточно хорошо.
# number of images in the training dataset
n_train = 8000
# number of images in the validation dataset
n_validation = 2000
# the number of pixels for the width and height of the image
image_dim = 200
# the size of the image (h,w,c)
input_shape = (image_dim, image_dim, 3)
# the rate which the model learns
learning_rate = 0.001
# size of each mini-batch
batch_size = 32
# nunmber of training episodes
epochs = 10

Выходы

Выведем 2 элемента:

  1. Журналы тренировок: их можно передать в Tensorboard для анализа.
  2. Обученная модель: так что ее можно использовать где угодно

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

# directory which we will save training outputs to
# add a timestamp so that tensorboard show each training session as a different run
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
output_logs_dir = 'logs/' + timestamp + '-' + str(batch_size) + '-' + str(epochs)
# directory to save the model
model_name = 'trained_model'

Загрузка набора данных изображения для эффективного обучения

Генераторы данных изображений

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

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

Keras предоставляет для этого оптимизированный метод с помощью класса Image Data Generator. Это позволяет нам эффективно загружать изображения из каталога. Эти генераторы также могут преобразовывать набор данных многими другими способами, чтобы пополнить его. Изучите эти дополнительные преобразования, которые помогут сделать вашу модель более общей и повысить точность.

# define data generators
train_data_generator = ImageDataGenerator(rescale=1./255,
                                          fill_mode='nearest')
validation_data_generator = ImageDataGenerator(rescale=1./255,
                                               fill_mode='nearest')
# tell the data generators to use data from the train and validation directories
train_generator = train_data_generator.flow_from_directory(train_dir,
                                                          target_size=(image_dim, image_dim),
                                                          batch_size=batch_size,
                                                          class_mode='categorical')
validation_generator = validation_data_generator.flow_from_directory(validate_dir,
                                                          target_size=(image_dim, image_dim),
                                                          batch_size=batch_size,
                                                          class_mode='categorical')

Получить имена классов

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

# get a dictionary of class names
classes_dictionary = train_generator.class_indices
# turn classes dictionary into a list
class_keys = list(classes_dictionary.keys())
# get the number of classes
n_classes = len(class_keys)

Загрузить пути к изображениям для набора данных проверки

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

# Get the name of each directory in the root directory and store them as an array.
classes = get_class_labels(validate_dir)
# Get the paths of all the images in the first class directory and store them as a 2d array.
image_paths = get_class_images(classes, validate_dir)

Построение модели классификатора изображений

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

Мы будем использовать несколько типов слоев и активаций:

  1. Conv2D - это двумерный сверточный слой. Он применяет фильтры к введенному изображению. Это помогает модели узнать о пространственных отношениях на изображении.
  2. ReLu - это тип нелинейной функции активации. Это помогает модели понять, какие нейроны активируются.
  3. MaxPooling2D понижает дискретизацию входных данных. Мы используем его, чтобы уменьшить размерность ввода. Это создает более абстрактную форму ввода.
  4. Flatten превратит матрицу в строку. Как лепить булочку из блина. Мы используем его, чтобы можно было подавать вывод в плотные слои.
  5. Dense - это плотно связанный слой нейронной сети.
  6. Softmax - это функция активации. Мы используем его, чтобы преобразовать выходные числа в диапазон от 0 до 1. Это также приведет к тому, что все выведенные числа будут суммироваться до 1. Это можно интерпретировать как десятичную вероятность класса.

Обратите внимание, что последний слой имеет такое же количество нейронов, что и классы. Это означает, что этот слой выведет 10 чисел, сопоставленных с классом.

# define the model 
# takes in images, convoles them, flattens them, classifies them
model = Sequential([
    Conv2D(16, (3, 3), activation='relu', padding='same', input_shape=input_shape),
    Conv2D(16, (3, 3), activation='relu', padding='same'),
    MaxPooling2D(pool_size=(2,2), strides=None, padding='valid'),
    Conv2D(32, (3, 3), activation='relu', padding='same'),
    Conv2D(32, (3, 3), activation='relu', padding='same'),
    MaxPooling2D(pool_size=(2,2), strides=None, padding='valid'),
    Conv2D(64, (3, 3), activation='relu', padding='same'),
    Conv2D(64, (3, 3), activation='relu', padding='same'),
    MaxPooling2D(pool_size=(2,2), strides=None, padding='valid'),
    Conv2D(128, (3, 3), activation='relu', padding='same'),
    Conv2D(128, (3, 3), activation='relu', padding='same'),
    MaxPooling2D(pool_size=(2,2), strides=None, padding='valid'),
    Flatten(),
    Dense(256, activation='relu'),
    Dense(n_classes, activation='softmax')
])
# define the optimizer and loss to use
model.compile(optimizer=optimizers.SGD(lr=learning_rate, momentum=0.9),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

Изучите модель

Мы можем создать общий обзор структуры модели. Каждая строка - это слой модели.

# look at the defined model
model.summary()

Структура модели

_________________________________________________________________ Layer (type)                 Output Shape              Param #    ================================================================= conv2d_1 (Conv2D)            (None, 200, 200, 16)      448        _________________________________________________________________ conv2d_2 (Conv2D)            (None, 200, 200, 16)      2320       _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 100, 100, 16)      0          _________________________________________________________________ conv2d_3 (Conv2D)            (None, 100, 100, 32)      4640       _________________________________________________________________ conv2d_4 (Conv2D)            (None, 100, 100, 32)      9248       _________________________________________________________________ max_pooling2d_2 (MaxPooling2 (None, 50, 50, 32)        0          _________________________________________________________________ conv2d_5 (Conv2D)            (None, 50, 50, 64)        18496      _________________________________________________________________ conv2d_6 (Conv2D)            (None, 50, 50, 64)        36928      _________________________________________________________________ max_pooling2d_3 (MaxPooling2 (None, 25, 25, 64)        0          _________________________________________________________________ conv2d_7 (Conv2D)            (None, 25, 25, 128)       73856      _________________________________________________________________ conv2d_8 (Conv2D)            (None, 25, 25, 128)       147584     _________________________________________________________________ max_pooling2d_4 (MaxPooling2 (None, 12, 12, 128)       0          _________________________________________________________________ flatten_1 (Flatten)          (None, 18432)             0          _________________________________________________________________ dense_1 (Dense)              (None, 256)               4718848    _________________________________________________________________ dense_2 (Dense)              (None, 10)                2570       ================================================================= Total params: 5,014,938 Trainable params: 5,014,938 Non-trainable params: 0 _________________________________________________________________

Перед обучением проверьте точность модели

Давайте посмотрим, насколько хорошо модель работает, прежде чем тренировать ее. Определим точность модели по 1 классу. Это будет сделано путем прогнозирования всех изображений 1 класса. Помните, что это не является репрезентативным для всей модели, поскольку это только 1 класс из 10.

# label of the class we are making predictions on
single_class = class_keys[0]
# first class image paths 
single_class_image_paths = image_paths[0]
# make predictions on the first class
single_class_predictions = predict(int(n_validation / n_classes), single_class_image_paths, model)
# get the accuracy of predictions on the first class
single_class_accuracy = predictions_accuracy(class_keys, single_class, single_class_predictions)
print("Current accuracy of model for class " + single_class + ": " + str(single_class_accuracy))

Обучение модели с использованием облачных графических процессоров

Эта модель имеет более 5000000 обучаемых параметров - их слишком много, чтобы настраивать их вручную. Нам нужно обучить модель с помощью обучающего набора данных, чтобы модель могла узнать оптимальные веса, которые следует использовать. Эти веса являются значениями параметров модели.

# log information for use with tensorboard
tensorboard = TensorBoard(log_dir=output_logs_dir)
# train the model using the training data generator
model.fit_generator(train_generator,
                    steps_per_epoch=math.floor(n_train/batch_size),
                    validation_data=validation_generator,
                    validation_steps=n_validation,
                    epochs=epochs,
                    callbacks=[tensorboard])

Изучите точность модели после некоторого обучения

Давайте посмотрим, насколько хорошо работает модель, теперь, когда мы немного ее обучили. Опять же, будем определять точность модели по 1 классу.

# make predictions on the first class
single_class_predictions = predict(int(n_train / n_classes), single_class_image_paths, model)
# get the accuracy of predictions on the first class
single_class_accuracy = predictions_accuracy(class_keys, single_class, single_class_predictions)
print("Current accuracy of model for class " + single_class + ": " + str(single_class_accuracy))

Продолжить обучение модели

Продолжим обучение модели.

# train the model using the training data generator
model.fit_generator(train_generator,
                    steps_per_epoch=math.floor(n_train/batch_size),
                    validation_data=validation_generator,
                    validation_steps=n_validation,
                    epochs=epochs,
                    callbacks=[tensorboard])

Изучите точность модели после обучения

Теперь, когда мы закончили обучение модели, давайте проверим ее точность на 1 классе.

# make predictions on the first class
single_class_predictions = predict(int(n_train / n_classes), single_class_image_paths, model)
# get the accuracy of predictions on the first class
single_class_accuracy = predictions_accuracy(class_keys, single_class, single_class_predictions)
print("Current accuracy of model for class " + single_class + ": " + str(single_class_accuracy))

Понимание показателей обучения

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

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

Вы должны увидеть уменьшение потерь (потерь) при обучении, повышение точности обучения (соотв.) Для данных обучения.

Вы должны увидеть уменьшение потерь при проверке (val_loss) и повышение точности проверки (val_acc) для данных проверки.

Тензорборд

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

В JupyterLab вы можете использовать вкладку команд для создания новой Tensorboard.

  1. Откройте commands panel с помощью CTRL + SHIFT + C
  2. Искать Create a new tensorboard
  3. Выберите этот параметр и укажите на него animal_classifier/logs.

Вы сможете визуализировать точность своей модели по эпохам. Каждый тренировочный запуск создает новый набор журналов. Это отображается в Tensorboard в виде отдельной линии.

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

Потеря тренировки

Точность тренировки

Утрата валидации

Точность проверки

Предсказывать

Полезно знать, какие изображения были предсказаны правильно, а какие нет. Давайте рассмотрим 10 прогнозов, по 1 прогнозу на класс.

# get 1 image path per class
predict_image_paths = [image_path[0] for image_path in image_paths]
# Make 1 prediction per class
predictions = predict(10, predict_image_paths, model)
# plot the image that was predicted
plot_prediction(class_keys, predict_image_paths, predictions)

Экспорт обученной модели

Что нам делать с обученной моделью? Экспорт для ваших приложений!

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

# export the model for later
model.save(model_name)

Следующие шаги

В моем следующем сообщении в блоге мы исследуем поиск гиперпараметров до точности модели. Мы также рассмотрим, как можно улучшить архитектуру модели.

Образовательные ресурсы

использованная литература

Керас
Набор данных Animals 10