Часть 3

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

Успех ConvNet в конкурсе классификации изображений в 2011 году привел к более широкому вниманию к области глубокого обучения.

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

Две интересные характеристики, которыми обладает ConvNet:

  1. Шаблоны, которые изучает ConvNet, инвариантны к трансляции.
  2. ConvNet может изучать специальные иерархии шаблонов.

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

Типичная ConvNet имеет три типа слоев: свертка, объединение и ReLu (как показано на изображении выше).

В нашем примере мы используем набор данных CIFRA10. Набор данных CIFRA10 был разработан Канадским институтом перспективных исследований и состоит из 60 000 фотографий размером 32x32 пикселя, разделенных на 10 классов. Набор данных разделен на обучающие и тестовые данные, где 50 000 изображений являются обучающими данными, а 10 000 изображений — тестовыми данными.

Итак, специальные размеры входных данных — 32x32 с глубиной 3, которые должны поддерживаться нашим первым слоем ConvNet.

В ConvNet параметры организованы в наборы трехмерных структурных единиц, называемых фильтрами. Фильтры обычно квадратные с точки зрения специальных размеров, а типичные размеры 3x3, 5x5, 7x7 и более на больших изображениях, и они также называются картой признаков.

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

Прокладка

Операция свертки уменьшает размер слоя по сравнению с размером предыдущего слоя. Давайте посмотрим на пример. Если у нас есть входное изображение 32x32, после первого слоя операции свертки вы получите изображение 28x28. Если вам нужно получить выходное изображение с теми же пространственными размерами, что и входное изображение, то нам нужно будет использовать заполнение. Заполнение — это метод добавления соответствующего количества строк и столбцов с каждой стороны карты входных объектов, чтобы можно было расположить центральное окно свертки вокруг каждой входной плитки. В библиотеке Keras это достигается путем настройки аргумента заполнения на «одинаковый» в слое Conv2D, что означает, что выходные данные должны иметь ту же ширину и высоту, что и входные данные. Взгляните на пример кода:

# Convolutional Layer 1
    model.add(Conv2D(32, (3, 3), input_shape=(32, 32, 3), 
                     padding='same', activation='relu', 
                     kernel_constraint=maxnorm(3)))

Операция максимального объединения

В приведенном ниже примере вы заметите, что размер карты объектов уменьшается на 50% после каждого слоя MaxPooling2D, который играет роль агрессивного понижения дискретизации карты объектов. Эта операция концептуально похожа на операцию свертки, за исключением того, что вместо преобразования локальных патчей с помощью изученного линейного преобразования она преобразуется с помощью жестко запрограммированной операции максимального тензора. Максимальное объединение обычно выполняется с окнами 2x2, тогда как свертка обычно выполняется с окнами 3x3.

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

model.add(Conv2D(32, (3, 3), input_shape=(32, 32, 3), 
                     padding='same', activation='relu', 
                     kernel_constraint=maxnorm(3)))
model.add(MaxPooling2D(pool_size=(2, 2)))

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

Методы достижения более высокой точности

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

  1. Увеличение данных. Он генерирует больше обучающих данных из существующего набора данных, дополняя выборки с помощью ряда случайных преобразований, которые дают правдоподобно выглядящие изображения. Цель состоит в том, чтобы во время обучения ваша модель никогда не видела одну и ту же картинку дважды.
  2. Извлечение признаков с помощью предварительно обученной сети. Очень эффективным и распространенным способом углубления обучения на небольших наборах данных является использование предварительно обученных сетей. Если набор данных достаточно большой и достаточно общий, то специальная иерархия признаков, изученная предварительно обученной сетью, может эффективно действовать как общая модель и может оказаться полезной для многих различных задач компьютерного зрения. Извлечение признаков — это метод, который использует представления, изученные предыдущей сетью, для извлечения интересных признаков из новых выборок. Затем эти функции проходят через новый классификатор, который обучается с нуля.
  3. Тонкая настройка предварительно обученной сети. Это еще один очень популярный метод повторного использования модели. Техника точной настройки состоит из размораживания нескольких сверточных базовых слоев и совместного обучения как новых добавленных слоев в модель, так и этих незакрепленных верхних слоев. Это называется тонкой настройкой, так как она немного корректирует более абстрактное представление повторно используемой модели.

Модель CNN и пример кода

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

