Компьютерное зрение, машинное обучение, нейронные сети и т.п.
Про обычные и свёрточные нейронные сети. Почему свёрточные нейронные сети хороши для работы с изображениями. И немного о датасете MNIST.
MNIST
Начнём с того, что разберёмся с датасетом MNIST, на котором мы потом будем сравнивать обычные и свёрточные сети.
MNIST — это один из классических датасетов на котором принято пробовать всевозможные подходы к классификации (и не только) изображений. Набор содержит 60’000 (тренировачная часть) и 10’000 (тестовая часть) черно-белых изображений размера $28 imes 28$ пикселей рукописных цифр от 0 до 9. В TensorFlow есть стандартный скрипт для скачивания и развёртывания этого датасета и соответственно подгрузки данных в тензоры, что весьма удобно. Обычно для тренировки выбирается 55’000 изображений, а еще 5’000 откладывается для уточнения гиперпараметров. Таким образом для тренировки мы имеем $28 cdot 28 cdot 55’000 = 43’120’000$ пикселей.
Можно ознакомиться со списком классификаторов и результатами их работы на MNIST. Видно, что лучший на данный момент результат ошибается всего на 21 изображении из 10’000. Мы этого результата в данном рассказе не достигнем, поскольку нас интересует немного другое.
Обычные нейронные сети
Задача наша выглядит следующим образом. Нам надо натренировать сеть, на тренировочной часте набора, которая бы умела классифицировать черно-белое изображение размера $28 imes 28$ и определять цифру на изображении. Затем мы будем оценивать качество используя тестовую часть набора, т.е. считать какой процент изображений из 10’000 сеть правильно классифицировала.
Простая нейронная сеть
Первый вариант совсем простая сеть, на входе $784 = 28 cdot 28$ нейрона, каждый подключен к одному из пикселей изображения. На выходе слой с 10-ю нейронами по одному на цифру.
Соответственно, каждый из 10 выходов формируется как линейная комбинация 784 входов:
Таким образом, модель имеет $784 cdot 10 + 10 = 7850$ параметров, которые надо натренировать
Замечание
Безразлично как именно подключать пиксели к входному слою, т.е. в каком порядке выбирать их из изображения, единственно, что важно зафиксировать порядок на протяжении тренировки и тестирования.
Нейронная сеть с одним скрытым слоем.
Улучшим предыдущую модель добавив один скрытый слой с ReLU в качестве функции активации. Количество нейронов в этом скрытом слое, мы будем менять: $H = 128, 256, 512, 1024, 2046$.
Количество параметров у модели зависит от числа нейронов в скрытом слое по формуле:
Свёрточные нейронные сети
Свёрточная нейронная сеть, как следует из названия, вместо обычных слоёв использует оператор свёртки. Т.е. в данном случае мы будем использовать наши знания о структуре исходных данных. Поэтому подавать пиксели в произвольном порядке, как мы делали раньше, уже нельзя. На вход мы отправляем матрицу, соотвественно, пространственно близкие пиксели обрабатываются одним оператором свёртки.
Оператор свёртки с ядром $K(i,j)$, $i=0,…,(N-1)$, $j=0,…,(M-1)$, получая на вход изображение $I(p,q)$ (в нашем случае матрицу 28 x 28), на выходе формирует матрицу $L(p,q)$:
Для многоканального изображения $I(p, q, c)$ (или просто трехмерной матрицы) используется трехмерное ядро свёртки $K(i, j, c)$:
В нашем случае, мы будем снова использовать ReLU как функцию активацию и добавим свободный член для нормализации, т.е. у нас будет:
Так же мы в нашей свёрточной сети будем использовать оператор MaxPool, для которого определяются два параметра: размер ядра ($M imes N$) и сдвиг ($D_x imes D_y$):
Такой оператор уменьшает пространственные размеры матрицы в $D_x$ раз по горизонтали и в $D_y$ раз по вертикали.
Первый пример свёрточной нейронной сети
Первая свёрточная сеть, которую мы рассмотрим будет иметь следующую структуру:
Увеличить схему
Вначале мы применяем 20 свёрточных операторов с ядром $5 imes 5$, и получаем из изображения $28 imes 28 imes 1$ трёхмерную матрицу $28 imes 28 imes 20$. Затем используем оператор MaxPool и уменьшаем размеры матрицы к $14 imes 14 imes 20$. Еще 20 свёрточных операторов с ядром $5 imes 5 imes 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). Количество параметров у сети увеличится:
Результаты экспериментов
Все сети тренировались 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

