#python #tensorflow
#python #tensorflow
Вопрос:
Я пытаюсь применить два разных метода маскирования к входному тензору, один из которых представляет собой полунормальный фильтр распределения, а другой — простую пошаговую функцию.
Хотя фильтр половины Гаусса работает нормально, при попытке применить фильтр пошаговой функции переменная (т. е. определяющая точку, в которой выполняется шаг), похоже, вообще не усваивается.
Это код фильтров:
def per_kernel_step_filter(input,weight_param=20,trainable=True):
input_shape = input.get_shape().as_list()
weight_param_v = tf.Variable(np.full((input_shape[-1]),weight_param), dtype=tf.float32, trainable=trainable)
weight_param_v_c = tf.clip_by_value(weight_param_v, 0, input_shape[-2])
kernel_filter = tf.transpose(tf.sequence_mask(weight_param_v_c, input_shape[-2], dtype=tf.float32))
kernel_filter = tf.reshape(kernel_filter,tf.concat([(1,1),kernel_filter.get_shape()],0))
output = input * kernel_filter
tf.summary.histogram("weight_param histogram", weight_param_v)
return output
И из tensorboard кажется, что она даже не привязана к оптимизатору Adam в конце.
и weight_param_v
не изменяется weight_param
.
Возможно ли, что из-за других операций, например sequence_mask
, переменная становится необучаемой?
Комментарии:
1. Да, я думаю, проблема в том, что
tf.sequence_mask
не дифференцируема, то есть нет аналитической функции, которая сообщает вам, насколько изменится результат (или потери), если вы примените небольшое изменение кweight_param_v
(вы можете проверить это с помощьюtf.gradients
).2. Одним (из нескольких) возможных дифференцируемых приближений к пошаговой функции является логистическая функция ( tf.math.sigmoid ), сдвинутая таким образом, что она центрируется вокруг точки шага. Вы можете манипулировать точками, в которых она вычисляется, чтобы контролировать, насколько она «крутая», хотя это повлияет на градиенты и, в свою очередь, на способность переменной к обучению.
3. jdehesa, для справки на будущее, не могли бы вы, пожалуйста, подробнее рассказать о том, как можно проверить, «перемещаются» ли градиенты за определенную точку? (и не только с использованием общей логики, что она не дифференцируема)
4. Допустим, вы хотите знать, является ли
my_function
дифференцируемым. Вы принимаете входные данныеx
(это может быть что угодно, например,tf.placeholder
или сделано с помощьюtf.zeros
) и выполняетеy = my_function(x)
, а затем проверяете значение, возвращаемоеtf.gradients(y, x)
. Если это так[None]
, то функция не дифференцируема. Если у вас есть несколько входных данных, вы можете передать список в качестве второго параметраtf.gradients
; в этом случае любойNone
из возвращаемого списка будет означать, что выходные данные нельзя дифференцировать по отношению к соответствующим входным данным.5. Сложная вещь, которая, я думаю, и есть то, что происходит с вами в этом случае, заключается в том, что обучение может сработать, даже если есть некоторые
None
градиенты. Пока существует некоторый допустимый градиент, TensorFlow предполагает, чтоNone
градиенты не имеют значения.
Ответ №1:
Проблема в этом случае заключается в том, что tf.sequence_mask
не дифференцируема, то есть нет аналитической функции, которая сообщает вам, насколько изменится результат (или потери), если вы примените небольшое изменение к weight_param_v
. Возможным обходным путем является использование вместо этого какой-либо функции sigmoid или smoothstep. Например, вы могли бы использовать логистическую функцию ( tf.math.sigmoid
), сдвинутую таким образом, чтобы она была сосредоточена вокруг точки шага, и вы можете манипулировать точками, в которых она вычисляется, чтобы контролировать, насколько она «крутая» (обратите внимание, это повлияет на градиенты и, в свою очередь, на способность переменной к обучению).
В общем, вы можете использовать tf.gradients
, чтобы проверить, является ли что-то дифференцируемым или нет. Например, если у вас есть функция my_function
, вы можете взять входные данные x
и определить y = my_function(x)
, затем проверить выходные данные tf.gradients(y, x)
; если это так [None]
, то функция не дифференцируема.
import tensorflow as tf
x = tf.placeholder(tf.float32, [None])
# Squaring is differentiable
print(tf.gradients(tf.square(x), x))
# [<tf.Tensor 'gradients/Square_grad/Mul_1:0' shape=(?,) dtype=float32>]
# Flooring is not differentiable
print(tf.gradients(tf.floor(x), x))
# [None]
# Sequence mask is not differentiable
print(tf.gradients(tf.sequence_mask(x, dtype=tf.float32), x))
# [None]
# Gather is differentiable for the parameters but not for the indices
x2 = tf.placeholder(tf.int32, [None])
print(tf.gradients(tf.gather(x, x2), [x, x2]))
# [<tensorflow.python.framework.ops.IndexedSlices object at 0x000001F6EDD09160>, None]
Сложная вещь, которая, я думаю, и была тем, что происходило с вами в этом случае, заключается в том, что обучение может работать, даже если есть некоторые None
градиенты. Пока существует некоторый допустимый градиент, TensorFlow (или, более конкретно, tf.train.Optimizer
и его подклассы) предполагает, что None
градиенты не имеют значения. Одна из возможных проверок, которую вы могли бы сделать, это вместо того, чтобы вызывать minimize
напрямую, вызвать compute_gradients
и проверить отсутствие None
градиентов перед вызовом apply_gradients
.