Шаг 26.
Глубокое обучение на Python.
Математические основы нейронных сетей. Первое знакомство с нейронной сетью

    На этом шаге мы рассмотрим построение простой нейронной сети.

    Рассмотрим конкретный пример нейронной сети, которая обучается классификации рукописных цифр и создана с помощью библиотеки Keras для Python. Если у вас нет опыта использования Keras или других подобных библиотек, возможно, вы не все здесь поймете. Но пусть вас это не пугает. В дальнейшем мы рассмотрим и подробно объясним каждый элемент в примере.

    Перед нами стоит задача: реализовать классификацию черно-белых изображений рукописных цифр (28 * 28 пикселей) по десяти категориям (от 0 до 9). Мы будем использовать набор данных MNIST, популярный в сообществе исследователей глубокого обучения, который существует практически столько же, сколько сама область машинного обучения, и широко используется для обучения. Этот набор содержит 60 000 обучающих изображений и 10 000 контрольных изображений, собранных Национальным институтом стандартов и технологий США (National Institute of Standards and Technology - часть NIST в аббревиатуре MNIST) в 1980-х годах. "Решение" задачи MNIST можно рассматривать как своеобразный аналог Hello World в глубоком обучении - часто это первое действие, которое выполняется для уверенности, что алгоритмы действуют в точности как ожидалось. По мере углубления в практику машинного обучения вы увидите, что MNIST часто упоминается в научных статьях, блогах и т. д. Некоторые образцы изображений из набора MNIST можно видеть на рисунке 1.


Рис.1. Образцы изображений MNIST


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

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

    Набор данных MNIST уже входит в состав Keras в форме набора из четырех массивов NumPy.


Пример 2.1. Загрузка набора данных MNIST в Keras
from tensorflow.keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

    Здесь train_images и train_labels - это обучающий набор, то есть данные, на которых модель обучается. После обучения модель будет проверяться тестовым (или контрольным) набором, test_images и test_labels.

    Изображения хранятся в массивах NumPy, а метки - в массиве цифр от 0 до 9. Изображения и метки находятся в прямом соответствии, один к одному.

    Рассмотрим обучающие данные:

>>> train_images.shape(60000, 28, 28)
>>> from tensorflow import keras
>>> len(train_labels)
60000
>>> train_labels
[5 0 4 ... 5 6 8]

    И контрольные данные:

>>> test_images.shape(10000, 28, 28)
>>> len(test_labels)
10000
>>> test_labels
[7 2 1 ... 4 5 6]

    Вот как мы будем действовать дальше: сначала передадим нейронной сети обучающие данные, train_images и train_labels. Сеть обучится подбирать правильные метки для изображений. А затем мы предложим ей классифицировать изображения в test_images и проверим точность классификации по меткам из test_labels.

    Теперь сконструируем сеть.


Пример 2.2. Архитектура сети
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
    layers.Dense(512, activation="relu"),
    layers.Dense(10, activation="softmax")
])

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

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

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

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

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


Пример 2.3. Этап компиляции
model.compile(optimizer="rmsprop",
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy"])

    Перед обучением мы выполним предварительную обработку данных, преобразовав в форму, которую ожидает получить нейронная сеть, и масштабируем их так, чтобы все значения оказались в интервале [0, 1]. Исходные данные - обучающие изображения - хранятся в трехмерном массиве (60000, 28, 28) типа uint8, значениями в котором являются числа в интервале [0, 255]. Мы преобразуем его в массив (60000, 28 * 28) типа float32 со значениями в интервале [0, 1].


Пример 2.4. Подготовка исходных данных
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype('float32') / 255

    Теперь можно начинать обучение сети, для чего в случае библиотеки Keras достаточно вызвать метод fit() модели - он попытается адаптировать (fit) модель под обучающие данные.


Пример 2.5. Обучение ("адаптация") модели
>>> model.fit(train_images, train_labels, epochs=5, batch_size=128)
Epoch 1/5
60000/60000 [==============================] - 9s - loss: 0.2524 - acc: 0.9273
Epoch 2/5
51328/60000 [========================>	] - ETA: 1s - loss: 0.1035 - acc: 0.9692

    В процессе обучения отображаются две величины: потери сети на обучающих данных и точность сети на обучающих данных. Мы быстро достигли точности 0,989 (98,9 %).

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


Пример 2.6. Использование модели для получения предсказаний
>>> test_digits = test_images[0:10]
>>> predictions = model.predict(test_digits)
>>> predictions[0]
array([1.0726176e-10, 1.6918376e-10, 6.1314843e-08, 8.4106023e-06,
2.9967067e-11, 3.0331331e-09, 8.3651971e-14, 9.9999106e-01,
2.6657624e-08, 3.8127661e-07], dtype=float32)

    Каждое число в элементе массива с индексом i соответствует вероятности принадлежности изображения цифры test_digits[0] к классу i.

    Наивысшая оценка вероятности (0,99999106 - почти 1) для этого тестового изображения цифры находится в элементе с индексом 7, то есть согласно нашей модели - перед нами изображение цифры 7:

>>> predictions[0].argmax()
7
>>> predictions[0][7]
0.99999106

    Прогноз можно проверить по массиву меток:

>>> test_labels[0]
7

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


Пример 2.7. Оценка качества модели на новых данных
>>> test_loss, test_acc = model.evaluate(test_images, test_labels)
>>> print(f"test_acc: {test_acc}") 
test acc: 0.9785

    Точность на контрольном наборе составила 97,8% - немного меньше, чем на обучающем (98,9%) . Эта разница демонстрирует пример переобучения (overfitting), когда модели машинного обучения показывают точность на новом наборе данных худшую, чем на обучающем.

    На этом мы завершаем наш первый пример - вы только что увидели, как создать и обучить нейронную сеть классификации рукописных цифр, написав меньше 15 строк кода на Python. Далее мы подробнее остановимся на всех встретившихся здесь деталях. Вы узнаете о тензорах, объектах хранения данных в сети; об операциях с тензорами, выполняемых слоями; о градиентном спуске, позволяющем сети совершенствоваться на учебных примерах.

    На следующем шаге мы рассмотрим подготовку данных для нейронных сетей.




Предыдущий шаг Содержание Следующий шаг