Это руководство поможет очень быстро создать простую сверточную нейронную сеть (CNN). Такие нейросети обычно используются для классификации изображений. Библиотека Keras, написанная на языке Python, позволяет создать CNN без каких-либо сложностей.
Компьютеры «видят» изображения с помощью пикселей. Пиксели в изображениях обычно связаны друг с другом. Например, определенная группа пикселей может означать край какого-то объекта или его определенную деталь. Сверточные нейросети используют этот принцип для распознавания изображений.
CNN перемножает матрицу пикселей с матрицей фильтров («ядром») и суммирует значения умножения. После чего переходит к следующему пикселю и повторяет этот процесс до тех пор, пока все пиксели не будут покрыты. Этот процесс показан на схеме ниже.

В данном руководстве мы будем использовать популярную базу данных MNIST. Она состоит из 70 000 изображений рукописных цифр от 0 до 9. Мы попытаемся идентифицировать их с помощью нейросети.
Загрузка базы данных
Базу данных MNIST легко загрузить – она предоставляется в рамках библиотеки Keras. Среди 70 000 изображений датасета 60 000 даются для обучения и 10 000 – для тестирования.
В загруженной базе данных матрицы X_train и X_test будут содержать изображения, а y_train и y_test – цифры, которые эти изображения обозначают.

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

По умолчанию размер каждого изображения в базе MNIST – 28 × 28. При использовании реальных баз данных вам может так не повезти. 28 × 28 – это довольно маленький размер, поэтому CNN сможет проверить каждое изображение довольно быстро.
Предварительная обработка данных
Нам нужно переформатировать исходные параметры базы данных (X_train и X_test) в ту форму, которая требуется для обучения модели. Первое число – это количество изображений (60 000 для X_train и 10 000 для X_test). После этого идет размер каждого изображения (28 × 28). Последнее число – 1, оно обозначает, что изображения черно-белые.

Нам нужна «горячая кодировка» нашей целевой переменной. Это означает, что для каждой категории вывода будет создан столбец, а каждой категории ввода будет присвоена двоичная переменная. К примеру, мы видим, что первое изображение – это 5. Значит, шестому числу в массиве будет присвоена 1, а остальное пространство будет заполнено 0.

Построение модели
Мы готовы строить свою модель. Вот ее код:

Мы будем использовать модель последовательного типа. Такие модели в Keras строить проще всего. Этот метод позволяет выстраивать модель послойно. Для добавления слоев используем функцию «add()».
Первые 2 слоя – Conv2D. Эти сверточные слои будут работать с входными изображениями, которые рассматриваются как двумерные матрицы.
64 и 32 – это количество узлов в первом и втором слое соответственно. Это количество можно увеличить или уменьшить в зависимости от размера базы данных. В нашем случае отлично подходят 64 и 32, поэтому эти параметры оставляем.
«Kernel size» (размер ядра) – это размер матрицы фильтра для нейросети. Размер ядра 3 означает матрицу фильтров 3 × 3. Вернитесь к вступлению и схеме в начале, чтобы освежить эти знания.
«Activation» – это функция активации для слоя. Функция активации, которую мы будем использовать для первых двух слоев, называется ReLU (Rectified Linear Activation). Она доказанно хорошо работает в нейросетях.
Первый слой принимает входную форму. Это форма каждого входного изображения – 28,28,1, как указывалось ранее. Число 1 здесь обозначает, что изображения черно-белые.
Между сверточными слоями Conv2D и слоем пулинга (Dense) находится слой выравнивания (Flatten). Он служит соединительным узлом между слоями.
Слой пулинга мы будем использовать для выходных данных. Это стандартный тип слоя, который часто используется в нейронных сетях.
В нашем выходном слое будет 10 узлов, по одному для каждого вероятного исхода (0-9).
«Softmax» – это функция активации. Она сводит получившуюся сумму к 1, чтобы результат мог интерпретироваться как ряд возможных исходов. Тогда модель будет делать прогноз на основании того, какой вариант наиболее вероятен.
Компиляция модели
Для компиляции модели используются три параметра: оптимизатор (optimizer), потери (loss) и показатели (metrics).
Оптимизатор контролирует скорость обучения. В качестве оптимизатора мы будем использовать «adam». Скорость обучения определяет, как быстро рассчитываются оптимальные веса для модели. При меньшей скорости веса будут определяться более точно (до определенного предела), но времени при этом будет затрачено больше.
Для функции потерь мы будем использовать «categorical_crossentropy». Это наиболее распространенный выбор для классификации. Более низкая оценка показывает, что модель работает лучше.
Чтобы упростить интерпретацию, мы будем использовать метрику «точность» (accuracy), чтобы увидеть оценку точности при валидации во время обучения модели.

Обучение модели
Для обучения используем функцию «fit()» со следующими параметрами: данные обучения (train_X), целевые данные (train_y), данные валидации и количество эпох.
Для данных валидации мы будем использовать набор тестов, который уже есть в базе данных (X_test и y_test).
Количество эпох – это количество циклов обработки моделью данных. Чем больше эпох мы задаем, тем больше модель будет улучшаться. Но улучшение будет происходить до определенного уровня и затем остановится. Для нашей модели установим число эпох, равное 3.

После трех эпох при валидации мы получаем показатель точности 97,57%, и для начала это хороший результат. Поздравляем – вы построили сверточную нейросеть!
Использование модели для предсказаний
Если вы хотите увидеть настоящие предсказания, которые модель делает для тестовых данных, используйте функцию прогнозирования (predict function). Функция прогнозирования даст массив с 10 цифрами. Они обозначают вероятность того, что входное изображение представляет какую-либо цифру от 0 до 9. Цифра с наибольшим значением и будет предсказанием модели. Сумма вероятностей для всего массива равна 1 (поскольку каждое число является вероятностью).
Чтобы наглядно это показать, посмотрим на предсказания для первых четырех изображений из базы данных.
Примечание: необязательно работать с тестовыми данными – вы можете ввести в функцию предсказания свои данные.

Как видим, модель предсказала значения 7, 2, 1 и 0 для первых четырех изображений. Сравним это с настоящими результатами.