С этой моделью я добился точности 83,41%; оставляя эту модель с огромными возможностями для улучшения, применяя методы, описанные в этой статье.

Ниже приведен полный код модели сверточных нейронных сетей (CNN):

import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Activation, Dropout
from keras.layers import Flatten
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.utils import to_categorical
from keras.constraints import maxnorm
from keras.optimizers import SGD
from keras.datasets import cifar10
import matplotlib.pyplot as plt
# network attributes
dropout1 = 0.2
dropout2 = 0.5
epochs = 100
learning_rate = 0.01
batch_size = 30
decay = learning_rate/epochs
sgd = SGD(lr=learning_rate, momentum=0.9,
          decay=decay, nesterov=False)
# initialize random number generator
seed = 7
np.random.seed(seed)
###############################################
# Load and prepare dataset
###############################################
# load CIFRA10 dataset
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
# normalize the input from 0-255 to 0.00 - 1.00
X_train = (x_train.astype('float32')) / 255
X_test = (x_test.astype('float32')) / 255
# label encoding - one hot encode
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
number_classes = y_test.shape[1]
###############################################
# Create our CNN model
###############################################
def create_model():
    model = Sequential()
    # Convolutional Layer 1
    model.add(Conv2D(32, (3, 3), input_shape=(32, 32, 3), 
                     padding='same', activation='relu', 
                     kernel_constraint=maxnorm(3)))
    # model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(dropout1))
    # Convolutional Layer 2
    model.add(Conv2D(32, (3, 3), padding='same',
                     activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    # Convolutional Layer 3
    model.add(Conv2D(64, (3, 3), padding='same',
                     activation='relu'))
    model.add(Dropout(dropout1))
    # Convolutional Layer 4
    model.add(Conv2D(64, (3, 3), padding='same',
                     activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    # Convolutional Layer 5
    model.add(Conv2D(128, (3, 3), padding='same',
                     activation='relu'))
    model.add(Dropout(dropout1))
    # Convolutional Layer 6
    model.add(Conv2D(128, (3, 3), padding='same',
                     activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    # Dropout is added as Regulaizer
    model.add(Flatten())
    model.add(Dropout(dropout1))
    # multilayer perceptrons part of the network
    model.add(Dense(512, activation='relu'))
    model.add(Dropout(dropout1))
    model.add(Dense(128, activation='relu'))
    model.add(Dropout(dropout1))
    model.add(Dense(number_classes))
    model.add(Activation('softmax'))
    # compile the model
    model.compile(loss='categorical_crossentropy',
                  optimizer=sgd, metrics=['accuracy'])
    return model
# build a model
model = create_model()
# print model summary
model.summary()
# train the model
history = model.fit(X_train, y_train,
                    validation_data=(X_test, y_test),
                    epochs=epochs, batch_size=batch_size)
# Final evaluation of the model
score = model.evaluate(X_test, y_test, verbose=0)
print("\n--------------------------------------------")
print("\nCNN Accuracy: %.2f%%" % (score[1]*100))
print("\nCNN Error: %.2f%%" % (100-score[1]*100))
# summarize history for accuracy
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
# summarize history for loss
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
# save the model as JSON file
# serialize model to JSON
model_json = model.to_json()
with open("CNN2_model.json", "w") as json_file:
    json_file.write(model_json)
# save the weights
# serialized weight to HDF5
model.save_weights("CNN2_model.h5")
print("\nCNN model saved to the disk.")

А вот и графики точности и потерь в зависимости от эпох.

Резюме

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

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

  1. Глубокое обучение с помощью Python, Франсуа Шолле, ISBN 9781617294433
  2. Искусственный интеллект для людей, том 1: основные алгоритмы, Джефф Хитон, ISBN978–1493682225
  3. Искусственный интеллект для людей, том 3: глубокое обучение и нейронные сети, Джефф Хитон, ISBN978–1505714340
  4. Разработка моделей глубокого обучения на Theano и TensorFlow с использованием Keras, Джейсон Браунли
  5. Глубокое обучение, Ян Гудфеллоу, Йошуа Бенджио и Аарон Курвиль, ISBN 9780262035613
  6. Нейронные сети и обучающие машины, Саймон Хейкин, ISBN 9780131471399
  7. Нейронные сети и глубокое обучение, Чари К. Аггарвал, ISBN 9783319944623