为了理解深度学习框架的大致机理,决定使用numpy实现一个简单的神经网络框架

深度学习框架我觉得最重要的是实现了链式求导法则,而计算图就是建立在链式求导法则之上的,目前大多数深度学习是基于反向传播思想的,如何在链式计算图中进行前向传播和反向传播是深度学习框架重点要考虑的

计算图

目前主流的深度学习框架有两种计算图实现方式:静态图:先构建好图再让数据流入,优点是结构清晰,理论上速度占优(实际不一定);缺点是debug困难,对初学者学习不友好(我认为主要是对计算图的理解不深刻导致的)。典型的框架代表:Tensorflow

动态图:程序按照编写的顺序动态执行,优点是所见所得,可以随时输出动态结果,调试方便,典型的框架代表:PyTorch

个人现在更倾向于使用tensorflow,一方面是tensorflow生态较成熟,另一方面个人感觉静态图更数学化,而动态图更工程化

不过本文实现的是一个类似pytorch风格的动态图框架

知识储备

链式求导法则

[begin{align*}

& f{'} = f(x) \\

& g{'} = g(f{'}) \\

& y{'} = k(g{'}) \\

& loss = L(y, y{'})

end{align*}]

用链式求导法则计算可得

[begin{align*}

frac{d(loss)}{d(x)} = frac{d(f{'})}{d(x)} times frac{d(g{'})}{d(f{'})} times frac{d(y{'})}{d(g{'})} times frac{d(loss)}{y{'}}\\

tag{1}

end{align*}

]

常见的激活函数

激活函数几乎都是非线性且尽可能全局可导的,激活函数的选择是很重要的,sigmoid, tanh 由于自身函数的特点,只有很小的区间梯度变化比较明显,大部分的区间梯度变化很小很容易造成梯度消失,本人更倾向于使用relu,或者是 batch normalization和tanh搭配使用

sigmoid

[sigma (z) = frac{1}{1+e^{-z}} tag{2}]

用matplotlib画出它的图像1

2

3

4

5

6

7

8

9

10

11

12

13import numpy as np

import matplotlib.pyplot as plt

def (x):

return 1. / (1. + np.exp(-x))

x = np.arange(-10, 10, 0.2)

y = sigmoid(x)

plt.plot(x, y, label="sigmoid", color="blue")

plt.show()

tanh

[tanh(z) = frac{e^{z} - e^{-z}}{e^{z} + e^{-z}} tag{3}]

用matplotlib画出它的图像1

2

3

4

5

6

7

8

9

10

11

12

13import numpy as np

import matplotlib.pyplot as plt

def tanh(x):

return (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))

x = np.arange(-10, 10, 0.2)

y = tanh(x)

plt.plot(x, y, label="tanh", color="blue")

plt.show()

relu

[relu(z) = max(0, z) = relu(z) = begin{cases}

0 & text{ if } x leqslant 0 \

z & text{ if } x > 0

end{cases} tag{4}]

用matplotlib画出它的图像1

2

3

4

5

6

7

8

9

10

11

12

13import numpy as np

import matplotlib.pyplot as plt

def relu(x):

return np.maximum(0, x)

x = np.arange(-10, 10, 0.2)

y = relu(x)

plt.plot(x, y, label="relu", color="blue")

plt.show()

常见的优化器

SGD、Adam等,推荐阅读本人的另一篇文章 常用的梯度下降优化算法

常见的损失函数

MSE

[L(x_{i}, y_{i}) = (x_{i} - y_{i})^{2} tag{5}]

NLL 负对数似然

[L(x, label) = -x_{label} tag{6}]

BCE

BinCrossEntropy 是二分类用的交叉熵

[L(x_{i}, y_{i}) = -w_{i}[y_{i} logx_{i} + (1-y_{i})log(1-x_{i})] tag{7}]

CrossEntropy 交叉熵

[begin{align*}

L(x, label) & = -w_{label} logfrac{e^{x_label}}{sum_{j=1}^{N} e^{x_{j}}} \\

& = w_{label} [-x_{label} + logsum_{j=1}^{N} e^{x_{j}}]

end{align*} tag{8}]

目录结构nn:核心的网络包NN: 基础网络类

Linear:全连接层

Variable:基础参数类

ReLU / Sigmoid / Tanh:激活函数

optim:优化器SGD

Adam

loss:损失函数MSE

CrossEntropy

init:初始化器Normal:高斯分布

TruncatedNormal:截断高斯分布

Uniform:均匀分布

fn.py:激活函数

pipe.py:pipeline

实现细节

NN

NN 是最基础的网络基类,所有定义的网络都要继承该类1

2

3

4

5

6

7

8

9

10

11class NN(object):

def __init__(self):

pass

def forward(self, *args):

pass

def backward(self, grad):

pass

def params(self):

pass

def __call__(self, *args):

return self.forward(*args)

Variable

用于保存可导变量,求导时会用到此类封装的参数1

2

3

4

5

6class Variable(object):

def __init__(self, wt, dw, b, db):

self.wt = wt

self.dw = dw

self.b = b

self.db = db

Linear

定义全连接层, 全连接层可以实现网络空间大小的放缩,全连接层是实现深网的一种方式(但不推荐,深网的构建可以使用残差网络或者高速网络来构建)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36class Linear(NN):

def __init__(self,

dim_in,

dim_out,

init=None,

pretrained=None,

zero_bias=False):

super(Linear, self).__init__()

if isinstance(pretrained, tuple):

self.wt, self.b = pretrained

else:

if not isinstance(init, Init):

init = ini.Random([dim_in, dim_out])

self.wt = init()

if zero_bias:

self.b = ini.Zero([dim_out])()

else:

self.b = ini.Random([dim_out])()

self.input = None

self.output = None

self.dw = ini.Zero(self.wt.shape)()

self.db = ini.Zero([dim_out])()

self.variable = Variable(self.wt, self.dw, self.b, self.db)

def params(self):

return self.variable

def forward(self, *args):

self.input = args[0]

self.output = np.dot(self.input, self.wt) + self.b

return self.output

def backward(self, grad):

self.db = grad

self.dw += np.dot(self.input.T, grad)

grad = np.dot(grad, self.wt.T)

return grad

Sigmoid的实现

Sigmoid的前向推导很容易实现,也就是将输入放入sigmoid函数即可,难点在Sigmoid的求导上,以下是sigmoid的求导过程

[begin{align*}

f{'}(z) & = (frac{1}{1+e^{-z}}){'} \\

& = frac{e^{-z}}{(1+e^{-z})^{2}} \\

& = frac{1+e^{-z}-1}{(1+e^{-z})^{2}} \\

& = frac{1}{1+e^{-z}}(1-frac{1}{1+e^{-z}}) \\

& = f(z)(1-f(z))

end{align*} tag{9}]

知道了前向推导和反向推导的结果就可以用代码实现了1

2

3

4

5

6

7

8

9

10

11

12

13

14class Sigmoid(NN):

def __init__(self):

super(Sigmoid, self).__init__()

self.input = None

self.output = None

def forward(self, *args):

self.input = args[0]

self.output = 1.0 / (1.0 + np.exp(-self.input))

return self.output

def backward(self, grad):

grad *= self.output*(1.0-self.output)

return grad

tanh的实现

tanh的实现和sigmoid的类似,只要计算出tanh的导函数就可以很容易实现反向传播部分,tanh的求导结果是

[f(z){'} = 1-(f(z))^{2} tag{10}]1

2

3

4

5

6

7

8

9

10

11

12

13

14

15class Tanh(NN):

def __init__(self):

super(Tanh, self).__init__()

self.input = None

self.output = None

def forward(self, *args):

self.input = args[0]

self.output = ((np.exp(self.input) - np.exp(-self.input)) /

np.exp(self.input) + np.exp(-self.input))

return self.output

def backward(self, grad):

grad *= 1.0 - np.power(self.output, 2)

return grad

同理其他模块的实现也类似,主要包括前向传播和反向传播两部分

实例

以下构造了一个简单的BP网络1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18class BPNet(nn.NN):

def __init__(self,D_in, D_hidden, D_out):

super(Mnistnet,self).__init__()

self.layers = Pipe(

nn.Linear(D_in, D_hidden),

nn.ReLU(),

nn.Linear(D_hidden, D_out)

)

self.criterion = loss.MSE()

def forward(self,*args):

x = args[0]

return self.layers.forward(x)

def backward(self,grad=None):

grad=self.criterion.backward(grad)

self.layers.backward(grad)

可视化训练

使用simnet实现了一个简单的BP网络,数据集是 mnist,做了可视化训练demo , 效果如下图

refrence

np实现sigmoid_使用numpy实现一个深度学习框架相关推荐

  1. 从头搭建一个深度学习框架

    从头搭建一个深度学习框架 转自:Build a Deep Learning Framework From Scratch 代码:https://github.com/borgwang/tinynn 当 ...

  2. 手把手实现一个深度学习框架(附代码实现)

    编辑丨极市平台 转载 | 深度学习初学者 来源丨https://zhuanlan.zhihu.com/p/78713744 当前深度学习框架越来越成熟,对于使用者而言封装程度越来越高,好处就是现在可以 ...

  3. 手把手教你如何自己设计实现一个深度学习框架(附代码实现)

    作者丨王桂波@知乎(已授权) 来源丨https://zhuanlan.zhihu.com/p/78713744 编辑丨极市平台 导读 本文首先从深度学习的流程开始分析,对神经网络中的关键组件抽象,确定 ...

  4. TorchFusion 是一个深度学习框架,主要用于 AI 系统加速研究和开发

    TorchFusion 是一个深度学习框架,主要用于 AI 系统加速研究和开发. TorchFusion 基于 PyTorch 并且完全兼容纯 PyTorch 和其他 PyTorch 软件包,它供了一 ...

  5. 如何欣赏一个深度学习框架?

    点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 作者:袁进辉 https://zhuanlan.zhihu.com/ ...

  6. 如何评判一个深度学习框架?

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 目前,国内有多个深度学习框架开源,OneFlow也在为开源做最后的 ...

  7. 百炼成钢!自己动手写一个深度学习框架!

    2020年的AI算法岗竞争究竟多惨烈?这两年AI大火,还被顺势纳入了新基建的队伍,算法岗的平均薪资水平远超传统开发岗一大截,高薪+前景好,自然吸引越来越多技术人员转去AI工程师方向. 再加上跨专业和高 ...

  8. 3天,我用Python手撕了一个深度学习框架!

    人工智能如何学习?要看哪些书? 经常听到有粉丝问到这类的问题,其实,要想学习人工智能,你需要先搞懂什么是人工智能. 01  人工智能概念的提出 人工智能(Artificial Intelligence ...

  9. 大佬评清华Jittor,这是怎样一个深度学习框架?

    点击上方"机器学习与生成对抗网络",关注"星标" 获取有趣.好玩的前沿干货! 如何评价清华大学发布的自研深度学习框架-计图(Jittor)? 2020年3月20 ...

最新文章

  1. template模板中插入自定义参数
  2. wdk1703+vs2015编译的诡异问题
  3. 【HDU - 5094】 Maze (状态压缩+bfs)
  4. 下载丨DataGuard环境搭建详细步骤
  5. 路飞的11大团队建设之道
  6. 先搭云安全框架 再谈云落地
  7. 打造微信“智慧城市” 乌海率先开通城市公共微信服务
  8. 安全提示:IIS不要开启“WebDAV”扩展
  9. Ueditor 使用
  10. 林子雨 慕课答案2021新版
  11. DHCP实现跨网段自动分配IP地址
  12. 带色彩恢复的多尺度视网膜增强算法(MSRCR)的原理、实现及应用。
  13. 非肿瘤体细胞突变可能是临床基因检测新赛道
  14. pscs6安装序列号
  15. 求三个数的最小公倍数的解法之美
  16. 00012__photoScissor__替换照片背景
  17. Lua Busted 单元测试简介(Windows 环境)
  18. 计算机实验楼应用需求分析,校园网络信息化需求分析报告
  19. 简单的描述电荷泵的工作原理
  20. INTEL RealSense-D415 在 Ubuntu 16.04 开发流程 1

热门文章

  1. MVC,MVP 和 MVVM 的图示
  2. android-----带你一步一步优化ListView(一)
  3. UIButton下面添加滑动的线
  4. Nginx/LVS/HAProxy 负载均衡软件的优缺点详解
  5. c#导出包含图片的word文档
  6. 在MATLAB中添加语音处理工具箱(voicebox)
  7. 基于Python的BPSK音频的波形和频谱
  8. 基于Python+Django实现药品管理系统
  9. 微服务限流Sentinel讲解(一)
  10. TCP握手--(HTTP权威指南学习笔记)