自动微分

  • 数值微分:利用导数极限公式,计算导数。优点:简单直观,对复杂函数也有效。缺点:计算量大,舍入误差(round-off error,浮点计算过程带来的误差),截断误差(truncation error,近似带来的误差)。
  • 符号微分:对常见函数给出求导函数,然后利用链式法则生成复杂函数的求导函数。优点:准确无误。缺点:生成的求导函数复杂,计算量大。
  • 自动微分:利用链式法则逐步计算导数(以数值方式保留中间计算结果,而非生成求导函数)。包含前向自动微分、反向自动微分两种形式。

前向自动微分:先对内侧/底层函数求导,以数值方式保留导数,利用链式法则,依次向外/向上求导。外侧的局部导数乘以内侧的全局导数,得到外侧的全局导数(此处全局是指当前函数对内侧根部参数求导)。优点:随着前向计算,可以同时进行微分计算,简单直观。缺点:对每个参数,都要进行一遍计算(因为内侧全局导数是针对某一个参数的)。

反向自动微分:先对外侧/顶层函数求导,以数值方式保留导数,利用链式法则,依次向内/向下求导。外侧的全局导数乘以内侧的局部导数,得到内侧的全局导数(此处全局是指外部叶子函数对当前节点求导)。当前深度学习框架主流的自动微分形式,和我们手动对复杂公式求导的过程类似。优点:一遍计算,即可得到每个册数的导数(因为外侧全局导数不是针对某一个参数的)。缺点:需要保留前向计算结果,直到最内侧导数计算完成。

Demo实现

PyTorch计算图

Pytorch Codes:

  • torch/_tensor.py
  • torch/autograd/init.py:
  • torch/csrc/autograd/autograd.h
  • torch/csrc/autograd/autograd.cpp:run_backward()调用engine执行反向传播
  • torch/csrc/autograd/engine.h:反向传播图遍历执行
  • torch/csrc/autograd/function.h:Node定义,以及建立Edge(next_edge同反向传播方向)。
  • torch/csrc/autograd/variable.h:gradient_edge同反向传播方向
  • torch/csrc/autograd/edge.h:Edge定义
  • aten/src/ATen/core/TensorBase.h

custom_function:

  • 针对前向传播,Function::apply -> 1. next_edges=collect_next_edges(inputs) 2. set_ctx_grad_fn(node) 3. node->set_next_edges(std::move(next_edges)) 4. forward -> _wrap_outputs -> _process_backward_mode_ad:给output设置grad_fn -> Variable.set_gradient_edge(variable, edge)/grad_accumular
  • 针对反向传播,CppNode::apply -> backward
    Function: collect_next_edges(variable):获取node的input的edges -> Variable.gradient_edge(variable)

autograd: backward()/grad() -> run_backward -> Engine::excute

engine: Engine::excute -> GraphTask::execute_with_graph_task -> GraphTask::thread_main(graph_task) -> while(NodeTask task = local_ready_queue->pop();) -> Engine::evaluate_function -> 1. output=Engine::call_function 2. input_buffer.add(std::move(output)) -> queue->push(NodeTask(next.function, input_buffer))

Edge(grad_fn, input_nr)

Node.next_edges[]: 针对反向计算图,第i个next_edge代表node_current/grad_fn_current的第i个输出(grad_input),该next_edge的grad_fn代第i个输出对应的grad_fn_next,input_nr代表grad_fn_next的第几个输入(grad_output)

Variable:针对反向计算图,root(如loss)和leaf(如weight)的Variable都加入到计算图中,设置edge。

  • Variable.set_gradient_edge(variable, edge):给variable设置gran_fn。
  • Variable.set_grad_accumulator(variable, grad_accumulator):给variable设置给variable设置grad_accumulator。
  • Variable.gradient_edge(variable):返回variable的(grad_fn/grad_accumulator, input_nr), 针对反向计算图,对于非叶子节点,grad_fn代表产生这个variable的fn对应的grad_fn,input_nr代表grad_fn的第几个输入。对于叶子节点,返回variable的grad_accumulator(累加梯度),input_nr只能为0。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容