Ошибка «Нет градиентов для любой переменной» при обучении СИАМСКОЙ СЕТИ - PullRequest
0 голосов
/ 24 октября 2018

В настоящее время я строю модель на платформе Tensorflow (версия: 1.8 os: Ubuntu MATE16.04).Целью модели является обнаружение / сопоставление ключевых точек человеческого тела.Во время обучения произошла ошибка «Нет градиентов для какой-либо переменной», и у меня возникли трудности с ее исправлением.

Справочная информация о модели : основные идеи были взяты из этих двух статей:

  1. глубокое изучение двоичных хэш-кодов для быстрого поиска изображений
  2. изучение компактных двоичных дескрипторов с неконтролируемыми глубокими нейронными сетями

Они показали, что можно сопоставлять изображения в соответствии с хэш-кодами, сгенерированными из сверточной сети.Сходство двух изображений определяется расстоянием Хэмминга между соответствующими им хэш-кодами.

Я думаю, что можно разработать чрезвычайно легковесную модель для оценки человеческой позы в реальном времени на видео с «постоянным человеческим субъектом»."и" фиксированный фон ".


Структура модели

01. Источник данных:

3 изображения изодно видео с тем же человеческим сюжетом и похожим фоном.Ключевые точки каждого человека на каждом изображении хорошо обозначены.2 изображения будут использоваться в качестве «источников подсказок», а последнее изображение будет целью для обнаружения / сопоставления ключевых точек.

02. Подсказки:

23x23pixelРИ будут вырезаны из изображений «источника подсказки» в соответствии с расположением ключевых точек человека.Центром этих ROI являются ключевые точки.

03. сверточная сеть "для подсказок":

Простая 3-уровневая структура.Первые два слоя свернуты с помощью [2,2] шага с фильтром 3х3.Последний слой представляет собой свертку 5x5 на входе 5x5 без заполнения (равняется полностью подключенному слою)

Это превратит 23x23-пиксельную ROI Hint в один 32-битный хэш-код.Одно изображение подсказки генерирует набор из 16 хеш-кодов.

04. Сверточная сеть "для целевого изображения": Сеть делит веса smae с сетью подсказок.Но в этом случае каждый слой свертки имеет отступы.Изображение 301x301pixel будет преобразовано в "хэш-карту" 76x76

05. Соответствие хеш-функции:

Я создал функцию под названием "locateMin_and_get_loss", чтобы вычислить расстояние Хемминга между«Подсказка хэш» и хэш-коды в каждой точке хэш-карты.Эта функция создаст «карту расстояний».Местоположение точки с наименьшим значением расстояния будет рассматриваться как местоположение ключевой точки.

06. Расчет потерь:

Я сделал функцию "get_total_loss_and_result" длярассчитать общую потерю 16 ключевых точек.Потери представляют собой нормированное евклидово расстояние между точками наземных истинных меток и точками, расположенными моделью.

07. Предлагаемый рабочий процесс:

Перед инициализацией этой модели пользовательсделает два снимка целевого человека с разных ракурсов.Изображения будут помечены современными моделями, такими как OpenPose или DeepPose, и генерировать из них хэш-подсказки с использованием сети свертки, упомянутой в 03.

Наконец, поток видео будет запущен и обработан моделью.

08. Почему «два» набора подсказок?

Один человеческий сустав / ключевая точка, наблюдаемая под разными углами, будет иметь очень различный вид.Вместо того, чтобы увеличивать размерность нейронной сети, я хочу «обмануть игру», собирая две подсказки вместо одной.Я хочу знать, может ли это повысить точность и обобщающую способность модели или нет.


Проблемы, с которыми я столкнулся:

01. "Нет«Градиенты для любой переменной» ошибка (мой главный вопрос к этому посту) :

Как уже упоминалось выше, я сталкиваюсь с этой ошибкой при обучении модели.Я пытался учиться на таких сообщениях, как это и это и это .Но в настоящее время я понятия не имею, хотя я проверил вычислительный график.

02.Проблема "Batch":

Из-за своей уникальной структуры трудно использовать обычный заполнитель для хранения вводаданные нескольких партий.Я исправил это, установив номер партии в 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

1 Ответ

0 голосов
/ 04 ноября 2018

Я использовал «нетерпеливое выполнение», описанное в https://www.tensorflow.org/guide/eager, чтобы проверить градиент.

В конце концов, я обнаружил, что «tf.round» и «tf.nn.relu6» сотрут или установятградиент к нулю.

Я внес некоторые изменения в код, и теперь я могу перейти к этапу обучения:

