В первой статье мы представили основные концепции нейронных сетей и основы использования Tensorflow. Это вторая статья из серии, в которой будут представлены сверточные нейронные сети. Он фокусируется на классических сверточных нейронных сетях, основных концепциях и основных единицах полностью сверточных сетей, а также на сходствах и различиях между сверточных нейронных сетей и нейронных сетей. Наконец, реализуя алгоритм обнаружения ключевых точек лица, который широко используется на практике, он знакомит с тем, как построить свёрточную нейронную сеть с помощью TensorFlow.
История развития нейронной сети
Происхождение сверточной нейронной сети (CNN) можно проследить до 1960-х годов. Биологические исследования показали, что передача визуальной информации от сетчатки к мозгу осуществляется посредством возбуждения нескольких уровней рецептивных полей, и были предложены ранние модели, такие как неокогнитрон. В 1998 году Лекун и другие, один из трех гигантов глубокого обучения, официально предложили CNN и разработали модель LeNet-5, как показано на рисунке ниже. Модель добилась хороших результатов в таких областях, как распознавание рукописных символов.
Из-за вычислительных ресурсов и других причин CNN долгое время находилась в забытом состоянии. В конкурсе ImageNet более 20 лет спустя AlexNet на основе CNN блистал в соревновании и возглавил возрождение CNN.С тех пор исследования CNN вступили в период быстрого развития. В настоящее время развитие сверточных нейронных сетей имеет два основных направления:
- Как улучшить производительность модели. Большое внимание в этом направлении уделяется обучению более широких и глубоких сетей. В соответствии с этим направлением мысли появилось много классических моделей, включая GoogleNet, VGG, ResNet и ResNext.
- Как увеличить скорость модели. Повышение скорости имеет решающее значение для развертывания CNN на мобильных устройствах. За счет удаления максимального пула, использования свертки шага, использования групповой свертки, фиксированной точки и других методов приложения CNN, такие как обнаружение лиц и сегментация переднего и заднего фона, были развернуты на мобильных телефонах в больших масштабах.
В настоящее время CNN является наиболее важным алгоритмом в области компьютерного зрения, и он добился хороших результатов во многих задачах. Из-за нехватки места в этой статье в основном будут представлены основы сверточных нейронных сетей.
Нейронные сети против сверточных нейронных сетей
В прошлой статье мы представили нейронные сети. Нейронные сети широко используются в обработке больших данных, распознавании языков и других областях. Но есть много проблем при работе с проблемами изображения:
- Параметрический взрыв
Взяв в качестве примера изображение 200x200x3, если скрытый слой после входного слоя имеет 100 нейронов, количество параметров достигнет 200x200x3x100=12 миллионов. Очевидно, что модель с таким количеством параметров трудно обучать и она склонна к переоснащению. - трансляционная инвариантность
Для многих задач с изображениями мы хотим, чтобы модель удовлетворяла некоторой трансляционной инвариантности. Например, для задач классификации изображений мы надеемся, что модель сможет правильно идентифицировать объект, когда объект появляется в любом месте изображения. - локальная корреляция
В таких задачах, как большие данные, нет явной топологической связи между входными измерениями, поэтому для моделирования подходят нейронные сети (полностью связанные слои). Но для задач компьютерного зрения существует естественная топологическая связь между соседними пикселями входного изображения. Например, при оценке того, есть ли объект в определенной позиции на изображении, нам нужно рассматривать только пиксели вокруг этой позиции, вместо того, чтобы принимать информацию обо всех пикселях на изображении в качестве входных данных, как традиционная нейронная сеть.
Чтобы преодолеть вышеуказанные проблемы нейронных сетей, в области зрения нам нужна более разумная структура сети. Сверточная нейронная сеть преодолевает вышеупомянутые проблемы нейронной сети с помощью локального соединения и совместного использования параметров в дизайне, поэтому она добилась потрясающих результатов в области изображений. Далее мы подробно представим принцип сверточной нейронной сети.
Сверточная нейронная сеть
сетевая структура
Общая структура сверточных нейронных сетей и традиционных нейронных сетей примерно одинакова. Как показано на рисунке ниже, традиционная нейронная сеть с 2 полносвязными слоями и сверточная нейронная сеть с 2 сверточными слоями укладываются базовыми единицами, а выход предыдущего слоя используется как вход последнего слоя. Выходные данные последнего слоя используются в качестве прогнозируемого значения модели. Основное различие между ними заключается в том, что базовые единицы различны.Сверточные нейронные сети используют сверточные слои вместо полносвязных слоев в нейронных сетях.
Как и полносвязный слой, сверточный слой также содержит параметры веса и смещения, которые можно изучить. Параметры модели могут быть определены в рамках обучения с учителем по методу, описанному в предыдущей статье, и оптимизированы обратным распространением.
свертка
Сверточные слои являются основой всей сверточной нейронной сети. Операцию двумерной свертки можно рассматривать как процесс, аналогичный сопоставлению с шаблоном. Как показано на рисунке ниже, шаблон размером h×w×d сопоставляется с вводом путем сдвига окна. В процессе скольжения в качестве значения соответствующей выходной позиции используется внутренний продукт значения соответствующей позиции на входе и веса шаблона плюс смещение b. w, h — размер шаблона, в совокупности именуемый размером ядра, в CNN w и h обычно принимают одно и то же значение. d — количество каналов в шаблоне, равное количеству каналов во входных данных. Например, для изображений RGB количество каналов равно 3.
Шаблоны часто называют ядрами свертки (K) или фильтрами в сверточных нейронных сетях. В стандартной свертке выходное значение, соответствующее выходной позиции (x, y), может быть выражено как:
conv(I,K)xy=∑hi=1∑wj=1∑dk=1Kijk⋅Ix+i−1,y+j−1,k+b
В CNN помимо параметров h, w, d, описывающих отдельный фильтр, есть три важных параметра: глубина, шаг и отступ:
- глубина относится к количеству выходных каналов, соответствующих количеству фильтров в сверточном слое.
- шаг относится к размеру шага каждого слайда фильтра
- Заполнение относится к ширине заполнения 0 вокруг ввода. Основная цель использования заполнения — контролировать размер вывода. Если заполнение не добавлено, использование фильтра с размером ядра больше 1 сделает выходной размер меньше, чем входной. На практике часто добавляют отступы, чтобы сделать входные и выходные размеры согласованными.
Как показано на рисунке ниже, для одномерного случая, если исходный размер равен W, размер фильтра — F, шаг — S, а заполнение — P, то выходной размер равен (W−F+2P)/ С+1. Установив P=(F-1)/2, когда S=1, размер ввода и вывода останется прежним. Вычисление двумерной свертки аналогично вычислению одномерной свертки.
По сравнению с полносвязным слоем в традиционной нейронной сети сверточный слой фактически можно рассматривать как частный случай полносвязного слоя. Во-первых, локальная связность.Используя пространственную топологию ввода, сверточная нейронная сеть должна учитывать только входные узлы, расстояние которых от выходного узла находится в пределах диапазона фильтра, а веса других ребер равны 0. Кроме того, для разных выходных узлов мы заставляем параметры фильтра быть одинаковыми. Но через этоместное соединениеисовместное использование параметров, сверточный слой может лучше использовать присущие изображению топологические отношения, а перевод не деформируется, что значительно снижает параметры, чтобы получить лучшее локальное оптимальное решение, чтобы оно имело лучшую производительность при проблемах с изображением.
Реализация сверточных слоев в тензорном потоке очень проста и может быть вызвана напрямуюtf.nn.conv2d
:
bias = tf.get_variable(shape=[depth])
conv = tf.nn.conv2d(x, weight, strides=[1, 1, 1, 1], padding='SAME')
conv_relu = tf.nn.relu(conv + bias)
Объединение
В сети CNN, в дополнение к большому количеству сверточных слоев, мы также вставляем соответствующее количество слоев объединения по мере необходимости. Слои пула можно использовать для уменьшения размера входных данных, тем самым уменьшая параметры и вычисления последующей сети. Обычные операции объединения (такие как максимальное объединение, среднее объединение) обычно также могут обеспечить определенную трансляционную инвариантность.
Возьмем в качестве примера максимальный пул.Максимальный пул принимает максимальное значение для всех значений в пределах диапазона размера ядра, а результат используется в качестве вывода соответствующей позиции. Объединение обычно работает с каждым каналом отдельно, поэтому количество выходных каналов такое же, как и входных. Слой объединения аналогичен слою свертки.Операция объединения также может пониматься как скользящее окно, поэтому существуют такие понятия, как шаг и заполнение, соответствующие свертке. На следующем рисунке показана операция максимального пула с размером ядра и шагом 2:
На практике есть две распространенные конфигурации параметров слоя пула: во-первых, размер ядра и шаг равны 2. Этот параметр не имеет перекрывающихся областей в процессе пула. Другой заключается в том, что размер ядра равен 3, а шаг равен 2 с перекрывающимся пулом. Реализовать слой пула в tensorflow тоже очень просто:
tf.nn.max_pool(x, ksize=[1, размер, размер, 1], strides=[1, шаг, шаг, 1], padding='SAME')Классическая сетевая структура сверточной нейронной сети
После знакомства с основными компонентами сверточной нейронной сети давайте представим классическую сетевую структуру сверточной нейронной сети. Начиная с LeNet-5 в 1998 году, до модели AlexNet в Imagenet 2012, а затем до серии классических моделей, таких как VGG, они в основном следуют этой классической структуре.
Для ясности мы опускаем нелинейные функции активации после сверточных и полносвязных слоев. Как показано на рисунке выше, классическую сверточную нейронную сеть можно разделить на три части:
- Ряд каскадных слоев conv+pooling (слои объединения иногда опускаются). В процессе каскадирования размер входных постепенно становится меньше, а количество выходных каналов постепенно увеличивается, завершая абстрагирование информации от низкоуровневого к высокоуровневому.
- Ряд каскадных полносвязных слоев. На стыке между сверточным слоем и полносвязным слоем выходные данные сверточного слоя преобразуются в одномерные входные данные и отправляются на полносвязный слой. После этого ряд полностью связанных слоев каскадируется в соответствии со сложностью задачи.
- Конечный выходной слой определяет форму вывода в соответствии с потребностями задачи. Для задач с несколькими классификациями в конце будет добавлен слой softmax.
Классическую сверточную нейронную сеть можно рассматривать как нелинейную функцию с фиксированным выходным размером. Он может преобразовать входное изображение размера H×W×3 в окончательный вектор фиксированной длины размера d. Классические сверточные нейронные сети достигли больших успехов в классификации изображений, регрессии и других задачах. В следующей практической части мы приведем пример задачи регрессии.
Полностью сверточная сеть
Из-за наличия полносвязного слоя в классической сверточной нейронной сети она может принимать только изображение фиксированного размера в качестве входных данных и генерировать выходные данные фиксированного размера. Хотя с помощью адаптивного объединения можно принимать входные данные переменной длины, этот процесс по-прежнему производит только выходные данные фиксированного размера. Чтобы преодолеть этот недостаток классических сверточных нейронных сетей, мы больше не используем полносвязные слои в сценариях приложений с переменными выходными размерами, такими как сегментация объектов. Эта сеть, все основные вычислительные блоки которой состоят из сверточных слоев, называется полностью сверточной сетью (FCN).
Как показано на рисунке выше, поскольку операция свертки не имеет ограничений на размер входных данных, а размер выходных данных определяется входными данными, полностью сверточная сеть может решать такие проблемы, как сегментация, которые не фиксированы по размеру. Полностью сверточная сеть может рассматриваться как нелинейная функция, выходной размер которой линейно зависит от входного размера. Он может преобразовывать входное изображение размера H×W×3 в выходное изображение конечного размера H/S×H/S×d. Задачи обучения с учителем, которые могут быть преобразованы в эту форму, в основном могут быть решены в рамках полностью сверточных сетей.
Деконволюция
В полностью сверточной сети стандартная операция свертки + пула уменьшит размер вывода. Для многих задач нам нужно, чтобы выходной размер соответствовал входному изображению, поэтому нам нужна операция, которая может увеличить входной размер. Наиболее распространенной операцией является деконволюция.
Деконволюцию можно понимать как обратную операцию свертки. Здесь мы в основном вводим деконволюцию шага> 1 и целого числа. Эту деконволюцию можно понимать как обобщенную разностную операцию. На следующем рисунке приведен пример, входные данные представляют собой зеленый квадрат 3x3, шаг деконволюции равен 2, размер ядра равен 3, а заполнение равно 1. В процессе скольжения для каждого входного квадрата выходом является соответствующая теневая область 3x3, а выходным значением является произведение входного значения и соответствующего значения положения ядра. Окончательный вывод представляет собой кумулятивную сумму соответствующих значений каждой выходной позиции в процессе скольжения. Это можно рассматривать как разностную операцию со значениями ядра 3x3 в качестве весов. Самый внешний круг белых областей не может выполнять операцию полной разности, поэтому вы можете удалить окружающий круг белых областей, установив отступ равным 1, и окончательный выходной размер будет 5x5.
В соответствии с вышеприведенным описанием, шагом>1 и целочисленной деконволюцией, если значением фиксированного ядра деконволюции является ядро билинейной разности, деконволюция может быть эквивалентна билинейной разности. Ядро деконволюции, полученное путем обучения, может лучше адаптироваться к различным задачам, чем ядро с фиксированным параметром, поэтому деконволюцию можно рассматривать как обобщение традиционного различия. Аналогично свёртке модуль деконволюции был реализован в tensorflow.tf.layers.conv2d_transpose
.
Применение сверточных нейронных сетей в визуальном распознавании
CNN имеет очень широкий спектр приложений для визуального распознавания. Затем мы возьмем три классические проблемы визуального распознавания: классификацию/регрессию, обнаружение и сегментацию в качестве примеров, чтобы показать, как использовать CNN для решения практических задач.
классификация/регрессия
Классификация изображений относится к оценке того, к каким заранее определенным категориям принадлежит изображение, а регрессия изображений относится к оценке значений атрибутов изображения в соответствии с содержимым изображения. На практике широко используются как классификация, так и регрессия. От классификации объектов, распознавания лиц до распознавания проверочного кода 12306 и т. д. его можно абстрагировать от стандартных задач классификации. Точно так же предсказание положения ключевой точки лица, предсказание атрибутов лица (таких как возраст, внешний вид) и т. Д. Также можно абстрагировать как стандартные задачи регрессии. В настоящее время, если приложение в поле зрения может быть абстрагировано в задачу классификации или регрессии фиксированной длины, в случае большого количества обучающих данных для ее решения обычно можно использовать представленную ранее классическую структуру сверточной нейронной сети.
обнаружение
Проблема обнаружения обычно относится к оценке того, есть ли объект на изображении, и местонахождения объекта. Существуют одноэтапные и двухэтапные методы обнаружения. Из-за нехватки места мы сосредоточимся на одноэтапном методе в рамках FCN.
Согласно предыдущему введению, FCN можно рассматривать как нелинейную функцию, которая преобразует входное изображение H×W×3 в выход H/S×W/S×d. Для решения задачи обнаружения в рамках FCN мы можем предсказать, есть ли объект в каждой выходной позиции, и смещение верхнего левого и нижнего правого углов объекта относительно текущей входной позиции. Таким образом, для каждой выходной позиции необходим 5-мерный вектор, чтобы указать, существует ли объект, то есть d=5. После определения выхода сети мы вручную строим соответствующую землю
правда, а затем в рамках обучения с учителем выполняется обучение параметрам путем определения функции потерь (потери l2) и выполнения обратного распространения ошибки.
сегментация
Проблема сегментации относится к присвоению класса каждому пикселю изображения. Метод сегментации на основе FCN очень похож на описанный выше одноэтапный метод обнаружения. Для задачи мультиклассовой сегментации для каждой позиции вывода мы можем определить класс, к которому она принадлежит. В рамках FCN для задачи классификации N результатом является H/S×W/S×N. После этого он обучается методом обратного распространения. Одно из различий между задачами сегментации и обнаружения заключается в том, что иногда нам нужно получить выход того же размера, что и входное изображение (В×Ш×N), но для ускорения сверточной нейронной сети обычно добавляется объединяющий слой. уменьшить размер промежуточного сверточного слоя. Как показано на рисунке ниже, чтобы гарантировать, что размер вывода соответствует требованиям, мы можем добавить слой деконволюции в конце сети для компенсации, чтобы получить вывод большего размера.
Настоящий бой: обнаружение ключевых точек лица
Обнаружение ключевых точек лица является относительно зрелым приложением в поле зрения и является основой для продвинутых приложений, таких как живое обнаружение, украшение человека и распознавание лиц. Наконец, на примере обнаружения ключевых точек лица в этой статье показано, как использовать Tensorflow для реализации применения регрессии изображений. Набор экспериментальных данных использует набор данных Faical Kerypoints Detection в конкурсе Kaggle (woohoo.cardreform.com/from/facial-can…). Набор данных содержит 7094 обучающих изображения и 1783 тестовых изображения. Каждое лицо в наборе данных аннотировано 15 ключевыми точками, а размер изображения составляет 96x96.
Регрессия расстояния L2
Цель конкурса Kaggle — предсказать координаты 15 ключевых точек на лице, всего 30 значений с плавающей запятой, что является стандартными задачами регрессии. Мы решили принять наиболее распространенное расстояние l2 в качестве цели оптимизации. Как и структура кода модели нейронной сети в первой статье, мы разделили код на 3 основных модуля, а именно модуль набора данных, модуль сети и модуль решателя.
Структура модели
-
inference
Мы определяем основную структуру сети в функции вывода. Поскольку модель будет повторно использовать полносвязные и сверточные слои, мы инкапсулируем их как функции.linear_relu
иconv_relu
, чтобы облегчить повторное использование кода. Что касается сетевой структуры, мы используем относительно простую трехуровневую свертка и двухуровневую полносвязную структуру. Выход сверточного слоя проходит черезtf.reshape
Преобразуется в формат, приемлемый для полносвязного слоя. Поскольку это проблема регрессии, мы напрямую используем результат последнего полносвязного слоя в качестве выходных данных. -
loss
Для простоты для стандартных задач регрессии мы используем mse в качестве функции потерь.tf.reduce_mean(tf.square(predictions - labels), name='mse')
-
metric
Во время тестирования мы по-прежнему используем tensorflow, чтобы предоставить модуль tf.metrics для автоматического завершения оценки каждой партии и суммирования всех оценок. В этом примере мы решаем задачу регрессии, поэтому мы можем использоватьtf.metrics.mean_squared_error
Вычислите среднеквадратичную ошибку.
__Fri Dec 15 2017 10:13:58 GMT+0800 (CST)____Fri Dec 15 2017 10:13:58 GMT+0800 (CST)__def linear(x, output_size, wd=0):
input_size = x.get_shape()[1].value
weight = tf.get_variable(
name='weight',
shape=[input_size, output_size],
initializer=tf.contrib.layers.xavier_initializer())
bias = tf.get_variable(
'bias', shape=[output_size], initializer=tf.constant_initializer(0.0))
out = tf.matmul(x, weight) + bias
if wd != 0:
weight_decay = tf.multiply(tf.nn.l2_loss(weight), wd, name='weight_loss')
tf.add_to_collection('losses', weight_decay)
return out
def linear_relu(x, output_size, wd=0):
return tf.nn.relu(
linear(x, output_size, wd), name=tf.get_default_graph().get_name_scope())
def conv_relu(x, kernel_size, width, wd=0):
input_size = x.get_shape()[3]
weight = tf.get_variable(
name='weight',
shape=[kernel_size, kernel_size, input_size, width],
initializer=tf.contrib.layers.xavier_initializer())
bias = tf.get_variable(
'bias', shape=[width], initializer=tf.constant_initializer(0.0))
conv = tf.nn.conv2d(x, weight, strides=[1, 1, 1, 1], padding='SAME')
if wd != 0:
weight_decay = tf.multiply(tf.nn.l2_loss(weight), wd, name='weight_loss')
tf.add_to_collection('losses', weight_decay)
out = tf.nn.relu(conv + bias, name=tf.get_default_graph().get_name_scope())
return out
def pool(x, size):
return tf.nn.max_pool(
x, ksize=[1, size, size, 1], strides=[1, size, size, 1], padding='SAME')__Fri Dec 15 2017 10:13:58 GMT+0800 (CST)____Fri Dec 15 2017 10:13:58 GMT+0800 (CST)__
__Fri Dec 15 2017 10:13:58 GMT+0800 (CST)____Fri Dec 15 2017 10:13:58 GMT+0800 (CST)__class BasicCNN(Net):
def __init__(self, **kwargs):
self.output_size = kwargs.get('output_size', 1)
return
def inference(self, data):
with tf.variable_scope('conv1'):
conv1 = conv_relu(data, kernel_size=3, width=32)
pool1 = pool(conv1, size=2)
with tf.variable_scope('conv2'):
conv2 = conv_relu(pool1, kernel_size=2, width=64)
pool2 = pool(conv2, size=2)
with tf.variable_scope('conv3'):
conv3 = conv_relu(pool2, kernel_size=2, width=128)
pool3 = pool(conv3, size=2)
# Flatten convolutional layers output
shape = pool3.get_shape().as_list()
flattened = tf.reshape(pool3, [-1, shape[1] * shape[2] * shape[3]])
# Fully connected layers
with tf.variable_scope('fc4'):
fc4 = linear_relu(flattened, output_size=100)
with tf.variable_scope('fc5'):
fc5 = linear_relu(fc4, output_size=100)
with tf.variable_scope('out'):
prediction = linear(fc5, output_size=self.output_size)
return {"predictions": prediction, 'data': data}
def loss(self, layers, labels):
predictions = layers['predictions']
with tf.variable_scope('losses'):
loss = tf.reduce_mean(tf.square(predictions - labels), name='mse')
return loss
def metric(self, layers, labels):
predictions = layers['predictions']
with tf.variable_scope('metrics'):
metrics = {
"mse": tf.metrics.mean_squared_error(
labels=labels, predictions=predictions)}
return metrics__Fri Dec 15 2017 10:13:58 GMT+0800 (CST)____Fri Dec 15 2017 10:13:58 GMT+0800 (CST)__
Dataset
__Fri Dec 15 2017 10:13:58 GMT+0800 (CST)____Fri Dec 15 2017 10:13:58 GMT+0800 (CST)__images = np.vstack(df['Image'].values) / 255. # scale pixel values to [0, 1]
images = images.astype(np.float32)
label = df[df.columns[:-1]].values
label = (label - 48) / 48 # scale target coordinates to [-1, 1]
label = label.astype(np.float32)__Fri Dec 15 2017 10:13:58 GMT+0800 (CST)____Fri Dec 15 2017 10:13:58 GMT+0800 (CST)__
__Fri Dec 15 2017 10:13:58 GMT+0800 (CST)____Fri Dec 15 2017 10:13:58 GMT+0800 (CST)__def parse_example(example_proto):
features = {
"data": tf.FixedLenFeature((9216), tf.float32),
"label": tf.FixedLenFeature((30), tf.float32, default_value=[0.0] * 30),
}
parsed_features = tf.parse_single_example(example_proto, features)
image = tf.reshape(parsed_features["data"], (96, 96, -1))
return image, parsed_features["label"]
dataset = tf.contrib.data.TFRecordDataset(files)
dataset = dataset.map(self.parse_function)__Fri Dec 15 2017 10:13:58 GMT+0800 (CST)____Fri Dec 15 2017 10:13:58 GMT+0800 (CST)__
Для части набора данных мы используем формат tfrecord, рекомендованный tensorflow. пройти черезTFRecordDataset
Функция читает файл tfrecord и передаетparse_example
Преобразуйте tfrecod во входной формат модели. Как формат фиксированной длины, tfrecord может значительно ускорить чтение и доставку данных. Особенно при использовании графического процессора это может предотвратить то, что ввод-вывод данных станет узким местом производительности.
Solver
Благодаря модульной конструкции мы можем полностью повторно использовать код Солвера из первой статьи без каких-либо модификаций, тем самым повышая эффективность повторного использования кода.
Результаты экспериментов
__Fri Dec 15 2017 10:13:58 GMT+0800 (CST)____Fri Dec 15 2017 10:13:58 GMT+0800 (CST)__file_dict = {
'train': os.path.join(args.data_dir, 'train.tfrecords'),
'eval': os.path.join(args.data_dir, 'test.tfrecords')
}
with tf.Graph().as_default():
dataset = Dataset(
file_dict=file_dict,
split='train',
parse_function=parse_example,
batch_size=50)
net = Net(output_size=30)
solver = Solver(dataset, net, max_steps=200, summary_iter=10)
solver.train()__Fri Dec 15 2017 10:13:58 GMT+0800 (CST)____Fri Dec 15 2017 10:13:58 GMT+0800 (CST)__
После инкапсуляции оправдания мы можем завершить обучение модели с помощью простого кода выше. На следующем рисунке показана визуализированная структура сети в tensorboad, статистика потерь и влияние модели на тестовое изображение:
__Fri Dec 15 2017 10:13:58 GMT+0800 (CST)____Fri Dec 15 2017 10:13:58 GMT+0800 (CST)__step 10: loss = 0.0756 (136.2 examples/sec)
step 20: loss = 0.0230 (155.2 examples/sec)
step 30: loss = 0.0102 (149.1 examples/sec)
step 40: loss = 0.0071 (125.1 examples/sec)
step 50: loss = 0.0065 (160.9 examples/sec)
step 60: loss = 0.0081 (171.9 examples/sec)
step 70: loss = 0.0058 (148.4 examples/sec)
step 80: loss = 0.0060 (169.4 examples/sec)
step 90: loss = 0.0069 (185.4 examples/sec)
step 100: loss = 0.0057 (186.1 examples/sec)
step 110: loss = 0.0062 (183.8 examples/sec)
step 120: loss = 0.0080 (170.3 examples/sec)
step 130: loss = 0.0052 (185.8 examples/sec)
step 140: loss = 0.0071 (184.3 examples/sec)
step 150: loss = 0.0049 (170.7 examples/sec)
step 160: loss = 0.0056 (178.7 examples/sec)
step 170: loss = 0.0053 (173.2 examples/sec)
step 180: loss = 0.0058 (172.6 examples/sec)
step 190: loss = 0.0053 (172.5 examples/sec)
step 200: loss = 0.0056 (188.1 examples/sec)
mse: 0.140243709087__Fri Dec 15 2017 10:13:58 GMT+0800 (CST)____Fri Dec 15 2017 10:13:58 GMT+0800 (CST)__
Видно, что классическая сверточная нейронная сеть с 3 слоями свертки + 2 слоями полной связи может очень хорошо решить проблему обнаружения ключевых точек лица. На практике мы можем использовать более сложную сеть и некоторые другие приемы для дальнейшего улучшения производительности модели.
Полная загрузка кода:GitHub.com/dong--J Ян/…