Автоматическое дифференцирование

редактировать

В математике и компьютерной алгебре, автоматическое дифференцирование (AD), также называемое алгоритмическое дифференцирование, вычислительное дифференцирование, автоматическое дифференцирование или просто autodiff, представляет собой набор методов для численной оценки производная функции, заданной компьютерной программой. AD использует тот факт, что каждая компьютерная программа, независимо от ее сложности, выполняет последовательность элементарных арифметических операций (сложение, вычитание, умножение, деление и т. Д.) И элементарных функций (exp, log, sin, cos и т. Д.). Путем многократного применения правила цепочки к этим операциям производные произвольного порядка могут быть вычислены автоматически с точностью до рабочей точности и с использованием не более небольшого постоянного множителя для большего числа арифметических операций, чем в исходной программе.

Рисунок 1: Как автоматическое дифференцирование связано с символическим дифференцированием

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

Содержание
  • 1 Правило цепочки, прямое и обратное накопление
    • 1.1 Прямое накопление
    • 1.2 Обратное накопление
    • 1.3 Помимо прямого и обратного накопления
  • 2 Автоматическое дифференцирование с использованием двойных чисел
    • 2.1 Векторные аргументы и функции
    • 2.2 Высокий порядок и множество переменных
  • 3 Реализация
    • 3.1 Преобразование исходного кода (SCT)
    • 3.2 Перегрузка оператора (OO)
  • 4 Примечания
  • 5 Ссылки
  • 6 Дополнительная литература
  • 7 Внешние ссылки
Правило цепочки, прямое и обратное накопление

В основе AD лежит разложение дифференциалов, обеспечиваемое правилом цепочки. Для простой композиции

y = f (g (h (x))) = f (g (h (w 0))) = f (g (w 1)) = f (w 2) = w 3 w 0 знак равно XW 1 знак равно час (вес 0) вес 2 знак равно г (вес 1) вес 3 знак равно е (вес 2) = Y {\ Displaystyle {\ begin {align} y = f (g (h (x))) = f (g (h (w_ {0}))) = f (g (w_ {1})) = f (w_ {2}) = w_ {3} \\ w_ {0} = x \\ w_ { 1} = h (w_ {0}) \\ w_ {2} = g (w_ {1}) \\ w_ {3} = f (w_ {2}) = y \ end {выровнено}}}{\ displaystyle {\ begin {выровнено} y = f (g (h (x))) = f (g (h (w_ {0}))) = f (g (w_ {1})) = f (w_ {2}) = w_ {3} \\ w_ {0} = x \\ w_ {1} = h (w_ {0}) \\ w_ {2} = g (w_ {1}) \\ w_ {3 } = f (w_ {2}) = y \ end {align}}}

цепное правило дает

dydx = dydw 2 dw 2 dw 1 dw 1 dx = df (w 2) dw 2 dg (w 1) dw 1 dh (w 0) dx {\ displaystyle {\ frac {dy) } {dx}} = {\ frac {dy} {dw_ {2}}} {\ frac {dw_ {2}} {dw_ {1}}} {\ frac {dw_ {1}} {dx}} = { \ frac {df (w_ {2})} {dw_ {2}}} {\ frac {dg (w_ {1})} {dw_ {1}}} {\ frac {dh (w_ {0})} { dx}}}{\ displaystyle {\ frac {dy} {dx}} = {\ frac {dy} {dw_ {2}}} {\ frac {dw_ {2} } {dw_ {1}}} {\ frac {dw_ {1}} {dx}} = {\ frac {df (w_ {2})} {dw_ {2}}} {\ frac {dg (w_ {1 })} {dw_ {1}}} {\ frac {dh (w_ {0})} {dx}}}

Обычно представлены два различных режима AD: прямое накопление (или прямой режим ) и обратное накопление (или реверсивный режим ). Прямое накопление указывает, что каждый проходит по правилу цепочки изнутри наружу (то есть сначала вычисляется dw 1 / dx {\ displaystyle dw_ {1} / dx}{\ displaystyle dw_ {1} / dx} , а затем dw 2 / dw 1 {\ displaystyle dw_ {2} / dw_ {1}}{\ displaystyle dw_ {2} / dw_ {1}} и, наконец, dy / dw 2 {\ displaystyle dy / dw_ {2}}{\ displaystyle dy / dw_ {2}} ), а обратное накопление имеет обход снаружи внутрь (сначала вычисляем dy / dw 2 {\ displaystyle dy / dw_ {2}}{\ displaystyle dy / dw_ {2}} , а затем dw 2 / dw 1 {\ displaystyle dw_ { 2} / dw_ {1}}{\ displaystyle dw_ {2} / dw_ {1}} и, наконец, dw 1 / dx {\ displaystyle dw_ {1} / dx}{\ displaystyle dw_ {1} / dx} ). Более лаконично,

  1. накопление вперед вычисляет рекурсивное отношение : dwidx = dwidwi - 1 dwi - 1 dx {\ displaystyle {\ frac {dw_ {i}} {dx}} = {\ гидроразрыв {dw_ {i}} {dw_ {i-1}}} {\ frac {dw_ {i-1}} {dx}}}{\ displaystyle {\ frac {dw_ {i}} {dx}} = {\ frac {dw_ {i}} {dw_ {i-1}}} {\ frac {dw_ {i-1}} {dx}}} с w 3 = y {\ displaystyle w_ {3} = y}{\ displaystyle w_ {3} = y} , а
  2. обратное накопление вычисляет рекурсивное отношение : dydwi = dydwi + 1 dwi + 1 dwi {\ displaystyle {\ frac {dy} { dw_ {i}}} = {\ frac {dy} {dw_ {i + 1}}} {\ frac {dw_ {i + 1}} {dw_ {i}}}}{\ displaystyle {\ frac {dy} {dw_ {i}}} = {\ frac {dy} {dw_ {i + 1}}} {\ frac {dw_ {я + 1}} {dw_ {i}}}} с w 0 = x {\ displaystyle w_ {0} = x}{\ displaystyle w_ {0} = x} .

Как правило, как прямое, так и обратное накопление являются конкретными проявлениями применения оператора композиции программы, фиксирующего соответствующее одно из двух сопоставлений (w, y) {\ displaystyle (w, y)}{\ displaystyle (w, y)} .

Прямое накопление

Рисунок 2: Пример прямого накопления с вычислительным графом

При прямом накоплении AD сначала фиксируется независимая переменная с помощью относительно которого выполняется дифференцирование, и вычисляет производную ive каждого под- выражения рекурсивно. При ручном вычислении это включает в себя многократную замену производной внутренних функций в цепном правиле:

∂ y ∂ x = ∂ y ∂ wn - 1 ∂ wn - 1 ∂ x = ∂ y ∂ wn - 1 (∂ wn - 1 ∂ wn - 2 ∂ wn - 2 ∂ x) = ∂ y ∂ wn - 1 (∂ wn - 1 ∂ wn - 2 (∂ wn - 2 ∂ wn - 3 ∂ wn - 3 ∂ x)) Знак равно ⋯ {\ Displaystyle {\ frac {\ partial y} {\ partial x}} = {\ frac {\ partial y} {\ partial w_ {n-1}}} {\ frac {\ partial w_ {n-1 }} {\ partial x}} = {\ frac {\ partial y} {\ partial w_ {n-1}}} \ left ({\ frac {\ partial w_ {n-1}} {\ partial w_ {n -2}}} {\ frac {\ partial w_ {n-2}} {\ partial x}} \ right) = {\ frac {\ partial y} {\ partial w_ {n-1}}} \ left ( {\ frac {\ partial w_ {n-1}} {\ partial w_ {n-2}}} \ left ({\ frac {\ partial w_ {n-2}} {\ partial w_ {n-3}}) } {\ frac {\ partial w_ {n-3}} {\ partial x}} \ right) \ right) = \ cdots}{\ displaystyle {\ frac {\ partial y} {\ partial x}} = {\ frac {\ partial y} {\ partial w_ {n-1}}} {\ frac {\ partial w_ {n-1}} {\ partial x}} = {\ frac {\ partial y} {\ частичный w_ {n-1}}} \ left ({\ frac {\ partial w_ {n-1}} {\ partial w_ {n-2}}} {\ frac {\ partial w_ {n-2}} {\ partial x}} \ right) = {\ frac {\ partial y} {\ partial w_ {n-1}}} \ left ({\ frac {\ partial w_ { n-1}} {\ partial w_ {n-2}}} \ left ({\ frac {\ partial w_ {n-2}} {\ partial w_ {n-3}}}} {\ frac {\ partial w_ {n-3}} {\ partial x}} \ right) \ right) = \ cdots}

Это можно обобщить на несколько переменных как матричное произведение якобианов.

По сравнению с обратным накоплением, прямое накопление является естественным и легко реализуемым, поскольку поток производной информации совпадает с t Порядок оценки. Каждая переменная w дополняется ее производной ẇ (сохраняется как числовое значение, а не как символическое выражение),

w ˙ = ∂ w ∂ x {\ displaystyle {\ dot {w}} = {\ frac {\ partial w } {\ partial x}}}{\ dot w } = {\ frac {\ partial w} {\ partial x}}

