В настоящее время я создаю модель на платформе Tensorflow (версия 1.8 os: Ubuntu MATE16.04). Цель модели - обнаружить / сопоставить ключевые точки человеческого тела. Во время обучения возникла ошибка «Нет градиентов ни для одной переменной», и мне трудно ее исправить.
Предыстория модели. Основные идеи взяты из следующих двух статей:
- Глубокое изучение двоичных хеш-кодов для быстрого поиска изображений
- Изучение компактных двоичных дескрипторов с помощью неконтролируемых глубоких нейронных сетей
Они показали, что изображения можно сопоставить по хэш-кодам, сгенерированным из сверточной сети. Сходство двух изображений определяется расстоянием Хэмминга между их соответствующими хэш-кодами.
Я думаю, что можно разработать чрезвычайно легкую модель для оценки позы человека в реальном времени на видео с «постоянным человеческим объектом» и «фиксированным фоном».
Структура модели
01. Источник данных:
3 изображения из одного видео с одним и тем же человеком и похожим фоном. Все человеческие ключевые точки на каждом изображении хорошо обозначены. 2 изображения будут использоваться в качестве «источников подсказок», а последнее изображение будет целью для обнаружения / сопоставления ключевых точек.
02. Подсказки:
Области интереса размером 23x23 пикселей будут вырезаны из изображений «источника подсказки» в соответствии с местоположением ключевых точек человека. Центром этих ROI являются ключевые точки.
03. сверточная сеть «для подсказок»:
Простая 3-х слойная конструкция. Первые два слоя свертываются на [2,2] шага с фильтром 3x3. Последний слой представляет собой свертку 5x5 на входе 5x5 без заполнения (соответствует полностью связанному слою).
Это превратит область интереса подсказки 23x23 пикселей в один 32-битный хэш-код. Одно изображение подсказки сгенерирует набор из 16 хэш-кодов.
04. Сверточная сеть «для целевого изображения»: сеть разделяет веса smae с сетью подсказок. Но в этом случае у каждого свёрточного слоя есть отступы. Изображение 301x301 пикселей будет преобразовано в «хэш-карту» 76x76.
05. Соответствие хэша:
Я создал функцию под названием «locateMin_and_get_loss» для вычисления расстояния Хэмминга между «хеш-кодом» и хеш-кодами в каждой точке хеш-карты. Эта функция создаст «карту расстояний». Местоположение точки с наименьшим значением расстояния будет рассматриваться как местоположение ключевой точки.
06. Расчет убытков:
Я сделал функцию «get_total_loss_and_result», чтобы вычислить общую потерю 16 ключевых точек. Потери - это нормализованное евклидово расстояние между точками наземной метки истинности и точками, расположенными по модели.
07. предлагаемый рабочий процесс:
Перед инициализацией этой модели пользователь сделает два снимка целевого человека под разными углами. Изображения будут помечены современными моделями, такими как OpenPose или DeepPose, и генерировать из них хеш-хэши с помощью сверточной сети, упомянутой в 03.
Наконец, видеопоток будет запущен и обработан моделью.
08. Почему два набора подсказок?
Один человеческий сустав / ключевая точка, наблюдаемая под разными углами, будет иметь очень разный вид. Вместо того, чтобы увеличивать размерность нейронной сети, я хочу «обмануть игру», собирая две подсказки вместо одной. Я хочу знать, может ли это повысить точность и обобщающую способность модели или нет.
Проблемы, с которыми я столкнулся:
01. Ошибка "Нет градиентов ни для одной переменной" (мой главный вопрос в этом посте):
Как упоминалось выше, я столкнулся с этой ошибкой при обучении модели. Я пытался узнать из таких сообщений, как this и это и this. Но в настоящее время я понятия не имею, хотя я проверил вычислительный график.
02. "Пакетная" проблема:
Из-за его уникальной структуры трудно использовать обычный заполнитель для хранения входных данных нескольких пакетов. Я исправил это, установив номер партии на 3 и вручную объединив значения функций потерь.
2018.10.28 Редактировать:
Упрощенная версия с одним набором подсказок:
import tensorflow as tf
import numpy as np
import time
from imageLoader import getPaddedROI,training_data_feeder
import math
'''
created by Cid Zhang
a sub-model for human pose estimation
'''
def truncated_normal_var(name,shape,dtype):
return(tf.get_variable(name=name, shape=shape, dtype=dtype, initializer=tf.truncated_normal_initializer(stddev=0.01)))
def zero_var(name,shape,dtype):
return(tf.get_variable(name=name, shape=shape, dtype=dtype, initializer=tf.constant_initializer(0.0)))
roi_size = 23
image_input_size = 301
#input placeholders
#batch1 hints
inputs_b1h1 = tf.placeholder(tf.float32, ( 16, roi_size, roi_size, 3), name='inputs_b1h1')
inputs_s = tf.placeholder(tf.float32, (None, image_input_size, image_input_size, 3), name='inputs_s')
labels = tf.placeholder(tf.float32,(16,76,76), name='labels')
#define the model
def paraNet(input):
out_l1 = tf.layers.conv2d(input, 8, [3, 3],strides=(2, 2), padding ='valid' ,name='para_conv_1')
out_l1 = tf.nn.relu6(out_l1)
out_l2 = tf.layers.conv2d(out_l1, 16, [3, 3],strides=(2, 2), padding ='valid' ,name='para_conv_2')
out_l2 = tf.nn.relu6(out_l2)
out_l3 = tf.layers.conv2d(out_l2, 32, [5, 5],strides=(1, 1), padding ='valid' ,name='para_conv_3')
return out_l3
#network pipeline to create the first Hint Hash Sets (Three batches)
with tf.variable_scope('conv'):
out_b1h1_l3 = paraNet(inputs_b1h1)
#flatten and binerize the hashs
out_b1h1_l3 =tf.squeeze( tf.round(tf.nn.sigmoid(out_b1h1_l3)) )
with tf.variable_scope('conv', reuse=True):
out_2_l1 = tf.layers.conv2d(inputs_s, 8, [3, 3],strides=(2, 2), padding ='same' ,name='para_conv_1')
out_2_l1 = tf.nn.relu6(out_2_l1)
out_2_l2 = tf.layers.conv2d(out_2_l1, 16, [3, 3],strides=(2, 2), padding ='same' ,name='para_conv_2')
out_2_l2 = tf.nn.relu6(out_2_l2)
out_2_l3 = tf.layers.conv2d(out_2_l2, 32, [5, 5],strides=(1, 1), padding ='same' ,name='para_conv_3')
#binerize the value into Hash code
out_2_l3 = tf.round(tf.nn.sigmoid(out_2_l3))
orig_feature_map_size = tf.shape(out_2_l3)[1]
#calculate Hamming distance maps
map0 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[0] , out_2_l3 ) ) , axis=3 )
map1 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[1] , out_2_l3 ) ) , axis=3 )
map2 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[2] , out_2_l3 ) ) , axis=3 )
map3 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[3] , out_2_l3 ) ) , axis=3 )
map4 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[4] , out_2_l3 ) ) , axis=3 )
map5 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[5] , out_2_l3 ) ) , axis=3 )
map6 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[6] , out_2_l3 ) ) , axis=3 )
map7 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[7] , out_2_l3 ) ) , axis=3 )
map8 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[8] , out_2_l3 ) ) , axis=3 )
map9 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[9] , out_2_l3 ) ) , axis=3 )
map10 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[10] , out_2_l3 ) ) , axis=3 )
map11 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[11] , out_2_l3 ) ) , axis=3 )
map12 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[12] , out_2_l3 ) ) , axis=3 )
map13 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[13] , out_2_l3 ) ) , axis=3 )
map14 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[14] , out_2_l3 ) ) , axis=3 )
map15 = tf.reduce_sum ( tf.abs (tf.subtract( out_b1h1_l3[15] , out_2_l3 ) ) , axis=3 )
totoal_map =tf.div( tf.concat([map0, map1, map2, map3, map4, map5, map6, map7,
map8, map9, map10,map11,map12, map13, map14, map15], 0) , 32)
loss = tf.nn.l2_loss(totoal_map - labels , name = 'loss' )
#ValueError: No gradients provided for any variable, check your graph for ops that do not support gradients, between variables
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(loss )
init = tf.global_variables_initializer()
batchsize = 3
with tf.Session() as sess:
#writer = tf.summary.FileWriter("./variable_graph",graph = sess.graph)
sess.run(init)
#load image from dataset(train set)
joint_data_path = "./custom_data.json"
train_val_path = "./train_val_indices.json"
imgpath = "./000/"
input_size = 301
hint_roi_size = 23
hintSet01_norm_batch = []
hintSet02_norm_batch = []
t_img_batch = []
t_label_norm_batch = []
#load data
hintSet01,hintSet02,t_img,t_label_norm = training_data_feeder(joint_data_path, train_val_path, imgpath, input_size, hint_roi_size )
#Normalize the image pixel values to 0~1
hintSet01_norm = []
hintSet02_norm = []
t_img = np.float32(t_img /255.0)
for rois in hintSet01:
tmp = np.float32(rois / 255.0)
hintSet01_norm.append(tmp.tolist())
for rois in hintSet02:
tmp = np.float32(rois / 255.0)
hintSet02_norm.append(tmp.tolist())
print(tf.trainable_variables())
temp = sess.run(totoal_map , feed_dict={inputs_s: [t_img] ,
inputs_b1h1: hintSet01_norm,
labels: t_label_norm
})
print(temp)
print(np.shape(temp))
Код: https://github.com/gitpharm01/Parapose/blob/master/paraposeNetworkV3.py
График Tensorflow: https://github.com/gitpharm01/Parapose/blob/master/variable_graph/events.out.tfevents.1540296979.pharmboy-K30AD-M31AD-M51AD
Набор данных:
Это настраиваемый набор данных, созданный из набора данных mpii. В нем 223 кластера изображений. В каждом кластере есть один постоянный человек в разных позах, а фон остается прежним. В одном кластере не менее 3 картинок. Это примерно 627МБ и я попробую запаковать и выложить позже.
2018.10.26 Редактировать:
Вы можете скачать его на GoogleDrive, весь набор данных был разделен на 9 частей. (Я не могу разместить больше 8 ссылок в этой статье. Ссылки находятся в этом файле: https://github.com/gitpharm01/Parapose/blob/master/000/readme.md