Tensorflow — обучаемая переменная не изменяется со временем

#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 .