import tensorflow as tf
import numpy as np
import time
from imageLoader import getPaddedROI,training_data_feeder
import math
import cv2
'''
created by Cid Zhang 
a sub-model for human pose estimation
'''
tf.reset_default_graph()

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_b1h2 = tf.placeholder(tf.float32, ( 16, roi_size, roi_size, 3), name='inputs_b1h2')


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(inputs, inputs_s):
    with tf.variable_scope('conv'):
        out_l1 = tf.layers.conv2d(inputs, 16, [3, 3],strides=(2, 2), padding ='valid' ,name='para_conv_1')
        out_l1r = tf.nn.relu(out_l1)
        out_l2 = tf.layers.conv2d(out_l1r, 48, [3, 3],strides=(2, 2), padding ='valid' ,name='para_conv_2')
        out_l2r = tf.nn.relu(out_l2)
        out_l3 = tf.layers.conv2d(out_l2r, 96, [5, 5],strides=(1, 1), padding ='valid' ,name='para_conv_3')
        out_l3r = tf.nn.relu(out_l3)
        out_l4 = tf.layers.conv2d(out_l3r, 32, [1, 1],strides=(1, 1), padding ='valid' ,name='para_conv_4')
        out_l4r = tf.squeeze(  tf.sign( tf.sigmoid(out_l4) ) )

    with tf.variable_scope('conv', reuse=True):
        out_2_l1 = tf.layers.conv2d(inputs_s,  16, [3, 3],strides=(2, 2), padding ='same' ,name='para_conv_1')
        out_2_l1r = tf.nn.relu(out_2_l1)
        out_2_l2 = tf.layers.conv2d(out_2_l1r, 48, [3, 3],strides=(2, 2), padding ='same' ,name='para_conv_2')
        out_2_l2r = tf.nn.relu(out_2_l2)
        out_2_l3 = tf.layers.conv2d(out_2_l2r, 96, [5, 5],strides=(1, 1), padding ='same' ,name='para_conv_3')
        out_2_l3r = tf.nn.relu(out_2_l3)
        out_2_l4 = tf.layers.conv2d(out_2_l3r, 32, [1, 1],strides=(1, 1), padding ='same' ,name='para_conv_4')
        out_2_l4r =tf.sign( tf.sigmoid(out_2_l4))
    return out_l4r , out_2_l4r  

def lossFunc(inputs_hint, inputs_sample, labels):    
    hint, sample = paraNet(inputs_hint, inputs_sample)

    map0 = tf.reduce_sum ( tf.abs (tf.subtract( hint[0] , sample ) ) , axis=3 )  
    map1 = tf.reduce_sum ( tf.abs (tf.subtract( hint[1] , sample ) ) , axis=3 )  
    map2 = tf.reduce_sum ( tf.abs (tf.subtract( hint[2] , sample ) ) , axis=3 )  
    map3 = tf.reduce_sum ( tf.abs (tf.subtract( hint[3] , sample ) ) , axis=3 )  
    map4 = tf.reduce_sum ( tf.abs (tf.subtract( hint[4] , sample ) ) , axis=3 )  
    map5 = tf.reduce_sum ( tf.abs (tf.subtract( hint[5] , sample ) ) , axis=3 )  
    map6 = tf.reduce_sum ( tf.abs (tf.subtract( hint[6] , sample ) ) , axis=3 )  
    map7 = tf.reduce_sum ( tf.abs (tf.subtract( hint[7] , sample ) ) , axis=3 )  
    map8 = tf.reduce_sum ( tf.abs (tf.subtract( hint[8] , sample ) ) , axis=3 )  
    map9 = tf.reduce_sum ( tf.abs (tf.subtract( hint[9] , sample ) ) , axis=3 )  
    map10 = tf.reduce_sum ( tf.abs (tf.subtract( hint[10] , sample ) ) , axis=3 )  
    map11 = tf.reduce_sum ( tf.abs (tf.subtract( hint[11] , sample ) ) , axis=3 )  
    map12 = tf.reduce_sum ( tf.abs (tf.subtract( hint[12] , sample ) ) , axis=3 )  
    map13 = tf.reduce_sum ( tf.abs (tf.subtract( hint[13] , sample ) ) , axis=3 )  
    map14 = tf.reduce_sum ( tf.abs (tf.subtract( hint[14] , sample ) ) , axis=3 )  
    map15 = tf.reduce_sum ( tf.abs (tf.subtract( hint[15] , sample ) ) , 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) , 64)
    loss = tf.nn.l2_loss( totoal_map -  labels , name = 'loss'  )
    return loss, totoal_map

loss, totoal_map = lossFunc(inputs_b1h1, inputs_s, labels)
train_step = tf.train.GradientDescentOptimizer(2.0).minimize(loss)

#init =  tf.global_variables_initializer()

saver = tf.train.Saver()

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
    '''
    #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) ]
    #print(type(t_img))
    #print(np.shape(t_img))
    #print(type(t_label_norm))
    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())

    loss_value , total_map_value = sess.run ([loss, totoal_map], feed_dict = {inputs_s:  t_img, 
                                                                                                  inputs_b1h1: hintSet01_norm, 
                                                                          labels:     t_label_norm
                                                                          })
    print("-----loss value:",loss_value)
    print("-----total_map_value:", total_map_value[0,0] )
    print("-----label_value", t_label_norm[0,0] )
    #cv2.imshow("t_img",t_img[0])
    #for img in t_label_norm:
    #    print(img)
    #    cv2.imshow("hint", img)
    #    cv2.waitKey(0)

    #print(tf.trainable_variables())
    #print(hash_set01)
    #print(out_2_l3)
    '''
    saver.restore(sess, "./temp_model/model4.ckpt")


    for i in range(1000):

        #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) ]
        #print(type(t_img))
        #print(np.shape(t_img))
        #print(type(t_label_norm))
        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())
        loss_val, _ = sess.run([loss, train_step] , 
                      feed_dict = {inputs_s:  t_img, 
                                   inputs_b1h1: hintSet01_norm, 
                                   labels: t_label_norm })
        if i % 50 == 0:
            print(loss_val)

    save_path = saver.save(sess, "./temp_model/model" + '5' + ".ckpt")
    #print(temp)
    #print(np.shape(temp))

Но, к сожалению, значение потерь не уменьшалось во время обучения.

Я думаю, что в коде все еще есть ошибки.Сохраненный файл контрольных точек всегда называется «XXXX.ckpt.data-00000-of-00001», независимо от того, как долго будет установлена ​​итерация.

Я сделаю еще один пост об этом, так как основная проблема этогосообщение решено.

...