跟着这个教程一步步理解反向传播算法

欢迎关注天善智能,我们是专注于商业智能BI,人工智能AI,大数据分析与挖掘领域的垂直社区,学习,问答、求职一站式搞定!

对商业智能BI、大数据分析挖掘、机器学习,python,R等数据领域感兴趣的同学加微信:tstoutiao,邀请你进入数据爱好者交流群,数据爱好者们都在这儿。

3901436-ecd1b52360a0d22c

作者:张小鸡  人工智能爱好者社区专栏作者

知乎ID:https://www.zhihu.com/people/mr.ji

个人公众号:鸡仔说  

每一个认真生活的人,都应该认真学一下机器学习。骄傲者从中获得谦卑,浮躁者从中获得平静,就犹如体验过波涛风浪或生死洗礼一样。从此,便真真地知道了:自己是个弱鸡。

哔哔完了,进入正题,在此之前,希望你已经对基础的神经网络有一个了解,而反向传播算法,其实是一个寻求最优解的过程。包括我在内的很多人,一开始都认为其中的原理很难,但其实不是,反向传播算法之所以被广泛应用,除了有效性外,私以为还得益于它的容易理解。看过《土拨鼠之日》的人,一定希望拥有和男主一样的奇特经历。因为它的奇妙之处,是可以一次次地返回去实验,如果失败了,则得到反馈,再优化。相应的,反向传播算法也是如此,一次次的返回去重来,得到最优解。

下面咱们从从最简单三层神经网络开始,即输入层,隐含层和输出层。输入层包含两个神经元i1, i2,隐含层包含两个神经元h1, h2,输出层同样是两个神经元o1, o2,输入层和隐含层的偏置项分别为b1, b2,激活函数默认为sigmod函数。

3901436-899b98a4148003aa

现在我们对它们附上初始值,如下图所示:

3901436-d90dabf1032e240a

其中:

输入数据 i1=0.05,i2=0.10;

输出数据 o1=0.01,o2=0.99;

初始权重 w1=0.15,w2=0.20,w3=0.25,w4=0.30;

     w5=0.40,w6=0.45,w7=0.50,w8=0.55

还记得我们的最终目标吧?给出初始值i1,i2,求出使得离目标输出最接近的系数值,即(wi, bi)

一步步的推导过程我再次不赘述,可以参考下原文,传送门在文末参考

我说一下具体的代码实现部分的一些细节。Matt Mazur大佬的代码清晰易读,而且分类特别赞,我们回顾一下上面的结构,发现整个神经网络系统就分为两个部分:神经元和连接神经元的线(即权重和偏置项),分工也很清晰明了。神经元负责的有:

向前传播:加权和,激活函数,输出函数,误差

反向传播:误差偏导,输出函数到激活函数的偏导,激活层到加权和的偏导

它们之间的连线,也就是网络层,负责对神经元的操控,它只需要负责向前传播和得到输出的结果。有了如上的结构,便可以来搭建整个网络了,黑喂狗~~

首先编写神经元:

1classNeuron():

2

3def__init__(self, bias):

4self.bias = bias

5self.weights = []

6

7defcalculate_output(self, inputs):

8self.inputs = inputs

9self.out_put =self.activate(self.calculate_total_net_input())

10returnself.out_put

11

12defcalculate_total_net_input(self):

13total =0

14foriinrange(len(self.inputs)):

15total +=self.weights[i] *self.inputs[i]

16returntotal +self.bias

17

18defactivate(self, total_net_input):

19return1/(1+math.exp(-total_net_input))

20

21defcalculate_error(self, target_output):

22return0.5* (target_output -self.out_put) **2

23

24# ∂E/∂yⱼ

25defcalculate_pd_error_wrt_output(self, target_output):

26return- (target_output -self.out_put)

27

28# dyⱼ/dzⱼ = yⱼ * (1 - yⱼ)

29defcalculate_pd_active_wrt_total_net_input(self):

30returnself.out_put * (1-self.out_put)

31

32# ∂zⱼ/∂wᵢ = wᵢ

33defcalculate_pd_total_net_input_wrt_weight(self, index):

34returnself.inputs[index]

35

36# δ = ∂E/∂zⱼ = ∂E/∂yⱼ * dyⱼ/dzⱼ

37defcalculate_pd_error_wrt_total_net_input(self, target_output):

38returnself.calculate_pd_error_wrt_output(target_output) *self.calculate_pd_active_wrt_total_net_input()

接下来我们编写网络层部分的代码:

1classNeuronLayer():

2

3def__init__(self, num_neurons, bias):

4self.bias = bias

5self.neurons = []

6foriinrange(num_neurons):

7self.neurons.append(Neuron(bias))

8

9deffeed_forward(self, inputs):

10outputs = []

11forneuroninself.neurons:

12outputs.append(neuron.calculate_output(inputs))

13returnoutputs

14

15defget_outs(self):

16outputs = []

17forneuroninself.neurons:

18outputs.append(neuron.out_put)

19returnoutputs

最后,我们由它们来组合我们的整个网络结构:

1classNeuralNetwork():

2LEARNING_RATE =0.5

