

200行写一个自动微分工具
source link: https://www.tuicool.com/articles/beM3yam
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

简介
机器学习工具包(PyTorch/TensorFlow)一般都具有自动微分(Automatic Differentiation)机制,自动微分方法包括 手动求解法 (Manual Differentiation)、 数值微分法 (Numerical Differentiation)、 符号微法 (Symbolic Differentiation)、 自动微分法 (Automatic Differentiation),具体的详细介绍可以参见 自动微分(Automatic Differentiation)简介 ,这里主要说一下自动微分法的实现。
自动微分法实现
github地址:https://github.com/tiandiweizun/autodiff
git上有不少自动微分的实现,如 autograd ,但 AutodiffEngine 更适合作为教程,但AutodiffEngine是静态图,整个过程对于初学者还是有点复杂的,主要是不直观,于是动手 autodiff 写了一个简单的动态图的求导,里面的大部分算子的实现还是参照AutodiffEngine的。
设计:其实主要是2个类,一个类 Tensor 用于保存数据,另一个类 OP 支持forward和backward,然后各种具体的运算类,如加减乘除等继承OP,然后实现具体的forward和backward过程
过程:分为forward和backward两个过程,forward从前往后计算得到最终的输出,并返回新的tensor(如下图中的v1),新的tensor保存通过哪些子tensor(v-1),哪个具体的算子(ln)计算得到的(计算图),backward按照计算图计算梯度,并赋值给对应的子tensor(v-1)
实现:
先贴一点代码
class Tensor: def __init__(self, data, from_tensors=None, op=None, grad=None): self.data = data # 数据 self.from_tensors = from_tensors # 是从什么Tensor得到的,保存计算图的历史 self.op = op # 操作符运算 # 梯度 if grad: self.grad = grad else: self.grad = numpy.zeros(self.data.shape) if isinstance(self.data, numpy.ndarray) else 0 def __add__(self, other): # 先判断other是否是常数,然后再调用 return add.forward([self, other]) if isinstance(other, Tensor) else add_with_const.forward([self, other]) def backward(self, grad=None): # 判断y的梯度是否存在,如果不存在初始化和y.data一样类型的1的数据 if grad is None: self.grad = grad = numpy.ones(self.data.shape) if isinstance(self.data, numpy.ndarray) else 1 # 如果op不存在,则说明该Tensor为根节点,其from_tensors也必然不存在,否则计算梯度 if self.op: grad = self.op.backward(self.from_tensors, grad) if self.from_tensors: for i in range(len(grad)): tensor = self.from_tensors[i] # 把梯度加给对应的子Tensor,因为该Tensor可能参与多个运算 tensor.grad += grad[i] # 子Tensor进行后向过程 tensor.backward(grad[i]) # 清空梯度,训练的时候,每个batch应该清空梯度 def zero_gard(self): self.grad = numpy.zeros(self.data.shape) if isinstance(self.data, numpy.ndarray) else 0
class OP: def forward(self, from_tensors): pass def backward(self, from_tensors, grad): pass class Add(OP): def forward(self, from_tensors): return Tensor(from_tensors[0].data + from_tensors[1].data, from_tensors, self) def backward(self, from_tensors, grad): return [grad, grad] add = Add()
这里以加法为例,讲一下具体的实现。
Tensor类有四个属性,分别用于保存数据、子Tensor、操作符、梯度,OP类有两个方法,分别是forward和backword,其中Add类继承OP,实现了具体的forward和backword过程,然后Tensor重载了加法运算,如果是两个Tensor相加,则调用Add内部的forward。
x1_val = 2 * np.ones(3) x2_val = 3 * np.ones(3) x1 = Tensor(x1_val) x2 = Tensor(x2_val) # x1+x2 调用了Add的forward方法,并用[5,5,5]、x1与x2、加法操作构造新的Tensor,然后赋值给y y = x1 + x2 assert np.array_equal(y.data, x1_val + x2_val)
backward过程先是计算梯度,然后把梯度赋值给各个子Tensor
# 判断梯度是否存在,此时不存在则初始化为[1,1,1] # 调用Add的backward计算得到梯度[[1,1,1],[1,1,1]] # 把梯度累加给对应的子Tensor,并调用x1和x2的backward # 由于此时梯度存在,则不需要初始化 # 由于x1和x2无op和from_tensors,停止并退出 y.backward() assert np.array_equal(x1.grad, np.ones_like(x1_val)) assert np.array_equal(x2.grad, np.ones_like(x2_val))
add_with_const和其他运算符参见代码
利用现有的自动求导来训练一个线性回归模型,绝大部分代码来自于 AutodiffEngine 里面的lr_autodiff.py,其中gen_2d_data方法用于生成数据,每个样例有3维,其中第一维是bias,test_accuracy判断sigmoid(w*x)是否大于0.5来决定分类的类别,并于y进行对比计算准确率。
我这里仅修改了auto_diff_lr方法,去掉了动态图里面的逻辑,并换成Tensor来封装。
下图为训练日志和训练结果
Recommend
-
98
只用200行Go代码写一个自己的区块链! O...
-
13
当前,PyTorch、TensorFlow等机器学习框架已经成为了人们开发的重要工具。计算反向传播、贝叶斯推理、不确定性量化和概率编程等算法的梯度时,我们需要把所有的代码以微分型写入框架内。这对于将机器学习引入新领域带来了问题:在物理模拟、游戏引...
-
8
撰文 |
-
12
5.3. 自动微分¶ 上一节,我们介绍了机器学习框架的中间表示,设计这些中间表示的最核心的目的之一便是服务于自动微分...
-
7
第一篇自动微分原理文章中我们大概初步谈了谈从手动微分到自动微分的过程,第二篇自动微分正反模式中深入了自动微分...
-
6
撰文 | 郑建华 更新|...
-
6
图解自动微分的正向模式和逆向模式 自动微分建立在复合函数求导的链式规则之上,考虑以下复合函数 f(x)=a(b(c(x))) 则 f 对 x 的导数为 dfdx=dfdadadbdbdcdcdx 显然,上述公式存在两种计算顺序,第一种先对高阶函...
-
7
1 自动微分 我们在《数值分析》课程中已经学过许多经典的数值微分方法。许多经典的数值微分算法非常快,因为它们只需要计算差商。然而,他们的主要缺点在于他们是数值的,这意味着有限的算术精度和不精确的函数求值,而这些都从根本上限制...
-
6
自动微分(Automatic Differentiation,下面简称 AD)是用来计算偏导的一种手段,在深度学习框架中广泛使用(如 Pytorh, Tensorflow)。最近想学习这些框架的实现,先从 AD 入手,框架的具体实现比较复杂,我们主要是理解 AD 的思想并做个简单的实现。
-
8
自动微分(Automatic Differentiation):实现篇前情提要:在算法篇中,我们介绍了深度学习领域基本都是使用自动微分(Automati...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK