Как theano реализует вычисление градиента каждой функции?
У меня есть вопрос о реализации Theano. Как theano получает градиент каждой функции потерь с помощью следующей функции (T.grad)? Спасибо за помощь.
gparams = T.grad(cost, self.params)
2 ответа
Изменить: этот ответ был неверным, говоря, что Теано использует символическое дифференцирование. Мои извенения.
Theano реализует автодифференцирование в обратном режиме, но, как ни странно, они называют это "символическим дифференцированием" Это вводит в заблуждение, потому что символическая дифференциация - это нечто совершенно иное. Давайте посмотрим на оба.
Символическое дифференцирование: дан график, представляющий функцию f(x)
, он использует правило цепочки для вычисления нового графа, представляющего производную этой функции f'(x)
, Они называют это "компиляцией" f(x)
, Одна проблема с символическим дифференцированием состоит в том, что он может выводить очень неэффективный граф, но Theano автоматически упрощает выходной граф.
Пример:
"""
f(x) = x*x + x - 2
Graph =
ADD
/ \
MUL SUB
/ \ / \
x x x 2
Chain rule for ADD=> (a(x)+b(x))' = a'(x) + b'(x)
Chain rule for MUL=> (a(x)*b(x))' = a'(x)*b(x) + a(x)*b'(x)
Chain rule for SUB=> (a(x)-b(x))' = a'(x) - b'(x)
The derivative of x is 1, and the derivative of a constant is 0.
Derivative graph (not optimized yet) =
ADD
/ \
ADD SUB
/ | | \
MUL MUL 1 0
/ | | \
1 x x 1
Derivative graph (after optimization) =
ADD
/ \
MUL 1
/ \
2 x
So: f'(x) = 2*x + 1
"""
Autodiff в обратном режиме: работает за два прохода по графу вычислений, сначала продвигаясь вперед по графу (от входов к выходам), а затем назад, используя правило цепочки (если вы знакомы с обратным распространением, это именно то, как он вычисляет градиенты).
Смотрите этот великий пост для более подробной информации о различных решениях для автоматического дифференцирования и их плюсах и минусах.
Посмотрите Автоматическое дифференцирование и там режим назад, который используется для эффективной оценки градиентов.
Насколько я понимаю, Theano представляет собой гибрид между переписыванием кода и операторским подходом. Он использует перегрузку операторов в python для построения вычислительного графа, затем оптимизирует его и генерирует из этого графа (оптимизированные) последовательности операций для оценки требуемых чернил производных.