Эксперименты с многослойным перцептроном в Keras

From Deep Learning IMM
Jump to: navigation, search

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

Описание Keras

Keras - надстройка над Theano, предназначенная для работы с нейронными сетями.

Официальная страница: http://keras.io

В Keras входят базы примеров, например, MNIST (рукописные символы). Поэтому, Keras является хорошим средством для первых практических экспериментов с нейронными сетями.

(Также, Keras позволяет работать с TensorFlow).

Установка:

  • Windows, OSX: pip install keras
  • Linux: sudo pip install keras

Создание однослойного перцептрона

За основу взят код из главы 3 видеокурса Eder Santana, Deep Learning with Python, https://www.packtpub.com/big-data-and-business-intelligence/deep-learning-python-video

Подключение numpy и Keras

import numpy as np

from keras.datasets import mnist
from keras.models import Sequential
from keras.layers.core import Dense
from keras.utils import np_utils

from keras.models import Sequential
from keras.layers.core import Dense

Загрузка обучающих и тестовых примеров из MNIST

nb_classes = 10

# the data, shuffled and split between tran and test sets
(X_train, y_train), (X_test, y_test) = mnist.load_data()

X_train = X_train.reshape(60000, 784)
X_test = X_test.reshape(10000, 784)
X_train = X_train.astype("float32")
X_test = X_test.astype("float32")
X_train /= 255
X_test /= 255
print(X_train.shape[0], 'train samples')
print(X_test.shape[0], 'test samples')

# convert class vectors to binary class matrices
Y_train = np_utils.to_categorical(y_train, nb_classes)
Y_test = np_utils.to_categorical(y_test, nb_classes)

Обратите внимание на приведение значений яркостей из диапазона 0..255 в [0,1]:

X_train /= 255

X_test /= 255

Создание сети - однослойного перцептрона

Создадим однослойный перцептрон в Keras. Входные примеры базы MNIST являются изображениями 28x28 пикселей, которые преобразованы в вектора длины 784. Мы создаем слой, состоящий из 10 нейронов, в котором каждый нейрон связян со всеми входами. Такие слои в Keras называются "Dense". Мы задаём функцию активации выходного слоя - softmax, которая применяется для задач классификации. То есть, на выходе будет выдаваться 10 неотрицательных чисел, сумма которых равна 1, которые характеризуют вероятности того, что входное изображение является цифрой 0,1,...9.

model = Sequential()
model.add(Dense(output_dim=nb_classes, input_dim=784, activation='softmax'))

model.summary() #Print model info

Функция model.summary() выдаст информацию о слоях сети и общем числе параметров:

Layer (type)                     Output Shape          Param #     Connected to                     
====================================================================================================
dense_8 (Dense)                  (None, 10)            7850        dense_input_5[0][0]              
====================================================================================================
Total params: 7850

То есть, у сети 7850 параметров, что складывается из 784*10 - веса от каждого входа к каждому нейрону, плюс 10 значений сдвига (bias) (? требуется уточнение)

Компиляция модели

Теперь, скомпилируем модель. Это значит, что мы построим функцию Python, которая позволит вычислять результат работы сети на входном векторе, вызывая функцию model.predict(...). Но, главное, посчитается функция вычисления градиента функции ошибки по весам сети, что необходимо для осуществления обучения (настройки) параметров сети. (Эти вычисления делаются с помощью Theano):

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

Здесь 'adam' - тип градиентного спуска, 'categorical_crossentropy' - функция штрафа, кроссэнтропия, которую следует использовать для задач классификации, как у нас, metrics=['accuracy'] значит, что мы будем вычислять в модели не только функцию штрафа, но и точность работы, то есть, число правильно классифицированных примеров.

Обучение сети

Это самая ресурсоемкая операция. Мы выполняем обучение "пачками" (mini-batch) по batch_size=128 примеров. При этом, осуществляет nb_epoch=5 проходов по всем входным примерам.

(Другие варианты режима обучения:

  • по одному примеру - медленная сходимость, и алгоритм "не видит" хороших минимумов,
  • по всем примерам сразу - трудоемко, и сходимость к локальному минимуму и склонностьк переобучению.

А обработка mini-batch - промежуточный вариант, который называется градиентным стохастическим спуском)