3

4def__init__(self, num_inputs, num_hiddens, num_outputs, hidden_layer_weights=None, hidden_layer_bias=None, output_layer_weights=None, output_layer_bias=None):

5self.num_inputs = num_inputs

6

7self.hidden_layer = NeuronLayer(num_hiddens, hidden_layer_bias)

8self.output_layer = NeuronLayer(num_outputs, output_layer_bias)

9

10self.init_weights_from_inputs_to_hidden_layer_neurons(hidden_layer_weights)

11self.init_weights_from_hidden_layer_neurons_to_output_layer_neurons(output_layer_weights)

12

13definit_weights_from_inputs_to_hidden_layer_neurons(self, hidden_layer_weights):

14weight_num =0

15forhinrange(len(self.output_layer.neurons)):

16foriinrange(self.num_inputs):

17ifnothidden_layer_weights:

18self.hidden_layer.neurons[h].weights.append(random.random())

19else:

20self.hidden_layer.neurons[h].weights.append(hidden_layer_weights[weight_num])

21weight_num +=1

22

23definit_weights_from_hidden_layer_neurons_to_output_layer_neurons(self, output_layer_weights):

24weight_num =0

25foroinrange(len(self.output_layer.neurons)):

26forhinrange(len(self.hidden_layer.neurons)):

27ifnotoutput_layer_weights:

28self.output_layer.neurons[o].weights.append(random.random())

29else:

30self.output_layer.neurons[o].weights.append(output_layer_weights[weight_num])

31weight_num +=1

32

33deffeed_forward(self, inputs):

34hidden_layer_outputs =self.hidden_layer.feed_forward(inputs)

35returnself.output_layer.feed_forward(hidden_layer_outputs)

36

37deftrain(self, train_inputs, train_outputs):

38self.feed_forward(train_inputs)

39

40pd_errors_wrt_output_neuron_total_net_input = [0]*len(self.output_layer.neurons)

41foroinrange(len(self.output_layer.neurons)):

42pd_errors_wrt_output_neuron_total_net_input[o] =self.output_layer.neurons[o].calculate_pd_error_wrt_total_net_input(train_outputs[o])

43

44pd_errors_wrt_hidden_neuron_total_net_input = [0] * len(self.hidden_layer.neurons)

45forhinrange(len(self.hidden_layer.neurons)):

46d_error_wrt_hidden_neuron_output =0

47foroinrange(len(self.output_layer.neurons)):

48d_error_wrt_hidden_neuron_output += pd_errors_wrt_hidden_neuron_total_net_input[o] *self.output_layer.neurons[o].weights[h]

49

50pd_errors_wrt_hidden_neuron_total_net_input[h] += d_error_wrt_hidden_neuron_output *self.hidden_layer.neurons[h].calculate_pd_active_wrt_total_net_input()

51

52foroinrange(len(self.output_layer.neurons)):

53forw_hoinrange(len(self.output_layer.neurons[o].weights)):

54

55pd_error_wrt_weight = pd_errors_wrt_output_neuron_total_net_input[o] *self.output_layer.neurons[o].calculate_pd_total_net_input_wrt_weight(w_ho)

56

57self.output_layer.neurons[o].weights[w_ho] -=self.LEARNING_RATE * pd_error_wrt_weight

58

59forhinrange(len(self.hidden_layer.neurons)):

60forw_ihinrange(len(self.hidden_layer.neurons[h].weights)):

61# ∂Eⱼ/∂wᵢ = ∂E/∂zⱼ * ∂zⱼ/∂wᵢ

62pd_error_wrt_weight = pd_errors_wrt_hidden_neuron_total_net_input[h] *self.hidden_layer.neurons[

63h].calculate_pd_total_net_input_wrt_weight(w_ih)

64

65# Δw = α * ∂Eⱼ/∂wᵢ

66self.hidden_layer.neurons[h].weights[w_ih] -=self.LEARNING_RATE * pd_error_wrt_weight

以上便是通过简单的网络结构,理解反向传播算法的相关细节。从我学习和理解的过程来看,其实真正花耐心去理解,是不难的,往往真正击败我们的,真正击败我们的,往往是浮躁。道长且阻,一起加油~

GitHub地址:

https://github.com/hacksman/simple_neural_network

参考:

A Step by Step Backpropagation Example(原文):

https://mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/

3901436-504e64bf24702016

推荐阅读:

机器学习算法的随机数据生成

如果知乎被腾讯收购,会擦出什么火花?

2018年终精心整理|人工智能爱好者社区历史文章合集(作者篇)

2018年终精心整理 | 人工智能爱好者社区历史文章合集(类型篇)

公众号后台回复关键词学习

回复 免费 获取免费课程

回复 直播                获取系列直播课

回复 Python           1小时破冰入门Python

回复 人工智能         从零入门人工智能

回复 深度学习 手把手教你用Python深度学习

回复 机器学习 小白学数据挖掘与机器学习

回复 贝叶斯算法      贝叶斯与新闻分类实战

回复 数据分析师      数据分析师八大能力培养

回复 自然语言处理  自然语言处理之AI深度学习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值