I'm trying to implement Dynamic Time Warping as a loss function for a dynamic_rnn() with an LSTMCell(). Basically it's a big loop that fills a matrix, then takes the last value as its score.
In a toy example the code works (matrix is generated and bottom right score is returned). However when using the loop as a loss function I get the error "ValueError: No gradients provided for any variable, check your graph for ops that do not support gradients,.."
I'm not sure if there are operations that do not support gradients (is there a list somewhere?), or that the weights and bias somehow cannot be found. As far as I know I do not need to specify them myself for dynamic_rnn() as the code works fine with a simple RMSE loss function.
This is what it looks like at the moment:
total_iterations = tf.constant((LENGTH_MAX_OUTPUT + 1) * (LENGTH_MAX_OUTPUT+1) * BATCH_SIZE)
iteration2 = tf.Variable(0, trainable=False)
cost = tf.constant(0, dtype=tf.float32)
cost_cum = tf.Variable(0, dtype=tf.float32, trainable=False)
cost_matrix = tf.Variable(np.ones(((LENGTH_MAX_OUTPUT+1) , (LENGTH_MAX_OUTPUT+1))), dtype=tf.float32, trainable=False)
batch_size = tf.constant(BATCH_SIZE, dtype=tf.float32)
it_batch_continue = lambda cost: tf.less(iteration2, total_iterations)
def get_value(it_row_nr, it_col_nr, it_batch_nr):
abs_diff = tf.abs(tf.subtract(decoder_targets[it_row_nr, it_batch_nr], decoder_predictions[it_col_nr, it_batch_nr]))
prev_row = cost_matrix[tf.subtract(it_row_nr, 1), it_col_nr]
prev_col = cost_matrix[it_row_nr, tf.subtract(it_col_nr, 1)]
prev_rowcol = cost_matrix[tf.subtract(it_row_nr, 1), tf.subtract(it_col_nr, 1)]
min_prev_row_col_rowcol = tf.minimum(tf.minimum(prev_col, prev_row), prev_rowcol)
z_z_condition = tf.logical_and(tf.less(it_row_nr, 1), tf.less(it_col_nr, 1))
z_z_true = lambda: abs_diff
z_z = tf.cond(z_z_condition, z_z_true, lambda: tf.constant(99999, dtype=tf.float32))
n_z_condition = tf.logical_and(tf.greater(it_row_nr, 0), tf.equal(it_col_nr, 0))
n_z_true = lambda: prev_row + abs_diff
n_z = tf.cond(n_z_condition, n_z_true, lambda: z_z)
z_n_condition = tf.logical_and(tf.equal(it_row_nr, 0), tf.greater(it_col_nr, 0))
z_n_true = lambda: prev_col + abs_diff
z_n = tf.cond(z_n_condition, z_n_true, lambda: n_z)
n_n_condition = tf.logical_and(tf.greater(it_row_nr, 0), tf.greater(it_col_nr, 0))
n_n_true = lambda: min_prev_row_col_rowcol + abs_diff
n_n = tf.cond(n_n_condition, n_n_true, lambda: z_n)
return(n_n) # Note that the False method calls one of the other methods
def iterate_batch(cost):
row_nr = iteration2 % (LENGTH_MAX_OUTPUT + 1)
col_nr = (iteration2 - row_nr) / (LENGTH_MAX_OUTPUT + 1) % (LENGTH_MAX_OUTPUT + 1)
batch_nr = (iteration2 - col_nr * (LENGTH_MAX_OUTPUT + 1) - row_nr) / ((LENGTH_MAX_OUTPUT + 1) * (LENGTH_MAX_OUTPUT + 1))
val = get_value(row_nr, col_nr, batch_nr)
update_cost_matrix = tf.assign(cost_matrix[row_nr,col_nr], val)
with tf.control_dependencies([update_cost_matrix]):
update_cost_cum = tf.assign_add(cost_cum, tf.cond(tf.logical_and(tf.equal(row_nr, LENGTH_MAX_OUTPUT), tf.equal(col_nr, LENGTH_MAX_OUTPUT)), lambda: cost_matrix[-1,-1], lambda: tf.constant(0.0)))
with tf.control_dependencies([update_cost_cum]):
cost = cost_cum / (batch_size+1.0)
update_iteration = tf.assign_add(iteration2,1)
with tf.control_dependencies([update_iteration]):
return tf.add(cost,0)
loss = tf.while_loop(it_batch_continue, iterate_batch, [cost])
train_op = tf.train.AdamOptimizer().minimize(loss)