Python自动微分与闭包

举报
黄生 发表于 2026/09/07 09:07:54 2026/09/07
【摘要】 通过实现一个简单的自动微分系统,深入理解Python的闭包机制与命名规范。本文核心代码源自micrograd项目 https://gitcode.com/GitHub_Trending/mic/micrograd 一、核心实现:Value类class Value: def __init__(self, data, _children=(), _op='', label=''): ...

通过实现一个简单的自动微分系统,深入理解Python的闭包机制与命名规范。

本文核心代码源自micrograd项目 https://gitcode.com/GitHub_Trending/mic/micrograd

一、核心实现:Value类

class Value:
    def __init__(self, data, _children=(), _op='', label=''):
        self.data = data
        self.grad = 0.0
        self._backward = lambda: None
        self._prev = set(_children)
        self._op = _op
        self.label = label
        
    def __repr__(self):
        return f"Value(data={self.data})"
        
    def __add__(self, other):
        out = Value(self.data + other.data, (self, other), '+')
        
        def _backward():
            self.grad += 1.0 * out.grad
            other.grad += 1.0 * out.grad
        
        out._backward = _backward
        return out

二、闭包:函数内部的函数

_backward定义在__add__内部,形成闭包:

def __add__(self, other):
    out = Value(...)
    
    def _backward():          # 内部函数
        self.grad += out.grad  # 捕获外部变量
        other.grad += out.grad
    
    out._backward = _backward  # 存储函数引用,而非调用
    return out

闭包三要素:

  • 函数作为一等公民
  • 捕获定义时的环境变量
  • 支持延迟执行

闭包vs普通调用:

out._backward = _backward    # ✅ 存储函数,延迟执行
out._backward = _backward()  # ❌ 立即执行,梯度全为0

三、为什么用闭包?

每个节点独立管理自己的反向传播逻辑:

a = Value(2); b = Value(3)
c = a + b  # c._backward 捕获 a, b, c

d = Value(4)
e = c + d  # e._backward 捕获 c, d, e

# 反向传播链式执行
e.grad = 1.0
e._backward()  # 计算 c, d 的梯度
c._backward()  # 计算 a, b 的梯度

每个闭包记住自己的操作数和结果,形成完整的计算图。

四、命名规范:下划线的含义

命名形式 含义 示例
variable 公开API obj.data
_variable 内部使用(约定) obj._backward
__variable 名称修饰(防冲突) obj.__secret
__variable__ Python魔术方法 obj.__add__

原则: 语法上无区别,语义上有约定。Python相信开发者会遵守规范。

v = Value(5)
v.data = 10        # ✅ 公开属性
v._backward = None # ⚠️ 可以但不应这样做

五、闭包的跨语言背景

闭包不是Python独创,而是编程语言的共同财富:

  • 1960年代:概念萌芽于ALGOL 60
  • 1975年:Scheme语言正式实现
  • 1991年:Python引入闭包
  • 1995年:JavaScript原生支持

现代主流语言均支持闭包:JavaScript、Python、Java(8+)、C++(11+)、Rust、Go等。

六、关键要点

  1. 前向传播:构建计算图,每个节点存储_backward闭包
  2. 反向传播:按拓扑序调用_backward()计算梯度
  3. 闭包优势:捕获上下文,避免显式传参
  4. 命名约定_开头标识内部实现细节
  5. 延迟执行:存储函数引用,需要时再调用
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。