как обозначено точкой. Затем производные вычисляются синхронно с этапами оценки и комбинируются с другими производными с помощью цепного правила.

В качестве примера рассмотрим функцию:

z = f (x 1, x 2) = x 1 x 2 + sin ⁡ x 1 = w 1 w 2 + sin ⁡ w 1 = w 3 + вес 4 знак равно вес 5 {\ Displaystyle {\ begin {align} z = f (x_ {1}, x_ {2}) \\ = x_ {1} x_ {2} + \ sin x_ {1} \\ = w_ {1} w_ {2} + \ sin w_ {1} \\ = w_ {3} + w_ {4} \\ = w_ {5} \ end {align}}}{\ begin {align} z = f (x_ {1}, x_ {2}) \\ = x_ {1} x_ {2} + \ sin x_ {1} \\ = w_ {1} w_ {2} + \ sin w_ {1} \\ = w_ {3} + w_ {4} \\ = w_ {5} \ end {a ligned}}

Для ясности, отдельные подвыражения были помечены переменными w i.

. Выбор независимой переменной, для которой выполняется дифференцирование, влияет на начальные значения ẇ 1 и ẇ 2. Учитывая интерес к производной этой функции по x 1, начальные значения должны быть установлены на:

w ˙ 1 = ∂ x 1 ∂ x 1 = 1 w ˙ 2 = ∂ x 2 ∂ Икс 1 знак равно 0 {\ Displaystyle {\ begin {align} {\ dot {w}} _ {1} = {\ frac {\ partial x_ {1}} {\ partial x_ {1}}} = 1 \\ {\ dot {w}} _ {2} = {\ frac {\ partial x_ {2}} {\ partial x_ {1}}} = 0 \ end {align}}}{\ begin {align} {\ dot w} _ {1} = {\ frac {\ частичный x_ {1}} {\ partial x_ {1}}} = 1 \\ {\ dot w} _ {2} = {\ frac {\ partial x_ {2}} {\ partial x_ {1}}} = 0 \ конец {выровнено}}

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

Операции для вычисления значения Операции для вычисления производной w 1 = x 1 w ˙ 1 = 1 (начальное число) w 2 = x 2 w ˙ 2 = 0 (начальное значение) w 3 = w 1 ⋅ w 2 w ˙ 3 = w 2 ⋅ w ˙ 1 + w 1 ⋅ w ˙ 2 w 4 = sin ⁡ w 1 w ˙ 4 = cos ⁡ w 1 ⋅ w ˙ 1 w 5 = w 3 + w 4 w ˙ 5 = w ˙ 3 + w ˙ 4 {\ displaystyle {\ begin {array} {l | l} {\ text {Операции для вычисления значения}} {\ text {Операции для вычисления производной}} \\\ hline w_ {1} = x_ {1} { \ dot {w}} _ {1} = 1 {\ text {(seed)}} \\ w_ {2} = x_ {2} {\ dot {w}} _ {2} = 0 {\ text { (начальное число)}} \\ w_ {3} = w_ {1} \ cdot w_ {2} {\ dot {w}} _ {3} = w_ {2} \ cdot {\ dot {w}} _ { 1} + w_ {1} \ cdot {\ dot {w}} _ {2} \\ w_ {4} = \ sin w_ {1} {\ dot {w}} _ {4} = \ cos w_ { 1} \ cdot {\ dot {w}} _ {1} \\ w_ {5} = w_ {3} + w_ {4} {\ dot {w}} _ {5} = {\ dot {w} } _ {3} + {\ dot {w}} _ {4} \ end {array}}}{\ displaystyle {\ begin {array } {l | l} {\ text {Операции для вычисления значения}} {\ text {Операции для вычисления производной}} \\\ hline w_ {1} = x_ {1} {\ dot {w}} _ { 1} = 1 {\ text {(seed)}} \\ w_ {2} = x_ {2} {\ dot {w}} _ {2} = 0 {\ text {(seed)}} \\ w_ {3} = w_ {1} \ cdot w_ {2} {\ dot {w}} _ {3} = w_ {2} \ cdot {\ dot {w}} _ {1} + w_ {1} \ cdot {\ dot {w}} _ {2} \\ w_ {4} = \ sin w_ {1} {\ dot {w}} _ {4} = \ cos w_ {1} \ cdot {\ dot { w}} _ {1} \\ w_ {5} = w_ {3} + w_ {4} {\ dot {w}} _ {5} = {\ dot {w}} _ {3} + {\ точка {w}} _ {4} \ end {array}}}

Чтобы вычислить градиент этой функции примера, которая требует производных от f по отношению не только для x 1, но также для x 2, дополнительное сканирование выполняется по вычислительному графу с использованием начальных значений w 1 = 0; w ˙ 2 = 1 {\ displaystyle {\ dot {w}} _ {1} = 0; {\ dot {w}} _ {2} = 1}{\ dot w} _ {1} = 0; {\ dot w} _ {2} = 1 .

вычислительная сложность единицы развертка прямого накопления пропорциональна сложности исходного кода.

Прямое накопление более эффективно, чем обратное накопление для функций f: ℝ → ℝ с m ≫ n, поскольку необходимы только n разверток по сравнению с m развертками для обратного накопления.

Обратное накопление

Рисунок 3: Пример обратного накопления с вычислительным графом

При обратном накоплении AD зависимая переменная, подлежащая дифференцированию, фиксируется, а производная вычисляется по каждому под- выражение рекурсивно. При вычислении на бумаге производная внешних функций многократно подставляется в цепное правило:

∂ y ∂ x = ∂ y ∂ w 1 ∂ w 1 ∂ x = (∂ y ∂ w 2 ∂ w 2 ∂ вес 1) ∂ вес 1 ∂ Икс знак равно ((∂ Y ∂ вес 3 ∂ вес 3 ∂ вес 2) ∂ вес 2 ∂ вес 1) ∂ вес 1 ∂ x = ⋯ {\ displaystyle {\ frac {\ partial y} {\ partial x}} = {\ frac {\ partial y} {\ partial w_ {1}}} {\ frac {\ partial w_ {1}} {\ partial x}} = \ left ({\ frac {\ частичный y} {\ partial w_ {2}}} {\ frac {\ partial w_ {2}} {\ partial w_ {1}}} \ right) {\ frac {\ partial w_ {1}} {\ partial x }} = \ left (\ left ({\ frac {\ partial y} {\ partial w_ {3}}} {\ frac {\ partial w_ {3}} {\ partial w_ {2}}} \ right) { \ frac {\ partial w_ {2}} {\ partial w_ {1}}} \ right) {\ frac {\ partial w_ {1}} {\ partial x}} = \ cdots}{\ frac {\ partial y} {\ partial x}} = {\ frac {\ partial y } {\ partial w_ {1}}} {\ frac {\ partial w_ {1}} {\ partial x}} = \ left ({\ frac {\ partial y} {\ partial w_ {2}}} {\ frac {\ partial w_ {2}} {\ partial w_ {1}}} \ right) {\ frac {\ partial w_ {1}} {\ partial x}} = \ left (\ left ({\ frac {\ частичный y} {\ partial w_ {3}}} {\ frac {\ partial w_ {3}} {\ partial w_ {2}}} \ right) {\ frac {\ partial w_ {2}} {\ partial w_ {1}}} \ right) {\ frac {\ partial w_ {1}} {\ partial x}} = \ cdots

При обратном накоплении интересующая нас величина - сопряженная, обозначенная чертой (w̄); это производная выбранной зависимой переменной относительно подвыражения w:

w ¯ = ∂ y ∂ w {\ displaystyle {\ bar {w}} = {\ frac {\ partial y} {\ partial w} }}{\ bar w} = {\ frac {\ partial y} {\ partial w}}

Обратное накопление проходит по правилу цепочки извне внутрь или, в случае вычислительного графа на рисунке 3, сверху вниз. В примере функции используется скалярное значение, поэтому для вычисления производной используется только одно начальное значение, а для вычисления (двухкомпонентного) градиента требуется только одно сканирование вычислительного графа. Это только половина работы по сравнению с прямым накоплением, но обратное накопление требует хранения промежуточных переменных w i, а также инструкций, которые их создали в структуре данных, известной как список Венгерта (или «лента»), который может потреблять значительный объем памяти, если вычислительный граф большой. Это можно смягчить до некоторой степени, сохраняя только подмножество промежуточных переменных, а затем восстанавливая необходимые рабочие переменные путем повторения оценок, метод, известный как рематериализация. Контрольная точка также используется для сохранения промежуточных состояний.

Операции по вычислению производной с использованием обратного накопления показаны в таблице ниже (обратите внимание на обратный порядок):

