2016-07-13 5 views
7

Я хотел бы реализовать в TensorFlow технику «управляемого обратного распространения», представленную в этом Paper и описанную в этом recipe.Ведомое обратное распространение в TensorFlow

Вычислительно, что означает, что когда я вычисляю градиент, например, входной сигнал. выход NN, я должен будет изменить градиенты, вычисленные в каждом блоке RELU. Конкретно, обратный сигнал на этих устройствах должен быть установлен на ноль, чтобы этот метод работал. Другими словами, частную производную от RELU, отрицательных, следует игнорировать.

Учитывая, что я заинтересован в применении этих вычислений градиента только на примерах тестов, то есть я не хочу обновлять параметры модели - как это сделать?

Я пытался (безуспешно) две вещи до сих пор:

  1. Использование tf.py_func, чтобы обернуть мою простую версию Numpy из более РЕЛУ, который затем имеет право пересмотреть это градиент операции через г .gradient_override_map менеджер контекста.

  2. Соберите значения обратного хода и обратные значения BackProp и примените пороговое значение для тех, которые связаны с Relus.

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

Может ли кто-нибудь предложить любой другой маршрут или набросать код?

Большое спасибо.

ответ

5

tf.gradients имеет параметр grad_ys, который может быть использован для этой цели. Предположим, что ваша сеть имеет только один слой relu следующим образом:

before_relu = f1(inputs, params) 
after_relu = tf.nn.relu(before_relu) 
loss = f2(after_relu, params, targets) 

Во-первых, вычислить производную до after_relu.

Dafter_relu = tf.gradients(loss, after_relu)[0] 

Тогда порог ваших градиентов, которые вы отправляете.

Dafter_relu_thresholded = tf.select(Dafter_relu < 0.0, 0.0, Dafter_relu) 

Compute фактические градиенты w.r.t к params.

Dparams = tf.gradients(after_relu, params, grad_ys=Dafter_relu_thresholded) 

Вы можете легко расширить этот же метод для сети с большим количеством relu слоев.

+0

Привет, Kaveman, спасибо за быстрый ответ. В последнем вызове tf.gradients вы намеренно передаете Dafter_relu в качестве первого аргумента? – Peter

+1

Кроме того, я все еще смущен. как обобщить это в сети со многими слоями таким образом, который работает для любого NN, который имеет элементы RELU. Для этой части вам не нужно будет отслеживать все входные/выходные данные каждого элемента RELU и «цепочку» вашей ранее описанной логики? Благодарю. – Peter

+0

@Peter, извините, это была опечатка. Второй вызов 'tf.gradients' -' after_relu' w.r.t. 'Params'. – keveman

5

Лучшее решение (ваш подход 1) с ops.RegisterGradient и tf.Graph.gradient_override_map. Вместе они переопределяют вычисление градиента для заранее заданного Op, например. Relu в контексте gradient_override_map, используя только код python.

@ops.RegisterGradient("GuidedRelu") 
def _GuidedReluGrad(op, grad): 
    return tf.where(0. < grad, gen_nn_ops._relu_grad(grad, op.outputs[0]), tf.zeros(grad.get_shape())) 

... 
with g.gradient_override_map({'Relu': 'GuidedRelu'}): 
    y = tf.nn.relu(x) 

вот полный пример реализации управляемой РЕЛУ: https://gist.github.com/falcondai/561d5eec7fed9ebf48751d124a77b087

Update: в Tensorflow> = 1,0, tf.select переименован в tf.where. Я обновил фрагмент соответственно. (Спасибо @sbond за то, что привлекли это мое внимание :)

+2

Остерегайтесь того, что вам нужно обернуть конструкцию графа, включающую контекст relu op * внутри * gradient_override_map. – Falcon

+1

Спасибо, @Falcon, это хорошо работает. Мне также пришлось заменить tf.select на tf.where, поскольку я использую TF версию 1.2. – sbond

+0

@sbond Спасибо за обновление. Я отредактировал мое сообщение, чтобы включить ваш комментарий. – Falcon

 Смежные вопросы

  • Нет связанных вопросов^_^