Эта статья переведена сA guide to receptive field arithmetic for Convolutional Neural Networks(Возможно, вам придется пройти через стену, чтобы получить доступ), что удобно для вашего собственного обучения и справки. Если есть какие-либо нарушения, пожалуйста, сообщите.
Рецептивное поле, вероятно, является одним из самых важных понятий в сверточных нейронных сетях (CNN), и оно заслуживает нашего внимания и изучения. Архитектуры современных популярных методов распознавания объектов в основном вращаются вокруг дизайна рецептивных полей. Однако в настоящее время нет полного руководства по расчету и визуализации рецептивного поля CNN. Этот учебник призван заполнить пробелы и представить методы визуализации для карт объектов в CNN, тем самым раскрывая принципы рецептивных полей и расчета рецептивных полей в любой архитектуре CNN. Мы также предоставляем реализацию кода, чтобы доказать правильность расчета, чтобы каждый мог начать изучение CNN с расчета рецептивного поля, чтобы иметь более глубокое понимание архитектуры CNN.
В этой статье предполагается, что читатель уже знаком с идеей CNN, особенно с операциями свертки и объединения, конечно, вы можете обратиться к[1603.07285] A guide to convolution arithmetic for deep learning, чтобы просмотреть соответствующие знания CNN. Если вы уже что-то знаете о CNN, я думаю, вы сможете прочитать эту статью менее чем за полчаса. На самом деле эта статья вдохновлена предыдущей статьей, и в тексте используются аналогичные обозначения.
The fixed-sized CNN feature map visualization
Рис. 1. Два способа визуализации карты характеристик CNN.
Как показано на рисунке 1, мы используем размер ядра ядра свертки C (размер ядра) k=3*3, размер заполнения (padding size) p=1*1, шаг (шаг) s=2*2. (Верхний ряд на рисунке) Сворачивает карту входных объектов 5*5 для создания зеленой карты объектов 3*3. (Нижняя строка на рисунке) Та же операция свертки применяется к зеленой карте объектов выше для создания оранжевой карты объектов 2 * 2. (Левый столбец на рисунке) Визуализируйте карту признаков CNN по столбцам.Если мы посмотрим только на карту признаков, мы не сможем узнать местоположение признака (т.е. центральное положение рецептивного поля) и размер области ( то есть размер рецептивного поля), и мы не можем понять CNN в глубину.Информация о рецептивном поле в . (Правый столбец на рисунке) Размер карты признаков CNN фиксирован, а положение ее признаков — центральное положение рецептивного поля.
Рецептивное поле представляет область диапазона конкретной функции CNN во входном пространстве (Рецептивное поле определяется как область во входном пространстве, на которую смотрит конкретная функция CNN.. Рецептивное поле признака может быть описано центральным расположением области и размером признака. На рисунке 1 показаны некоторые примеры рецептивных полей с использованием размера ядра (размер ядра) k=3*3, размера заполнения (padding size) p=1*1, шага (шага) s=2*2 ядра свертки C Операция свертки выполняется на входной карте размером 5*5, а на выходе будет карта признаков (зеленая карта) размера 3*3. Выполнение той же операции свертки на карте объектов 3 * 3 приведет к выводу карты объектов 2 * 2 (оранжевого цвета). Размер выходной карты объектов в каждом измерении можно рассчитать по следующей формуле ([1603.07285] A guide to convolution arithmetic for deep learning):
Для простоты в этой статье предполагается, что архитектура CNN симметрична, а соотношение сторон входного изображения равно 1, поэтому значения переменных во всех измерениях одинаковы. Если архитектура CNN или входное изображение несимметричны, вы также можете рассчитать размер карты объектов в каждом измерении отдельно. Как показано на рисунке 1, левый столбец показывает общую визуализацию карт характеристик CNN. Этот метод визуализации может получить количество карт признаков, но не может рассчитать положение признака (центральное положение рецептивного поля) и размер области (размер рецептивного поля). В правом столбце на рисунке 1 показана визуализация фиксированного размера карт характеристик CNN, которая решает вышеуказанную проблему, сохраняя все карты характеристик того же размера, что и входная карта, за которой следует каждая функция в центре ее рецептивного поля. Поскольку размер рецептивного поля всех объектов на карте объектов одинаков, мы можем легко нарисовать ограничивающую рамку, соответствующую объекту. поле) для представления размера рецептивного поля. Поскольку размер карты объектов такой же, как у входного изображения, нам не нужно сопоставлять ограничивающую рамку с входным слоем.
Рис. 2. Еще одно представление карты объектов CNN фиксированного размера. То же ядро свертки C используется для выполнения операции свертки над входным изображением размером 7*7, где ограничивающая рамка рецептивного поля рисуется вокруг центра признака. Для ясности окружающие пиксели заполнения здесь игнорируются. Карты объектов CNN фиксированного размера могут быть представлены в 3D (слева) или 2D (справа).
На рис. 2 показан другой пример, в котором то же ядро свертки C используется для свертки входного изображения размером 7*7. Здесь представлены карты функций CNN фиксированного размера в трехмерном (слева) и двумерном (справа) представлениях. Примечание. Размер рецептивного поля на рисунке 2 постепенно увеличивается, и центральное восприимчивое поле объектов второго слоя признаков вскоре покроет все входное изображение. Это очень важно для повышения производительности архитектуры проектирования CNN.
Арифметика рецептивного поля
В дополнение к количеству карт объектов в каждом измерении необходимо рассчитать размер рецептивного поля каждого слоя, поэтому нам необходимо знать дополнительную информацию о каждом слое, в том числе: размер текущего рецептивного поляr, расстояние (или скачок) между соседними объектамиj, центральная координата верхнего левого (начального) объектаstart, где центральная координата объекта определяется как центральная координата его восприимчивого поля (как описано выше для карты объектов CNN фиксированного размера). Предполагаемый размер ядра сверткиk, размер заполненияp, размер шагаs, то соответствующие атрибуты выходного слоя вычисляются следующим образом:
- Формула 1 вычисляет количество выходных объектов на основе количества входных объектов и атрибутов, связанных со сверткой.
- Формула 2 вычисляет выходную карту признаковjump, равный произведению скачка входного изображения на количество входных признаков (количество скачков при выполнении операции свертки, размер шага)
- Формула 3 вычисляет размер рецептивного поля карты выходных объектов, который равен площади покрытия k входных объектов.плюс дополнительная площадь, охватываемая восприимчивым полем входного объекта на границе.
- Формула 4 вычисляет положение центра рецептивного поля первого выходного объекта, которое равно центральному положению первого входного объекта плюс расстояние от положения первого входного объекта до положения центра первого ядра свертки., минус размер области заполнения. Примечание. Вам нужно умножить скачок входной карты объектов здесь, чтобы получить фактическое расстояние или интервал.
Рисунок 3 выполняет расчеты рецептивного поля для примера на рисунке 1. В первой строке приведены некоторые символы и уравнения, вторая и последняя строки иллюстрируют процесс расчета восприимчивого поля выходного слоя с учетом информации входного слоя.
Первый слой CNN является входным слоем,n = image size,r = 1,j = 1,start = 0.5. В системе координат, используемой на рисунке 3, центр первого объекта входного слоя находится на отметке 0,5. Рекурсивно выполняя приведенные выше четыре формулы, можно рассчитать информацию о рецептивном поле во всех картах функций в CNN. На рис. 3 показан пример расчета по этим формулам.
Вот небольшая программа на Python для расчета информации о восприимчивом поле всех слоев в рамках заданной архитектуры CNN. Программа позволяет вводить название любой карты объектов и порядковый номер объекта на карте, а также выводит размер и местоположение соответствующего рецептивного поля. На рис. 4 показан пример для AlexNet.
Рисунок 4. Пример расчета рецептивного поля в AlexNet
# [filter size, stride, padding]
#Assume the two dimensions are the same
#Each kernel requires the following parameters:
# - k_i: kernel size
# - s_i: stride
# - p_i: padding (if padding is uneven, right padding will higher than left padding; "SAME" option in tensorflow)
#
#Each layer i requires the following parameters to be fully represented:
# - n_i: number of feature (data layer has n_1 = imagesize )
# - j_i: distance (projected to image pixel distance) between center of two adjacent features
# - r_i: receptive field of a feature in layer i
# - start_i: position of the first feature's receptive field in layer i (idx start from 0, negative means the center fall into padding)
import math
convnet = [[11,4,0],[3,2,0],[5,1,2],[3,2,0],[3,1,1],[3,1,1],[3,1,1],[3,2,0],[6,1,0], [1, 1, 0]]
layer_names = ['conv1','pool1','conv2','pool2','conv3','conv4','conv5','pool5','fc6-conv', 'fc7-conv']
imsize = 227
def outFromIn(conv, layerIn):
n_in = layerIn[0]
j_in = layerIn[1]
r_in = layerIn[2]
start_in = layerIn[3]
k = conv[0]
s = conv[1]
p = conv[2]
n_out = math.floor((n_in - k + 2*p)/s) + 1
actualP = (n_out-1)*s - n_in + k
pR = math.ceil(actualP/2)
pL = math.floor(actualP/2)
j_out = j_in * s
r_out = r_in + (k - 1)*j_in
start_out = start_in + ((k-1)/2 - pL)*j_in
return n_out, j_out, r_out, start_out
def printLayer(layer, layer_name):
print(layer_name + ":")
print("\t n features: %s \n \t jump: %s \n \t receptive size: %s \t start: %s " % (layer[0], layer[1], layer[2], layer[3]))
layerInfos = []
if __name__ == '__main__':
#first layer is the data layer (image) with n_0 = image size; j_0 = 1; r_0 = 1; and start_0 = 0.5
print ("-------Net summary------")
currentLayer = [imsize, 1, 1, 0.5]
printLayer(currentLayer, "input image")
for i in range(len(convnet)):
currentLayer = outFromIn(convnet[i], currentLayer)
layerInfos.append(currentLayer)
printLayer(currentLayer, layer_names[i])
print ("------------------------")
layer_name = raw_input ("Layer name where the feature in: ")
layer_idx = layer_names.index(layer_name)
idx_x = int(raw_input ("index of the feature in x dimension (from 0)"))
idx_y = int(raw_input ("index of the feature in y dimension (from 0)"))
n = layerInfos[layer_idx][0]
j = layerInfos[layer_idx][1]
r = layerInfos[layer_idx][2]
start = layerInfos[layer_idx][3]
assert(idx_x < n)
assert(idx_y < n)
print ("receptive field: (%s, %s)" % (r, r))
print ("center: (%s, %s)" % (start+idx_x*j, start+idx_y*j))