Операции по вычислению производной w ¯ 5 = 1 (начальное значение) w ¯ 4 = w ¯ 5 вес ¯ 3 знак равно вес ¯ 5 вес ¯ 2 = вес ¯ 3 ⋅ вес 1 вес ¯ 1 = вес ¯ 3 ⋅ вес 2 + вес ¯ 4 ⋅ соз ⁡ вес 1 {\ displaystyle {\ begin {array} {l} {\ text {Операции для вычисления производной}} \\\ hline {\ bar {w}} _ {5} = 1 {\ text {(seed)}} \\ {\ bar {w}} _ {4} = {\ бар {w}} _ {5} \\ {\ bar {w}} _ {3} = {\ bar {w}} _ {5} \\ {\ bar {w}} _ {2} = {\ бар {w}} _ {3} \ cdot w_ {1} \\ {\ bar {w}} _ {1} = {\ bar {w}} _ {3} \ cdot w_ {2} + {\ bar {w}} _ {4} \ cdot \ cos w_ {1} \ end {array}}}{\ displaystyle {\ begin {array} {l} {\ text {Операции для вычисления производной}} \\\ hline {\ bar {w}} _ {5} = 1 {\ text {(seed)}} \\ {\ bar {w}} _ {4} = {\ bar {w}} _ {5} \\ {\ bar {w}} _ {3} = {\ bar {w}} _ {5} \\ {\ bar {w}} _ {2} = {\ bar {w}} _ {3} \ cdot ш_ {1} \\ {\ бар {ш }} _ {1} = {\ bar {w}} _ {3} \ cdot w_ {2} + {\ bar {w}} _ {4} \ cdot \ cos w_ {1} \ end {array}} }

Графом потока данных вычисления можно управлять, чтобы вычислить градиент исходного вычисления. Это делается путем добавления сопряженного узла для каждого основного узла, соединенного смежными ребрами, которые параллельны основным ребрам, но текут в противоположном направлении. Узлы сопряженного графа представляют собой умножение на производные функций, вычисленных узлами в прямом. Например, сложение в основных причинах разветвления в смежных; разветвление в первичных причинах сложение в смежных; унарная функция y = f (x) в прямых причинах x̄ = ȳ f ′ (x) в сопряженном; и т.д.

Обратное накопление более эффективно, чем прямое накопление для функций f: ℝ → ℝ с m ≪ n, поскольку необходимы только m разверток, по сравнению с n развертками для прямого накопления.

Обратный режим AD был впервые опубликован в 1976 году Сеппо Линнаинмаа.

Обратное распространение ошибок в многослойных перцептронах, метод, используемый в машинном обучении, является особым случаем. обратного режима AD.

Помимо прямого и обратного накопления

Прямое и обратное накопление - это всего лишь два (крайних) способа обхода правила цепочки. Задача вычисления полного якобиана f: ℝ → ℝ с минимальным числом арифметических операций известна как задача оптимального якобиана накопления (OJA), которая является NP-полной. Центральным в этом доказательстве является идея о том, что между локальными частичными элементами, которые маркируют ребра графа, могут существовать алгебраические зависимости. В частности, две или более метки края могут быть признаны равными. Сложность проблемы остается открытой, если предположить, что все метки ребер уникальны и алгебраически независимы.

Автоматическое дифференцирование с использованием двойных чисел

Автоматическое дифференцирование в прямом режиме выполняется путем увеличения алгебры действительных чисел и получения новой арифметической . К каждому числу добавляется дополнительный компонент, чтобы представить производную функции по этому числу, и все арифметические операторы расширяются для расширенной алгебры. Расширенная алгебра - это алгебра двойных чисел.

