<aside> <img src="/icons/condense_yellow.svg" alt="/icons/condense_yellow.svg" width="40px" /> Python | C++ | 漂移扩散 | 方程 | 公式 | 期权 | 套利 | 定价权 | 算法 | 正向累积 | 反向累积 | 回归 | 分类 | 生成对抗网络 | 几何 | 网格
</aside>
🎯漂移扩散方程计算微分 | 🎯期权无风险套利公式计算微分 | 🎯实现图结构算法微分 | 🎯实现简单正向和反向计算微分 | 🎯实现简单回归分类和生成对抗网络计算微分 | 🎯几何网格计算微分
pie showdata
title 语言分比
"Python":42
"C++":38
"CMake":20
算法微分在机器学习领域尤为重要。例如,它允许人们在神经网络中实现反向传播,而无需手动计算导数。
计算微分的基础是复合函数偏导数链式法则提供的微分分解。简单结构如:
$$ \begin{aligned} y & =f(g(h(x)))=f\left(g\left(h\left(w_0\right)\right)\right)=f\left(g\left(w_1\right)\right)=f\left(w_2\right)=w_3 \\ w_0 & =x \\ w_1 & =h\left(w_0\right) \\ w_2 & =g\left(w_1\right) \\ w_3 & =f\left(w_2\right)=y \end{aligned} $$
由链式法则得出:
$$ \frac{\partial y}{\partial x}=\frac{\partial y}{\partial w_2} \frac{\partial w_2}{\partial w_1} \frac{\partial w_1}{\partial x}=\frac{\partial f\left(w_2\right)}{\partial w_2} \frac{\partial g\left(w_1\right)}{\partial w_1} \frac{\partial h\left(w_0\right)}{\partial x} $$
通常,存在两种不同的计算微分模式:正向累积和反向累积。
正向累积指定从内到外遍历链式法则(即首先计算 $\partial w_1 / \partial x$,然后计算 $\partial w_2 / \partial w_1$,最后计算 $\partial y / \partial w_2$ ),而反向累积是从外到内的遍历(首先计算 $\partial y / \partial w_2$,然后计算 $\partial w_2 / \partial w_1$,最后计算 $\partial w_1 / \partial x$)。更简洁地说,
正向累积计算递归关系:$\frac{\partial w_i}{\partial x}=\frac{\partial w_i}{\partial w_{i-1}} \frac{\partial w_{i-1}}{\partial x}$ 且$w_3=y$
反向累积计算递归关系:$\frac{\partial y}{\partial w_i}=\frac{\partial y}{\partial w_{i+1}} \frac{\partial w_{i+1}}{\partial w_i}$ 且 $w_0=x$
正向累积在一次传递中计算函数和导数(但每个仅针对一个独立变量)。相关方法调用期望表达式 Z 相对于变量 V 导出。该方法返回一对已求值的函数及其导数。该方法递归遍历表达式树,直到到达变量。如果请求相对于此变量的导数,则其导数为 1,否则为 0。然后求偏函数以及偏导数。
伪代码:
tuple<float,float> evaluateAndDerive(Expression Z, Variable V) {
if isVariable(Z)
if (Z = V) return {valueOf(Z), 1};
else return {valueOf(Z), 0};
else if (Z = A + B)
{a, a'} = evaluateAndDerive(A, V);
{b, b'} = evaluateAndDerive(B, V);
return {a + b, a' + b'};
else if (Z = A - B)
{a, a'} = evaluateAndDerive(A, V);
{b, b'} = evaluateAndDerive(B, V);
return {a - b, a' - b'};
else if (Z = A * B)
{a, a'} = evaluateAndDerive(A, V);
{b, b'} = evaluateAndDerive(B, V);
return {a * b, b * a' + a * b'};
}
Python实现正向累积:
class ValueAndPartial:
def __init__(self, value, partial):
self.value = value
self.partial = partial
def toList(self):
return [self.value, self.partial]
class Expression:
def __add__(self, other):
return Plus(self, other)
def __mul__(self, other):
return Multiply(self, other)
class Variable(Expression):
def __init__(self, value):
self.value = value
def evaluateAndDerive(self, variable):
partial = 1 if self == variable else 0
return ValueAndPartial(self.value, partial)
class Plus(Expression):
def __init__(self, expressionA, expressionB):
self.expressionA = expressionA
self.expressionB = expressionB
def evaluateAndDerive(self, variable):
valueA, partialA = self.expressionA.evaluateAndDerive(variable).toList()
valueB, partialB = self.expressionB.evaluateAndDerive(variable).toList()
return ValueAndPartial(valueA + valueB, partialA + partialB)
class Multiply(Expression):
def __init__(self, expressionA, expressionB):
self.expressionA = expressionA
self.expressionB = expressionB
def evaluateAndDerive(self, variable):
valueA, partialA = self.expressionA.evaluateAndDerive(variable).toList()
valueB, partialB = self.expressionB.evaluateAndDerive(variable).toList()
return ValueAndPartial(valueA * valueB, valueB * partialA + valueA * partialB)
# Example: Finding the partials of z = x * (x + y) + y * y at (x, y) = (2, 3)
x = Variable(2)
y = Variable(3)
z = x * (x + y) + y * y
xPartial = z.evaluateAndDerive(x).partial
yPartial = z.evaluateAndDerive(y).partial
print("∂z/∂x =", xPartial) # Output: ∂z/∂x = 7
print("∂z/∂y =", yPartial) # Output: ∂z/∂y = 8