дифференцирование детерминанта матрицы в тензорном потоке

Меня интересует вычисление производной определителя матрицы с использованием TensorFlow. Из экспериментов я вижу, что TensorFlow не реализовал метод дифференцирования через определитель:

LookupError: No gradient defined for operation 'MatrixDeterminant' 
(op type: MatrixDeterminant)

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

@tf.RegisterGradient("MatrixDeterminant")
def _sub_grad(op, grad):
    ...

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

Вот пример, когда я столкнулся с этой проблемой:

x = tf.Variable(tf.ones(shape=[1]))
y = tf.Variable(tf.ones(shape=[1]))

A = tf.reshape(
    tf.pack([tf.sin(x), tf.zeros([1, ]), tf.zeros([1, ]), tf.cos(y)]), (2,2)
)
loss = tf.square(tf.matrix_determinant(A))


optimizer = tf.train.GradientDescentOptimizer(0.001)
train = optimizer.minimize(loss)

init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)


for step in xrange(100):
    sess.run(train)
    print sess.run(x)

person user1936768    schedule 14.11.2015    source источник


Ответы (3)


Пожалуйста, проверьте раздел «Реализовать градиент в Python» здесь

В частности, вы можете реализовать это следующим образом

@ops.RegisterGradient("MatrixDeterminant")
def _MatrixDeterminantGrad(op, grad):
  """Gradient for MatrixDeterminant. Use formula from 2.2.4 from
  An extended collection of matrix derivative results for forward and reverse
  mode algorithmic differentiation by Mike Giles
  -- http://eprints.maths.ox.ac.uk/1079/1/NA-08-01.pdf
"""
  A = op.inputs[0]
  C = op.outputs[0]
  Ainv = tf.matrix_inverse(A)
  return grad*C*tf.transpose(Ainv)

Затем простой цикл обучения, чтобы проверить, что он работает:

a0 = np.array([[1,2],[3,4]]).astype(np.float32)
a = tf.Variable(a0)
b = tf.square(tf.matrix_determinant(a))
init_op = tf.initialize_all_variables()
sess = tf.InteractiveSession()
init_op.run()

minimization_steps = 50
learning_rate = 0.001
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train_op = optimizer.minimize(b)

losses = []
for i in range(minimization_steps):
  train_op.run()
  losses.append(b.eval())

Затем вы можете визуализировать свои потери с течением времени.

import matplotlib.pyplot as plt

plt.ylabel("Determinant Squared")
plt.xlabel("Iterations")
plt.plot(losses)

Должно появиться что-то вроде этого График потерь

person Yaroslav Bulatov    schedule 15.11.2015
comment
Очень круто! по какой-то причине документы на tf вызывают проблемы. например: по ссылкам выше tensorflow.org/ как_tos/adding_an_op/ - person Blaze; 19.11.2015

Я думаю, вы запутались с тем, что является производным определителя матрицы.

Определитель матрицы – это функция, вычисляемая над элементами матрицы по некоторой формуле. Итак, если все элементы матрицы являются числами, определитель даст вам только одно число, а производная будет равна 0. Когда некоторые элементы являются переменными, вы получите выражение этих переменных. Например:

x, x^2
1, sin(x)

Определитель будет x*sin(x) - x^2, а производная 2x + sin(x) + x*cos(x). Формула Якоби просто связывает определитель с вспомогательной матрицей.


В вашем примере ваша матрица A состоит только из чисел, поэтому определитель — это просто число, а loss — тоже просто число. GradientDescentOptimizer нужно иметь несколько свободных переменных для минимизации, а их нет, потому что loss — это просто число.

person Salvador Dali    schedule 15.11.2015
comment
Настоящая проблема здесь в том, что класс MatrixDeterminant не предоставляет зарегистрированный градиент. - person user1936768; 15.11.2015
comment
@user1936768 user1936768 да, это причина, по которой вы получили ошибку в своей проблеме с python, но это не настоящая причина. Предположим, что метод градиента существует. Он всегда будет возвращать вам 0, несмотря ни на что. Поможет ли это в ваших 100 итерациях? Как именно это минимизирует что-либо? - person Salvador Dali; 15.11.2015
comment
Нет, градиент не будет равен нулю. Я минимизирую по x и y, а матрица зависит от x и y через sin и cos соответственно. - person user1936768; 15.11.2015
comment
@user1936768 user1936768 внимательно посмотрите на свой пример. x и y — матрицы, состоящие только из чисел. - person Salvador Dali; 15.11.2015
comment
Это не то, как работает TensorFlow. Обратите внимание на оболочку Variable вокруг x и y. Учтите, что если я сделаю loss = tf.square(tf.reduce_sum(tf.matrix_inverse(A))), то я действительно буду двигаться к оптимальному решению x = 1.57079494, y = 1.09198811e-18, а это не то, для чего я инициализировал x или y. - person user1936768; 15.11.2015
comment
Во всяком случае, это не по делу. Мой пример был только примером. Легко представить (больше) ситуаций, когда матрица зависит от переменных. В этих случаях проблема заключается в том, что MatrixDeterminant не имеет градиента. - person user1936768; 15.11.2015
comment
@ Сальвадор, ты этого не понимаешь. Существует метод вычисления определителя, числа, из чисел во входной матрице. Мы говорим о производной определителя операции по каждому элементу входной матрицы, оцениваемой при текущем значении входа. Какая производная от x**2 при x=5? - person mdaoust; 18.11.2015

Для тех, кому интересно, я обнаружил решение, которое работает над моими проблемами:

@tf.RegisterGradient("MatrixDeterminant")
def _MatrixDeterminant(op, grad):
    """Gradient for MatrixDeterminant."""
    return op.outputs[0] * tf.transpose(tf.matrix_inverse(op.inputs[0]))
person user1936768    schedule 15.11.2015
comment
это не поддерживает правильно, если у вас есть что-то поверх детерминанта (т.е. если вы минимизируете квадрат детерминанта) - person Yaroslav Bulatov; 15.11.2015