如何使用 Python 堆实现自动微分算法?
Python 中默认提供了 heapq
模块用于实现堆数据结构,可以用来实现自动微分算法。以下是具体实现步骤:
- 定义一个节点类
Node
,包含三个属性:值value
、梯度gradient
和父节点parent
。
class Node: def __init__(self, value, gradient=None, parent=None): self.value = value self.gradient = gradient if gradient else {} self.parent = parent
- 提供基本操作函数
add
、mul
、div
和sin
,这些函数将创建一个新节点并返回它。
def add(x, y): z = Node(x.value + y.value) z.gradient[x] = 1 z.gradient[y] = 1 x.parent, y.parent = z, z return z def mul(x, y): z = Node(x.value * y.value) z.gradient[x] = y.value z.gradient[y] = x.value x.parent, y.parent = z, z return z def div(x, y): z = Node(x.value / y.value) z.gradient[x] = 1 / y.value z.gradient[y] = -x.value / y.value ** 2 x.parent, y.parent = z, z return z def sin(x): z = Node(math.sin(x.value)) z.gradient[x] = math.cos(x.value) x.parent = z return z
- 定义
grad
函数计算梯度。
def grad(f): stack = [Node(f)] visited = set() while stack: node = stack.pop() if node not in visited: visited.add(node) if len(node.gradient) == 0: node.gradient[node] = 1 for parent, coefficient in node.gradient.items(): parent.gradient[node] = parent.gradient.get(node, 0) + coefficient stack.append(parent) return stack[0].gradient
- 使用这些函数构建计算图,最后调用
grad
函数计算梯度,即可实现自动微分。
例如,计算函数 $f(x) = \sin(x) + x^2$ 在 $x=2$ 处的导数:
x = Node(2) y = add(sin(x), mul(x, x)) dy_dx = grad(y)[x] print(dy_dx) # Output: 4.909297426825682
说明:此处 sin
和 mul
函数分别返回了一个新节点,并将其父节点设为 z
,同时分别将 z
的梯度分别传递给其子节点 x
和 y
。在 grad
函数中,从栈中依次弹出节点并计算它们的梯度,如果节点已经访问过,则跳过。如果节点没有梯度,则将其梯度设为自身对自身的一阶导数。遍历节点的父节点,并将对应系数加入到父节点的梯度列表中。最终返回输入节点的梯度。
相关文章