model.fit(X_train, Y_train, batch_size=128, nb_epoch=5, verbose=2, validation_data=(X_test, Y_test))

Выдастся информация о проходах обучения:

Train on 60000 samples, validate on 10000 samples
Epoch 1/5
0s - loss: 0.2305 - acc: 0.9363 - val_loss: 0.2667 - val_acc: 0.9280
Epoch 2/5
0s - loss: 0.2298 - acc: 0.9366 - val_loss: 0.2691 - val_acc: 0.9276
Epoch 3/5
0s - loss: 0.2296 - acc: 0.9366 - val_loss: 0.2693 - val_acc: 0.9286
Epoch 4/5
0s - loss: 0.2296 - acc: 0.9367 - val_loss: 0.2688 - val_acc: 0.9289
Epoch 5/5
0s - loss: 0.2292 - acc: 0.9370 - val_loss: 0.2707 - val_acc: 0.9267

Здесь loss - функция ошибки, acc - точность на обучающей выборке, val_loss и val_acc - на тестовой выборке.

Видим, что точность на тестовой выборке получилась val_acc: 0.9267, то есть, 92.67%.

Запись и считывание из файла

Модель можно записывать и считывать из файла в формате HDF5 https://keras.io/getting-started/faq/#how-can-i-save-a-keras-model

  • model.save("my_model.h5") - запись в файл структуры модели и весов
  • model = keras.models.load_model("my_model.h5") - считывание из файла структуры модели и весов и компиляция

Тестирование модели

Хотя на этапе обучения выдавалась информация о точности на тестовой выборке, при использовании готовой модели, считанной из файла, нужно уметь проверять ее точность работы (возможно, на других тестовых выборках). Для этого следует применять функцию model.evaluate:

score = model.evaluate(X_test, Y_test,verbose=0)
#print('Test score:', score[0])
print('Test accuracy:', score[1])

Выдастся результат

('Test accuracy:', 0.92669999999999997)

Эксперименты с однослойной сетью

Увеличение числа прогонов

Если осуществить 20 обучающих прогонов (nb_epoch=20), то точность получится 92.62%. То есть, для однослойного перцептрона, увеличение числа прогонов не улучшает точность работы (была 92.66%).

Выключение нормализации входных данных

Закомментируем нормализацию входных яркостей:

#X_train /= 255
#X_test /= 255

Тогда, процесс обучение сходится гораздо хуже (была 92.66%):

  • на 5 обучающих прогонах точность 66.22%
  • на 20 обучающих прогонах точность 66.69%

То есть, точность с 92% упала до 66%, при этом, увеличение количества прогонов не улучшает ситуацию.

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

X_train /= 255
X_test /= 255

Двуслойный перцептрон

Создадим теперь сеть с двумя "плотными" слоями.

  • Первый слой ("скрытый слой") будет состоять из 100 нейронов, соединенных со всеми входами. Функция активации будет 'relu' - это самая популярная функция активации для скрытых слоев.
  • Второй слой будет состоять из 10 нейронов с функцией активации 'softmax'.
model = Sequential()
model.add(Dense(output_dim=100, input_dim=784, activation='relu'))
model.add(Dense(output_dim=nb_classes, activation='softmax'))

В этом случае, у сети будет уже 79510 параметров (в однослойном случае было 7850), а точность работы существенно возрастет 97.07% (в однослойном случае была 92.66%).

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

Создадим теперь сеть с тремя плотными слоями.

Трехслойный перцептрон

Добавим еще один скрытый слой из 200 нейронов после первого слоя двуслойной сети

model = Sequential()
#model.add(Dense(output_dim=100, input_dim=784, activation='relu'))
#model.add(Dense(output_dim=200, activation='relu'))
#model.add(Dense(output_dim=nb_classes, activation='softmax'))

В такой сети будет 100710 параметров, а точность работы 97.74%.

Выводы

Мы получили следующие результаты:

  • Однослойная сеть: 7850 параметров, точность 92.66%
  • Двуслойная сеть: 79510 параметров, точность 97.07%
  • Трехслойная сеть: 100710 параметров, точность 97.74%

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

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