. Замените каждое число x {\ displaystyle \, x}\,xчислом x + x ′ ε {\ displaystyle x + x '\ varepsilon}x + x'\varepsilon, где x ′ {\ displaystyle x'}x'- действительное число, но ε {\ displaystyle \ varepsilon}\ varepsilon - абстрактное число со свойством ε 2 = 0 {\ displaystyle \ varepsilon ^ {2} = 0}\ varepsilon ^ 2 = 0 (бесконечно малое ; см. Гладкий анализ бесконечно малых ). Используя только это, обычная арифметика дает

(x + x ′ ε) + (y + y ′ ε) = x + y + (x ′ + y ′) ε (x + x ′ ε) ⋅ (y + y ′ Ε) знак равно xy + xy ′ ε + yx ′ ε + x ′ y ′ ε 2 = xy + (xy ′ + yx ′) ε {\ displaystyle {\ begin {align} (x + x '\ varepsilon) + ( y + y '\ varepsilon) = x + y + (x' + y ') \ varepsilon \\ (x + x' \ varepsilon) \ cdot (y + y '\ varepsilon) = xy + xy' \ varepsilon + yx '\ varepsilon + x'y' \ varepsilon ^ {2} = xy + (xy '+ yx') \ varepsilon \ end {align}}}{\begin{aligned}(x+x'\varepsilon)+(y+y'\varepsilon)=x+y+(x'+y')\varepsilon \\(x+x'\varepsilon)\cdot (y+y'\varepsilon)=xy+xy'\varepsilon +yx'\varepsilon +x'y'\varepsilon ^{2}=xy+(xy'+yx')\varepsilon \end{aligned}}

и аналогично для вычитания и деления.

Теперь многочлены могут быть вычислены в этой расширенной арифметике. Если P (x) = p 0 + p 1 x + p 2 x 2 + ⋯ + pnxn {\ displaystyle P (x) = p_ {0} + p_ {1} x + p_ {2} x ^ { 2} + \ cdots + p_ {n} x ^ {n}}P (x) = p_0 + p_1 x + p_2x ^ 2 + \ cdots + p_n x ^ n , тогда

P (x + x ′ ε) = p 0 + p 1 (x + x ′ ε) + ⋯ + pn (x + x ′ ε) n = p 0 + p 1 x + ⋯ + pnxn + p 1 x ′ ε + 2 p 2 xx ′ ε + ⋯ + npnxn - 1 x ′ ε = P (x) + P (1) (Икс) Икс 'ε {\ Displaystyle {\ begin {Выровненный} P (х + х' \ varepsilon) = p_ {0} + p_ {1} (x + x '\ varepsilon) + \ cdots + p_ {n} (x + x '\ varepsilon) ^ {n} \\ = p_ {0} + p_ {1} x + \ cdots + p_ {n} x ^ {n} + p_ {1} x' \ varepsilon + 2p_ {2} xx '\ varepsilon + \ cdots + np_ {n} x ^ {n-1} x' \ varepsilon \\ = P (x) + P ^ {(1)} (x) x ' \ varepsilon \ end {align}}}{\begin{aligned}P(x+x'\varepsilon)=p_{0}+p_{1}(x+x'\varepsilon)+\cdots +p_{n}(x+x'\varepsilon)^{n}\\=p_{0}+p_{1}x+\cdots +p_{n}x^{n}+p_{1}x'\varepsilon +2p_{2}xx'\varepsilon +\cdots +np_{n}x^{{n-1}}x'\varepsilon \\=P(x)+P^{{(1)}}(x)x'\varepsilon \end{aligned}}

где P (1) {\ displaystyle P ^ {(1)}}P ^ {(1)} обозначает производную от P {\ displaystyle P}P относительно своего первого аргумента, и x ′ {\ displaystyle x '}x', называемый начальным значением, можно выбрать произвольно.

Новая арифметика состоит из упорядоченных пар, элементов, записанных ⟨x, x ′⟩ {\ displaystyle \ langle x, x '\ rangle}\langle x, x' \rangle, с обычной арифметикой для первого компонента и арифметикой дифференцирования первого порядка для второго компонента, как описано выше. Распространение приведенных выше результатов о полиномах на аналитические функции дает список основных арифметических и некоторых стандартных функций для новой арифметики:

⟨u, u ′⟩ + ⟨v, v ′⟩ = ⟨u + v, u ′ + v ′⟩ ⟨u, u ′⟩ - ⟨v, v ′⟩ = ⟨u - v, u ′ - v ′⟩ ⟨u, u ′⟩ ∗ ⟨v, v ′⟩ = ⟨uv, u ′ v + uv ′⟩ ⟨u, u ′⟩ / ⟨v, v ′⟩ = ⟨uv, u ′ v - uv ′ v 2⟩ (v ≠ 0) sin ⁡ ⟨u, u ′⟩ = ⟨sin ⁡ (u), u ′ cos ⁡ (u)⟩ cos ⁡ ⟨u, u ′⟩ = ⟨cos ⁡ (u), - u ′ sin ⁡ (u)⟩ exp ⁡ ⟨u, u ′⟩ = ⟨exp ⁡ u, u ′ exp ⁡ u⟩ log ⁡ ⟨u, u ′⟩ = ⟨log ⁡ (u), u ′ / u⟩ (u>0) ⟨u, u ′⟩ k = ⟨uk, kuk - 1 u ′ ⟩ (U ≠ 0) | ⟨U, u ′⟩ | = ⟨| u | U 'знак U⟩ (U ≠ 0) {\ Displaystyle {\ begin {align} \ left \ langle u, u' \ right \ rangle + \ left \ langle v, v '\ right \ rangle = \ left \ langle u + v, u '+ v' \ right \ rangle \\\ left \ langle u, u '\ right \ rangle - \ left \ langle v, v' \ right \ rangle = \ left \ langle uv, u '-v' \ right \ rangle \\\ left \ langle u, u '\ right \ rangle * \ left \ langle v, v' \ right \ rangle = \ left \ langle uv, u'v + uv '\ right \ rangle \\\ left \ langle u, u '\ right \ rangle / \ left \ langle v, v' \ right \ rangle = \ left \ langle {\ frac {u} {v}}, {\ frac {u'v-uv '} {v ^ {2}}} \ right \ rangle \ quad (v \ neq 0) \\\ sin \ left \ langle u, u' \ right \ rangle = \ left \ langle \ sin (u), u '\ cos (u) \ right \ rangle \\\ cos \ left \ langle u, u' \ right \ rangle = \ left \ langle \ cos (u), - u '\ sin (u) \ right \ rangle \\\ exp \ left \ langle u, u '\ right \ rangle = \ left \ langle \ exp u, u' \ exp u \ right \ rangle \\\ log \ left \ langle u, u '\ right \ rangle = \ left \ langle \ log (u), u' / u \ right \ rangle \ quad (u>0) \\\ left \ langle u, u '\ right \ rangle ^ {k} = \ left \ langle u ^ {k}, ku ^ {k-1} u '\ right \ rangle \ quad (u \ neq 0) \\\ left | \ left \ langle u, u' \ правый \ правый \ правый | = \ l eft \ langle \ left | u \ right |, u '{\ t_dv {sign}} u \ right \ rangle \ quad (u \ neq 0) \ end {выравнивается}}}{\begin{aligned}\left\langle u,u'\right\rangle +\left\langle v,v'\right\rangle =\left\langle u+v,u'+v'\right\rangle \\\left\langle u,u'\right\rangle -\left\langle v,v'\right\rangle =\left\langle u-v,u'-v'\right\rangle \\\left\langle u,u'\right\rangle *\left\langle v,v'\right\rangle =\left\langle uv,u'v+uv'\right\rangle \\\left\langle u,u'\right\rangle /\left\langle v,v'\right\rangle =\left\langle {\frac {u}{v}},{\frac {u'v-uv'}{v^{2}}}\right\rangle \quad (v\neq 0)\\\sin \left\langle u,u'\right\rangle =\left\langle \sin(u),u'\cos(u)\right\rangle \\\cos \left\langle u,u'\right\rangle =\left\langle \cos(u),-u'\sin(u)\right\rangle \\\exp \left\langle u,u'\right\rangle =\left\langle \exp u,u'\exp u\right\rangle \\\log \left\langle u,u'\right\rangle =\left\langle \log(u),u'/u\right\rangle \quad (u>0) \\ \ left \ langle u, u '\ right \ rangle ^ {k} = \ left \ langle u ^ {k}, ku ^ {{k-1}} u' \ right \ rangle \ quad (u \ neq 0) \\\ left | \ left \ langle u, u '\ right \ rangle \ right | = \ left \ langle \ left | u \ right |, u' {\ t_dv {sign}} u \ right \ rangle \ quad (u \ neq 0) \ end {align}}

и в целом для примитивной функции g {\ displaystyle g}g ,

g (⟨u, u ′⟩, ⟨v, v ′⟩) = ⟨g (u, v) гу (и, v) и '+ gv (и, v) v'⟩ {\ displaystyle g (\ langle u, u '\ rangle, \ langle v, v' \ rangle) = \ langle g (u, v), g_ {u} (u, v) u '+ g_ {v} (u, v) v' \ rangle}g(\langle u,u' \rangle, \langle v,v' \rangle) = \langle g(u,v), g_u(u,v) u' + g_v(u,v) v' \rangle

где gu {\ displaystyle g_ {u}}g_u и gv {\ displaystyle g_ {v}}g_v являются производными от g {\ displaystyle g}g по его первому и второму аргументам соответственно.

Когда к смешанным аргументам применяется базовая двоичная арифметическая операция - пара ⟨u, u ′⟩ {\ displaystyle \ langle u, u '\ rangle}\langle u, u' \rangleи действительное number c {\ displaystyle c}c - действительное число сначала поднимается до ⟨c, 0⟩ {\ displaystyle \ langle c, 0 \ rangle}\ langle c, 0 \ rangle . Производная функции f: R → R {\ displaystyle f: \ mathbb {R} \ rightarrow \ mathbb {R}}f: \ mathbb {R} \ rightarrow \ mathbb {R} в точке x 0 {\ displaystyle x_ { 0}}x_ {0} теперь находится путем вычисления f (⟨x 0, 1⟩) {\ displaystyle f (\ langle x_ {0}, 1 \ rangle)}f (\ langle x_0, 1 \ rangle) с использованием вышеуказанная арифметика, которая дает ⟨f (x 0), f ′ (x 0)⟩ {\ displaystyle \ langle f (x_ {0}), f '(x_ {0}) \ rangle}\langle f ( x_0), f' ( x_0) \rangle как результат.

Векторные аргументы и функции

Функции с несколькими переменными могут обрабатываться с той же эффективностью и механизмами, что и функции с одной переменной, путем принятия оператора производной по направлению. То есть, если достаточно вычислить y ′ = ∇ f (x) ⋅ x ′ {\ displaystyle y '= \ nabla f (x) \ cdot x'}y' = \nabla f(x)\cdot x', производную по направлению y ′ ∈ р м {\ displaystyle y '\ in \ mathbb {R} ^ {m}}y' \in \mathbb{R}^mиз f: R n → R m {\ displaystyle f: \ mathbb { R} ^ {n} \ rightarrow \ mathbb {R} ^ {m}}f: \ mathbb {R} ^ n \ rightarrow \ mathbb {R} ^ m в x ∈ R n {\ displaystyle x \ in \ mathbb {R} ^ {n}}x \ in \ mathbb {R} ^ n в направлении x ′ ∈ R n {\ displaystyle x '\ in \ mathbb {R} ^ {n}}x' \in \mathbb{R}^n, это может быть вычислено как (⟨y 1, y 1 ′⟩,…, ⟨ym, ym ′⟩) = f (⟨x 1, x 1 ′⟩,…, ⟨xn, xn ′⟩) {\ displaystyle (\ langle y_ {1}, y ' _ {1} \ rangle, \ ldots, \ langle y_ {m}, y '_ {m} \ rangle) = f (\ langle x_ {1}, x' _ {1} \ rangle, \ ldots, \ langle x_ {n}, x '_ {n} \ rangle)}(\langle y_1,y'_1\rangle, \ldots, \langle y_m,y'_m\rangle) = f(\langle x_1,x'_1\rangle, \ldots, \langle x_n,x'_n\rangle)используя ту же арифметику, что и выше. Если все элементы ∇ f {\ displaystyle \ nabla f}\ nabla f требуются, то требуются оценки функции n {\ displaystyle n}n. Обратите внимание, что во многих оптимизационных приложениях действительно достаточно производной по направлению.

Высокий порядок и многие переменные

Вышеупомянутая арифметика может быть обобщена для вычисления производных второго и более высокого порядка функций многих переменных. Однако арифметические правила быстро усложняются: сложность квадратична в высшей производной степени. Вместо этого может использоваться усеченная алгебра полиномов Тейлора. Результирующая арифметика, определенная для обобщенных двойных чисел, позволяет выполнять эффективные вычисления с использованием функций, как если бы они были типом данных. Как только полином Тейлора функции известен, производные легко извлекаются.

Реализация

AD прямого режима реализуется с помощью программы, в которой действительные числа заменяются двойными числами, константы повышаются до двойных чисел с нулевым эпсилон-коэффициентом и числовыми примитивами подняты для работы с двойными числами. Эта нестандартная интерпретация обычно реализуется с использованием одной из двух стратегий: преобразование исходного кода или перегрузка оператора.

Преобразование исходного кода (SCT)

Рисунок 4: Пример того, как может работать преобразование исходного кода

Исходный код для функции заменяется автоматически сгенерированным исходным кодом, который включает инструкции для вычисления производных чередующиеся с оригинальными инструкциями.

Преобразование исходного кода может быть реализовано для всех языков программирования, а также компилятору проще выполнять оптимизацию времени компиляции. Однако реализация самого инструмента AD сложнее.

Перегрузка оператора (OO)

Рисунок 5: Пример того, как может работать перегрузка оператора

Перегрузка оператора - это возможность для исходного кода, написанного на поддерживающем его языке. Объекты для действительных чисел и элементарных математических операций должны быть перегружены для обслуживания расширенной арифметики, изображенной выше. Это не требует изменения формы или последовательности операций в исходном исходном коде для дифференциации функции, но часто требует изменений в базовых типах данных для чисел и векторов для поддержки перегрузки, а также часто включает в себя вставку специальных операций маркировки.

Перегрузка оператора для прямого накопления легко реализуется, а также возможна для обратного накопления. Однако современные компиляторы отстают в оптимизации кода по сравнению с прямым накоплением.

Перегрузка операторов как для прямого, так и для обратного накопления может хорошо подходить для приложений, где объекты являются векторами действительных чисел, а не скалярами. Это потому, что лента содержит векторные операции; это может облегчить вычислительно эффективные реализации, в которых каждая векторная операция выполняет множество скалярных операций. Методы векторного сопряженного алгоритмического дифференцирования (векторного AAD) могут использоваться, например, для дифференцирования значений, вычисленных с помощью моделирования Монте-Карло.

Примерами реализаций автоматического дифференцирования с перегрузкой операторов в C ++ являются библиотеки Adept и Stan.

Примечания
Ссылки
Дополнительная литература
Внешние ссылки

.

Последняя правка сделана 2021-06-12 19:18:33
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте