Рисунок 1.Пример свертки двух матриц размера 5×5 и 3×3
Свертка (англ. convolution) — операция над парой матриц (размера ) и (размера ), результатом которой является матрица размера .
Каждый элемент результата вычисляется как скалярное произведение матрицы и некоторой подматрицы такого же размера (подматрица определяется положением элемента в результате).
То есть, . На Рисунке 1 можно видеть, как матрица «двигается» по матрице , и в каждом положении считается скалярное произведение матрицы и той части матрицы , на которую она сейчас наложена. Получившееся число записывается в соответствующий элемент результата.
Логический смысл свертки такой — чем больше величина элемента свертки, тем больше эта часть матрицы была похожа на матрицу (похожа в смысле скалярного произведения). Поэтому матрицу называют изображением, а матрицу — фильтром или образцом.
Структура сверточной нейронной сети
В сверточной нейронной сети выходы промежуточных слоев образуют матрицу (изображение) или набор матриц (несколько слоёв изображения). Так, например, на вход сверточной нейронной сети можно подавать три слоя изображения (R-, G-, B-каналы изображения). Основными видами слоев в сверточной нейронной сети являются сверточные слои (англ. convolutional layer), пулинговые слои (англ. pooling layer) и полносвязные слои (англ. fully-connected layer).
Рисунок 2.Пример свертки двух матриц с дополнением нулями и сдвигом 2
Сверточный слой нейронной сети представляет из себя применение операции свертки к выходам с предыдущего слоя, где веса ядра свертки являются обучаемыми параметрами. Еще один обучаемый вес используется в качестве константного сдвига (англ. bias). При этом есть несколько важных деталей:
Рисунок 4. Пример операции пулинга с функцией максимума
Пулинговый слой призван снижать размерность изображения. Исходное изображение делится на блоки размером и для каждого блока вычисляется некоторая функция. Чаще всего используется функция максимума (англ. max pooling) или (взвешенного) среднего (англ. (weighted) average pooling). Обучаемых параметров у этого слоя нет. Основные цели пулингового слоя:
Рисунок 6.Inception module с сокращением размерностей
Другие виды сверток
Данная свертка похожа на пуллинг и свертку с шагом, но позволяет:
— входные данные, — выходные, — ядро свертки, — коэффициент расширения.
Рисунок 8. 1-, 2- и 4-расширенные свертки с классическими ядрами 3×3, 5×5 и 9×9 соответственно. Красные точки обозначают ненулевые веса, остальные веса ядра равны нулю. Выделенные синие области обозначают рецептивные поля.
Частичная свертка (aнгл. Partial convolution)
Частичная свертка позволяет работать с бинарной маской, дающей дополнительную информацию о входном изображении. Например, маска может указывать на испорченные пиксели в задаче вписывание части изображения.
Значения обновляются по формуле:
— бинарная маска; — ядро свертки; — поэлементное перемножение, — гиперпараметр
Поэлементное перемножение и позволяет получить результат, зависящий только от значений с единичной маской, а служит для нормализации этого результата.
Обновление маски происходит так:
Как видно из формулы, дополнительная информация, вносимая маской, постепенно затухает при переходе от слоя к слою. То есть со временем маска полностью заполняется единицами.
Стробированная свертка (aнгл. Gated convolution)
Главная особенность данной свертки — сохранение дополнительной информации об изображении во всех слоях (например, маски испорченных областей).
В данном случае вместо того, чтобы работать с жесткой маской, которая обновляется по некоторым правилам, стробированная свертка учится автоматически извлекать маску из данных:
и — два разных ядра свертки, — входные данные, — выходные данные, — функция активации, — сигмоидная функция, — поэлементное перемножение.
Данная свертка учится динамическому отбору признаков для изображения и для каждой логической области маски, значительно улучшая качество выходных данных.
Известные архитектуры сверточных нейронных сетей
Сравнение известных нейронных сетей
Сверточная нейронная сеть (Convolutional Neural Networks, ConvNet) – класс Нейронных сетей (Neural Network), который специализируется на обработке данных, имеющих топологию в виде сетки, например изображений. Цифровое изображение – это двоичное представление визуальных данных. Он содержит серию пикселей, расположенных в виде сетки, где каждая ячейка содержит визуальные данные: яркость и цвет.
Изображение как сетка пикселей
Человеческий мозг обрабатывает огромное количество информации при просмотре изображения. Каждый нейрон работает в своем собственном рецептивном поле и связан с другими нейронами таким образом, что они покрывают все поле зрения. Подобно тому, как каждый нейрон реагирует на стимулы только в ограниченной области поля зрения, называемой рецептивным полем в системе биологического зрения, каждый нейрон в CNN также обрабатывает данные только в своем рецептивном поле. Слои расположены таким образом, что сначала они обнаруживают более простые узоры (линии, кривые и т. Д.), А затем более сложные узоры (лица, объекты и т. Д.). Используя CNN, можно обеспечить Компьютерное зрение (CV).
Архитектура
CNN обычно имеет три уровня: сверточный слой, слой объединения и полностью связанный слой:
Сверточный слой
Сверточный слой является основным строительным блоком CNN. Он несет основную часть вычислительной нагрузки сети.
Этот уровень выполняет скалярное произведение между двумя матрицами, где одна матрица представляет собой набор обучаемых параметров, иначе называемых ядром, а другая матрица – ограниченной частью воспринимающего поля. Ядро пространственно меньше изображения, но имеет бо́льшую глубину. Это означает, что если изображение состоит из трех RGB-каналов, высота и ширина ядра будут пространственно малы, но глубина распространяется на все три канала:
Во время прямого прохода ядро скользит по высоте и ширине изображения, создавая представление изображения этой рецептивной области. Это создает двумерное представление изображения, известное как карта Активации (Activation), которая дает реакцию ядра в каждой пространственной позиции изображения. Скользящий размер ядра называется шагом.Если у нас есть входные данные размером W x W x D и количество ядер с пространственным размером F с шагом S и количеством отступов P, то размер выходного слоя можно определить по следующей формуле:
Мы получим выходное разрешение Wout x Wout x Dout.
Причины сворачивания
Свертка использует три важные идеи, которые мотивировали исследователей компьютерного зрения: разреженное взаимодействие, совместное использование параметров и эквивариантное (равноценное) представление. Опишем подробно каждую из них.
Тривиальные слои нейронной сети используют результат перемножения матрицы на матрицу параметров, описывающих взаимодействие между входом и выходом. Это означает, что каждый блок вывода взаимодействует с каждым блоком ввода. Однако свёрточные нейронные сети взаимодействуют разреженно. Это достигается за счет уменьшения размера ядра по сравнению с входными данными, например, изображение может иметь миллионы или тысячи пикселей, но при его обработке с использованием ядра мы можем обнаружить значимую информацию, состоящую из десятков или сотен пикселей. Это означает, что нам нужно хранить меньше параметров, что не только снижает потребность модели в памяти, но и повышает ее статистическую эффективность.
Если вычисление одного объекта в пространственной точке (x1, y1) полезно, то оно также должно быть полезно в какой-то другой пространственной точке, например (x2, y2). Это означает, что для одного двумерного среза, то есть для создания одной карты активации, нейроны вынуждены использовать один и тот же набор весов. В традиционной нейронной сети каждый элемент матрицы весов используется один раз, а затем никогда не пересматривается, в то время как сеть свертки имеет общие параметры, то веса, применяемые к одному входу, такие же, как веса, применяемый в другом.
Благодаря совместному использованию параметров слои сверточной нейронной сети будут иметь свойство эквивалентности трансляции: если мы каким-то образом изменили входные данные, выходные также изменятся.
Слой пулинга
Слой пулинга (объединения) заменяет выходные данные сети в определенных местах, получая сводную статистику ближайших выходов. Это помогает уменьшить пространственный размер представления, что уменьшает необходимое количество вычислений и весов. Операция объединения обрабатывается отдельно для каждого фрагмента представления.
Существует несколько функций объединения, таких как среднее значение прямоугольной окрестности, норма L2 для прямоугольной окрестности и средневзвешенное значение, основанное на расстоянии от центрального пикселя. Однако самый популярный процесс – это максимальный пулинг, которое сообщает о максимальном выходе из окружения.
Если у нас есть карта активации размером W x W x D, объединяющее ядро пространственного размера F и шаг S, то размер выходного объема можно определить по следующей формуле:
Это позволит вычислить выходной объем размером Wout x Wout x D.
Во всех случаях объединение обеспечивает некоторую инвариантность трансляции, что означает, что объект будет узнаваемым независимо от того, где он появляется в кадре.
Полностью связанный слой
Нейроны в этом слое имеют полную связь со всеми нейронами предыдущего и последующего слоя, как это видно в обычном FCNN (Fully-Connected Convolutional Neural Network). Вот почему его можно вычислить как обычно, умножением матрицы с последующим эффектом смещения.
Полностью связанный cлой помогает сопоставить представление между данными на входе и выходе.
Нелинейные слои
Поскольку свертка – это линейная операция, а изображения далеки от линейности, нелинейные слои часто размещаются непосредственно после сверточного слоя, чтобы внести нелинейность в карту активации.Существует несколько типов нелинейных операций, самые популярные из которых:
Cверточная нейронная сеть и TensorFlow
CNN удобно продемонстрировать с помощью фреймворка Google TensorFlow и датасета с изображениями животных и транспорта (CIFAR-10). Нам понадобится библиотека TensorFlow Keras – это модуль для построения моделей глубинного обучения, matplotlib – это известнейшая библиотека для визуализации двумерной графики. Мы будем с вами использовать такие методы как figure(), show() и imshow(). Мы будем создавать области построения графика, отображать графики и преобразовывать набор пикселей в изображения.
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
import matplotlib
import matplotlib.pyplot as plt
Мы импортируем два набора датасетов – это тренировочный, на котором будет производиться непосредственно обучение и проверочный, валидационный. Грубо говоря, мы используем одну и ту же базу данных, разобьем ее на 2 части. Все изображения, которые мы будем использовать, любезно промаркированы для нейросети, которую мы будем обучать, поэтому мы используем train_labels.
(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()
# Нормализация значений цвета пикселей (приведем к диапазону от 0 до 1)
train_images, test_images = train_images / 255.0, test_images / 255.0
Что же такое CIFAR-10? Канадский институт перспективных исследований любезно подготовил обширную базу данных из 60 тысяч изображений объектов 10 видов. Мы сможем натренировать нашу нейронную сеть с помощью нескольких тысяч изображений лошадей, грузовиков, оленей, птиц и так далее. На самом деле, изображения размечены числами, а не словами. Это сделано для того, чтобы проще было создавать языковые версии нейронных сетей. К примеру, все изображения категории “олень” могут быть обозначены цифрой 7. Наши изображения будут описаны в цветовой модели RGB, состоящей из трех чисел в диапазоне от 0 до 255. Все пиксели изображения и мы будем описывать цветовой моделью RGB, которая обозначает цвета с помощью сочетания 3 цифр в диапазоне от 0 до 255 включительно. Для тренировки нейронной сети мы нормализуем эти числа и разделим каждый из трех значений этой цветовой модели каждого пикселя на 255. В результате мы получим набор значений от нуля до единицы. Это называется Нормализация (Normalization). С такими данными и нейронной сети будет проще взаимодействовать. Обратите внимание: знак равенства один, а операций присвоения производится две.
Как я и говорила, категории у нас обозначены числами, но мы для удобства собственного восприятия обозначим их снова словами. Зададим холст и с помощью параметра figsize обозначим его размер. Для начала отобразим двадцать пять картинок из этого датасета. Нейросеть будет действовать как фильтр. Изучив все тренировочные данные, она сможет категоризировать все последующие изображения. Создадим цикл for и отобразим двадцать пять картинок. Каждое из изображение будет “подграфиком”, то есть частью большого холста графика. Цифры 5 и 5 обозначают количество строк и столбцов на графике для подграфиков. Мы отключим отображение координат x и y, чтобы избежать перегрузки на глаза, иначе каждое из изображений будет размечено размерами. Мы также отключим сетку с помощью метода imshow() отобразим первые 25 тренировочных изображений.Мы задали псевдонимы для всех численных обозначений категорий изображений и теперь используем их для подписи на графике. Построим график.
Даже в таком скромном качестве вы легко распознаете птицу, лошадь, грузовик, автомобиль, лягушку. Представьте, что кто-то никогда не виделэти объекты. Как он узнает, что есть что икак он отличит, например, оленя от коня?Ведь у них у обоих бывают каурый окрас, есть копыта. Мы-то с вами их можем различить друг от друга, потому что многоповидали на своем веку. Так что загрузим в компьютер большую базу изображений, чтобы он тоже научился отличать эти предметы друг от друга. Эти изображения мы будем раскладывать на многомерные тензоры. Каждое из этих изображений мы представимкак последовательностьпикселей, описываемых с помощью нормализованной модели RGB.
Поскольку наше изображение размером 32 на 32 пикселя, то это будет 1024 пикселя 60 тысяч изображений. Для таких длинных последовательностей тензоров нам понадобится Keras. Этот высокоуровневый интерфейс как нельзя лучше подходит для подобных последовательностей. Мы будем использовать объект Sequential() этого API, который позволит нам привести данные к формату Keras. Создадим модель. используя метод Sequential(),не принимающий аргументов, добавим модель слой свёрточной нейронной двумерной сети. Смотрите, как происходит добавление слоя. модель мы добавляем функции-фильтры, на самом деле их 128 в данном примере, которые будут вычислять собственные параметры автоматически на базе тренировочных изображений. Эти функции в конечном итоге будут производить категоризацию валидационных изображений, чтобы очистить тензоры от нецветовых значений, которые не удалось нормализовать, то есть привести к размеру от 0 до 255 и используется параметр reLU – это метод активации, который просто отсечёт часть тендзора, которая не является числом в диапазоне от нуля до единицы. Так мы получим набор только цветовых обозначений пикселов и с помощью параметра input_shape мы определяем, какого размера наше изображение, с помощью какой цветовой модели она обозначается. Для уменьшения объемов выходных данных мы будем использовать пулинг и метод MaxPooling2D(): так последовательно мы добавляем фильтр, на сей раз их 64; прочие параметры остаются теми же. И последний этап добавления функции фильтров, на сей раз их 128 с такими же параметрами активации.
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation = ‘relu’, input_shape = (32, 32, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation = ‘relu’))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation = ‘relu’))
Запросим сводку модели:
Пока числа не очень информативны; в ходе дальнейших преобразований мы увидим, как меняется число параметров каждого их 6 слоев.
Model: “sequential”
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 30, 30, 32) 896
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 15, 15, 32) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 13, 13, 64) 18496
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 6, 6, 64) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 4, 4, 64) 36928
=================================================================
Total params: 56,320
Trainable params: 56,320
Non-trainable params: 0
Теперь преобразуем набор пикселей изображения размером 32 на 32 в двумерный массив, выстроим их как бы в ряд. В этом нам поможет метод Flatten(), не принимающий аргументов. К тому моменту как мы выстроили все пиксели изображения в одномерный массив, нейросеть содержит два полносвязных слоя. Каждый узел содержит оценку, указывающую вероятность принадлежностей изображений к одному из 10 классов.
Мы добавили полносвязные слои с таким же методом активации, снова изучим сводку.
Слои, добавленные на предыдущем этапе, остались неизменными; добавились уплощенный и плотные слои.
Model: “sequential”
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 30, 30, 32) 896
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 15, 15, 32) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 13, 13, 64) 18496
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 6, 6, 64) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 4, 4, 64) 36928
_________________________________________________________________
flatten (Flatten) (None, 1024) 0
_________________________________________________________________
dense (Dense) (None, 64) 65600
_________________________________________________________________
dense_1 (Dense) (None, 10) 650
=================================================================
Total params: 122,570
Trainable params: 122,570
Non-trainable params: 0
_________________________________________________________________
Количество параметров увеличилось. Соберем модель, для этого нам понадобится функция-оптимизатор и функция потери. Первое: поскольку нейросеть инициализируется со случайными значениями, то функция-оптимизатор переопределяет параметры тех самых 128 функций-фильтраторов, и с помощью функции потери измеряется точность распознавания тестовых изображений. Эй-ди-эй-эм (Adam) – это такой метод оптимизации, погружаться не будем в него. Параметр metrics позволит нам определить как часто нейронная сеть правильно категоризирует изображение относительно их настоящих Ярлыков (Label). Cоздадим объект history и скормим нейронной сети датасет учебных изображений в 10 этапов, чтобы улучшить точность. Мы условно делим этот процесс на 10 этапов, чтобы улучшить качество обучения.
Придется немного подождать:
Точность совсем низкая для начала, но она потом подрастет. Ура! Как вы видите, если параметры loss и accuracy характеризуют процесс обучения, то validation_loss и validaion_accuracy – потери и точность при проверке. Конечный результат – это 60 процентов точности, нормальный результат для первой попытки. Отобразим график, характеризующий скорость и качество обучения. Для этого мы метрику accuracy и вводили. Зададим название осей x и y, пограничные значения осей координат, чтобы график был более наглядным; легенду мы отправим вправо вниз. В топ-3 самых распространенных картинок, которая помогает понять нейронной сети, входит эта диаграмма со слоями.
Практика как всегда отличается от теории: точность при валидации существенно ниже:
Посмотрим, как изменилась точность классификации:
К счастью, эффективность модели подросла на целых 10%:
Автор оригинальной статьи: Mayank Mishra