Настоящие результаты показывают, что первые четыре изображения действительно содержат цифры 7, 2, 1 и 0 – модель предсказала все верно!
Репозиторий проекта на GitHub смотрите здесь.
Наконец то мы продолжим писать нейронные сети на Питоне. Сегодня мы познакомимся с сверточными сетями. Будем опять распознавать рукописные цифры из базы MNIST. В сверточные сети так же входит полносвязная сеть, например персептрон. По этому читаем первую статью.
Немного теории.
Свёрточная нейронная сеть (англ.convolutional neural network, CNN) — специальная архитектура искусственных нейронных сетей, предложенная Яном Лекуном в 1988 году и нацеленная на эффективное распознавание образов, Использует некоторые особенности зрительной коры, в которой были открыты так называемые простые клетки, реагирующие на прямые линии под разными углами, и сложные клетки, реакция которых связана с активацией определённого набора простых клеток.
Свёрточными сети называются так из за операции свертки, которая является основой всей сети. В этих сетях нету привычных связей и весовых коэффициентов. Вместо этого используется ядро свертки размером от 3х3 до 7х7. Операция свертки выделяет какой то признак в картинке, например переход от светлого пикселя к темному. Признаки зависят от ядра. Например в базе MNIST наши рукописные цифры это черно-белая картинка размером 28х28 (каждый пиксель имеет значения яркости от 0 до 255). По этой матрице мы проходим ядром и производим операцию свертки. После этого мы получаем слой свертки ( обычно такового размера , но бывает что большего или меньшего) или карту признака.
Автор: Michael Plotke
Следующая операция Пулинг . Это как бы сжатие картинки или слоя свёртки по максимум или среднему значению, при этом группа пикселей (обычно размера 2×2) уплотняется до одного пикселя. По факту мы увеличиваем область которую захватывает ядро свертки в два раза. Переходя от маленьких деталей изображения к более крупным. Так же пулингом мы объединяем карты признаков (полученные сверткой) в более абстрактные признаки, уже не пиксела , а черточки и т.д.
Автор: Aphex34
Keras. Создаем сеть.
Keras — открытая нейросетевая библиотека, написанная на языке Python. Она представляет собой надстройку над фреймворками TensorFlow, упрощая работу с последним.
TensorFlow — открытая программная библиотека для машинного обучения, разработанная компанией Google для решения задач построения и тренировки нейронной сети с целью автоматического нахождения и классификации образов, достигая качества человеческого восприятия.
Первым делом ставим TensorFlow , потом Keras. Далее нам надо будет понизить ваш numpy до 1.16.4.
База MNIST уже есть в данных нашей библиотеки, загружаем базу:
Функция reshape() изменяет форму массива без изменения его данных.
Тестовые данные нам тоже надо преобразовать.
Построение модели сети.
Теперь у нас все готово к построению нашей нейро-сети.
Первый слой будет сверточный двухмерный ( Conv2D ) . Эти сверточные слои будут работать с входными изображениями, которые рассматриваются как двумерные матрицы. kernel_size =3 — размер ядра 3х3. Функция активации ‘relu’ ( Rectified Linear Activation ) , 64 это число ядер свертки( сколько признаком будем искать)
Flatten() – слой, преобразующий 2D-данные в 1D-данные.
Dense() — полносвязный слов, число выходов — 10 , функция активации ‘softmax’ .
Далее, нам нужно скомпилировать нашу модель. Компиляция модели использует три параметра: оптимизатор, потери и метрики.
Оптимизатор весов optimizer=’adam’ (Адам: метод стохастической оптимизации). Функция потерь : loss=’categorical_crossentropy’ категориальная перекрестная энтропия (categorical crossentropy CCE). Последний параметр я не очень понял что такое :
metrics: List of metrics to be evaluated by the model during training and testing. Typically you will use metrics=[‘accuracy’] . To specify different metrics for different outputs of a multi-output model, you could also pass a dictionary, such as metrics= <‘output_a’: ‘accuracy’>.
Теперь запускаем обучение сети :
epochs=1 число эпох , val > — проверочные данные
Визуализация, эксперименты, сохранение.
Давайте построим графики обучения для наглядности. Благо метод fit() возвращает историю обучения.
Добавим слой Пулинг по Максимуму, и запустим на 10 эпох. Так же поменяем функцию ошибки и оптимизации.
Сохранение / загрузка целых моделей (архитектура + веса + состояние оптимизатора)
Вы можете использовать model.save(filepath) для сохранения модели Keras в один файл HDF5, который будет содержать:
- архитектура модели, позволяющая воссоздать модель
- весовые коэффициенты модели
- конфигурация обучения (потеря, оптимизатор)
- состояние оптимизатора, позволяющее возобновить тренировку именно там, где вы остановились.
Использование GPU.
Если вы работаете на TensorFlow или CNTK backends, ваш код автоматически запускается на GPU, если обнаружен какой-либо доступный GPU.
- tensorflow —Latest stable release for CPU-only
- tensorflow-gpu —Latest stable release with GPU support (Ubuntu and Windows)
Я думаю у вас еще много вопросов, но к сожаления разобраться со всем в одной статье очень трудно. Изучайте в месте со мной официальную документацию и экспериментируйте ))










