MNIST, нейронные сети и свёрточные нейронные сети
Про обычные и свёрточные нейронные сети. Почему свёрточные нейронные сети хороши для работы с изображениями. И немного о датасете MNIST.
MNIST
Начнём с того, что разберёмся с датасетом MNIST, на котором мы потом будем сравнивать обычные и свёрточные сети.
MNIST - это один из классических датасетов на котором принято пробовать всевозможные подходы к классификации (и не только) изображений. Набор содержит 60’000 (тренировачная часть) и 10’000 (тестовая часть) черно-белых изображений размера $28 \times 28$ пикселей рукописных цифр от 0 до 9. В TensorFlow есть стандартный скрипт для скачивания и развёртывания этого датасета и соответственно подгрузки данных в тензоры, что весьма удобно. Обычно для тренировки выбирается 55’000 изображений, а еще 5’000 откладывается для уточнения гиперпараметров. Таким образом для тренировки мы имеем $28 \cdot 28 \cdot 55’000 = 43’120’000$ пикселей.
Можно ознакомиться со списком классификаторов и результатами их работы на MNIST. Видно, что лучший на данный момент результат ошибается всего на 21 изображении из 10’000. Мы этого результата в данном рассказе не достигнем, поскольку нас интересует немного другое.
Обычные нейронные сети
Задача наша выглядит следующим образом. Нам надо натренировать сеть, на тренировочной часте набора, которая бы умела классифицировать черно-белое изображение размера $28 \times 28$ и определять цифру на изображении. Затем мы будем оценивать качество используя тестовую часть набора, т.е. считать какой процент изображений из 10’000 сеть правильно классифицировала.
Простая нейронная сеть
Первый вариант совсем простая сеть, на входе $784 = 28 \cdot 28$ нейрона, каждый подключен к одному из пикселей изображения. На выходе слой с 10-ю нейронами по одному на цифру.
Соответственно, каждый из 10 выходов формируется как линейная комбинация 784 входов:
\[y_i = \sum_{j=0}^{783} W_{ij}*x_j + b_i, i=0,1,...,9\]Таким образом, модель имеет $784 \cdot 10 + 10 = 7850$ параметров, которые надо натренировать
Замечание
Безразлично как именно подключать пиксели к входному слою, т.е. в каком порядке выбирать их из изображения, единственно, что важно зафиксировать порядок на протяжении тренировки и тестирования.
Нейронная сеть с одним скрытым слоем.
Улучшим предыдущую модель добавив один скрытый слой с ReLU в качестве функции активации. Количество нейронов в этом скрытом слое, мы будем менять: $H = 128, 256, 512, 1024, 2046$.
Получаем формулы:
\[h_i = {\rm ReLU}\left( \sum_{j=0}^{783} W^{(h)}_{ij}*x_j + b^{(h)}_i\right), i = 0,1,...,(H-1)\] \[y_i = \sum_{j=0}^{H-1} W^{(y)}_{ij}*h_j + b^{(y)}_i, i = 0,1,...,9\]Количество параметров у модели зависит от числа нейронов в скрытом слое по формуле:
\[784 \cdot H + H + H \cdot 10 +10 = 794 \cdot H + 10\]Свёрточные нейронные сети
Свёрточная нейронная сеть, как следует из названия, вместо обычных слоёв использует оператор свёртки. Т.е. в данном случае мы будем использовать наши знания о структуре исходных данных. Поэтому подавать пиксели в произвольном порядке, как мы делали раньше, уже нельзя. На вход мы отправляем матрицу, соотвественно, пространственно близкие пиксели обрабатываются одним оператором свёртки.
Оператор свёртки с ядром $K(i,j)$, $i=0,…,(N-1)$, $j=0,…,(M-1)$, получая на вход изображение $I(p,q)$ (в нашем случае матрицу 28 x 28), на выходе формирует матрицу $L(p,q)$:
\[L(p,q) = \sum_{n=0}^{N-1} \sum_{m=0}^{M-1} K(n, m) \cdot I(p+n-N/2, q+m-M/2)\]Для многоканального изображения $I(p, q, c)$ (или просто трехмерной матрицы) используется трехмерное ядро свёртки $K(i, j, c)$:
\[L(p,q) = \sum_c \sum_{n=0}^{N-1} \sum_{m=0}^{M-1} K(p, q, c) \cdot I(p+n-N/2, q+m-M/2, c)\]В нашем случае, мы будем снова использовать ReLU как функцию активацию и добавим свободный член для нормализации, т.е. у нас будет:
\[L'(p,q) = {\rm ReLU}\left(\sum_c \sum_{n=0}^{N-1} \sum_{m=0}^{M-1} K(p, q, c) \cdot I(p+n-N/2, q+m-M/2, h) + b\right)\]Так же мы в нашей свёрточной сети будем использовать оператор MaxPool, для которого определяются два параметра: размер ядра ($M \times N$) и сдвиг ($D_x \times D_y$):
\[M(p,q,c) = \max\{I(i,j,c) | i=D_x \cdot p,..., (D_x \cdot p + M); j=D_y \cdot q, ..., (D_y \cdot q + N)\}\]Такой оператор уменьшает пространственные размеры матрицы в $D_x$ раз по горизонтали и в $D_y$ раз по вертикали.
Первый пример свёрточной нейронной сети
Первая свёрточная сеть, которую мы рассмотрим будет иметь следующую структуру:
Вначале мы применяем 20 свёрточных операторов с ядром $5 \times 5$, и получаем из изображения $28 \times 28 \times 1$ трёхмерную матрицу $28 \times 28 \times 20$. Затем используем оператор MaxPool и уменьшаем размеры матрицы к $14 \times 14 \times 20$. Еще 20 свёрточных операторов с ядром $5 \times 5 \times 20$ и опять MaxPool, на выходе получаем $7 \cdot 7 \cdot 20 = 980$ величин, которые линейно заводим на выходной слой с 10 нейронами.
Количество параметров у модели:
-
Параметры для свёрточных ядер первого свёрточного слоя: $5 \cdot 5 \cdot 20 + 20 = 520$.
-
MaxPool нет параметров, которые следует тренировать.
-
Параметры для свёрточных ядер второго свёрточного слоя: $5 \cdot 5 \cdot 20 \cdot 20 + 20 = 10’020$.
-
Параметры полносвязного слоя: $980 \cdot 10 + 10 = 9’810$
Всего получаем $520 + 10’020 + 9’810 = 20’350$ параметров.
Второй пример свёрточной нейронной сети
В заключении, рассмотрим более сложную свёрточную сеть, добавив дополнительный полносвязный слой.
Cеть аналогична предыдущей и только последний MaxPool мы вначале заводим на полносвязный слой с M нейронами (M = 100). Количество параметров у сети увеличится:
\[520 + 10'020 + 980 \cdot 100 + 100 + 100 \cdot 10 + 10 =\] \[520 + 10'020 + 98'100 + 1'010 = 109'650\]Результаты экспериментов
Все сети тренировались 30 эпох с кросс-энтропией в качестве функции ошибки, с использованием AdamOptimizer и размером минибатча 100. Было проведено 10 тренировок для каждой сети, и взята средняя точность на тестовой части датасета.
сеть | кол-во коэффициентов | кол-во умножений | качество |
---|---|---|---|
простая | 7’850 | 7’840 | 92.92% |
скрытый слой 128 нейронов | 101’770 | 101’632 | 98.00% |
скрытый слой 256 нейронов | 203’530 | 203’264 | 98.23% |
скрытый слой 512 нейронов | 407’050 | 406’528 | 98.40% |
скрытый слой 1024 нейронов | 814’090 | 813’056 | 98.50% |
скрытый слой 2048 нейронов | 1’626’580 | 1’624’524 | 98.54% |
CNN версия 1 | 20’350 | 2’361’800 | 99.13% |
CNN версия 2 | 109’650 | 2’451’000 | 99.32% |
Что следует отметить:
-
Даже простая свёрточная сеть у которой до 80 раз меньше коэффициентов, выдаёт качество на ~1% лучше, чем обычная сеть.
-
Обычная сеть со скрытым слоем из 128 нейронов и свёрточная сеть версии 2 имеют одинаковое количество параметров, при этом вторая добавляет практически 1.5% качества
-
Свёрточная сеть тренируется до своей максимальной точности, намного быстрее. На примерах выше, свёрточные сети достигали максимальной точности уже после 10 эпох, а обычные сети ближе к 30-й.
-
Несмотря на уменьшение количества параметров, количество операций у свёрточной сети больше чем у обычной.
Почему свёрточная сеть лучше? Потому что нам надо тренировать существенно меньше параметров. Но при этом уменьшение количества параметров, компенсируется наложением правильной структуры. Можно ли натренировать обычную сеть до того же качества? Я думаю да, однако, для этого потребуется существенно расширить тренировочный датасет. Например, из таблицы видно, что вначале качество сети растёт вместе с ростом числа нейронов скрытого слоя, а затем этот рост практически останавливается. Мы просто не можем предоставить сети достаточно разнообразных примеров для обучения. А в случае свёрточной сети, знания полученные на одной часте изображения автоматически переносятся на другие его части.
Следует также отметить ещё один важный момент. MNIST на самом деле содержит крайне “простой” набор изображений, всего 784 вещественных числа описывают каждое из них. Если мы захотим классифицировать изображения большего размера, то количество параметров, которые надо будет натренировать возрастает кардинально, даже для свёрточной сети, для обычной оно возрастает еще больше и это приводит к проблемам с тренировкой.
Идея уменьшения количества параметров сети за счёт наложения структуры, получила развитие в статьях [1] и [2]. Однако, если свёрточные сети используют идею кластеризации по пространственному положению пикселей (а затем более сложных признаков), то в Inception сети (тоже свёрточной) осуществляется дополнительная кластеризация на другой основе. Но это большая тема для отдельной беседы.
Код с сетками и тестированием можно посмотреть на github
Литература
-
C. Szegedy, W. Liu, Y. Jia, P. Sermanet, S. Reed, D. Anguelov, D. Erhan, V. Vanhoucke, and A. Rabinovich, “Going deeper with convolutions”. arXiv:1409.4842 2014
-
C. Szegedy, V. Vanhoucke, S. Ioffe, J. Shlens, Z. Wojna, “Rethinking the Inception Architecture for Computer Vision”. arXiv:1512.00567 2015