torch.nn.Module的__call__和forward有什么区别?为什么要这样设计?torch.nn.Module的__call__和forward有什么区别?为什么要这样设计?
__call__,实际算的是 forward用户写的是 model(x),Python 会调用 model.__call__(x)。nn.Module 的 __call__ 内部会做一堆前后处理,最后再调 self.forward(x)。所以:
__call__:入口,负责 hook、training 模式、类型转换、最终调用 forward 等,不要在子类里重写(除非你很清楚在做什么)。forward:子类必须重写,这里写「输入到输出的计算逻辑」;真正参与计算图、被 Autograd 记录的是 forward 里的运算。一句话:__call__ = 框架层壳子,forward = 你写的数学/计算。
__call__ 里通常做了哪些事?(以常见 PyTorch 实现为准,细节可能随版本略有差异。)
forward_pre_hook、forward_hook,便于调试、可视化、插层。result = self.forward(*input, **kwargs)。所以若子类重写 __call__ 而不调 forward,或改了调用顺序,hook 和 Autograd 都可能错乱;规范做法是只重写 forward。
__call__ 统一处理「所有 Module 都要做的事」(hook、模式、检查),forward 只关心「这一层怎么算」,代码清晰、扩展方便。__call__ 里固定了 hook 的调用时机,用户和第三方库只要注册 hook,不用改 forward;若逻辑写在 forward 里,每个子类都要记得调 hook,容易漏。__call__ 里加新逻辑(如编译、图捕获),所有子类自动受益;若大家都重写 __call__,就难以统一升级。面试可答:__call__ 是框架入口负责通用逻辑和 hook,forward 是子类实现的纯计算;这样 hook 和扩展都集中在入口,子类只写数学。
model(x) 触发的是 __call__(x),内部再调 forward(x);不要重写 __call__,只重写 forward。__call__ 负责:重复调用检查、forward_pre_hook / forward_hook、调用 forward、以及可能的类型/设备处理。model(x) → Module.__call__(x) → 做 hook 与检查 → self.forward(x)。forward;重写 __call__ 容易破坏 hook 与 Autograd。| 返回模块 | 返回总览 |