2019-10-08-神经网络算法BP算法即python实现

最近自己专研了一下神经网络中的BP算法,写下这篇文章一是为了记录下自己的想法以免以后忘了,二是重新理一下自己的思路。

长话短说,bp算法的基本原理就是:数据向前传播,到达输出层,通过误差方向传播更新权重。

一、向前传播

三层神经网络模型

首先,为这个模型定义一些数据符号,以便下面操作:输入层---i、隐藏层---j、输出层---k、权重W_{i,j} ---表示第i层到第j层连线的权值,比如:W_{1,1} 表示第i层第一个节点和第j层第一个节点的连线。

从输入层传播到隐藏层。


图2

图2中显示了一次传播过程,其中a、b、c代表输入层的三个节点,输出y为隐藏层一个节点的输出值,S阈值函数使用的是sigmoid (x)= \frac{1}{1+e^(-x) } (显示有些问题,为e的-x次方)。

所以:x = (第一个节点的输出*链接权重)+(第二个节点的输出*链接权重) +(第三个节点的输出*链接权重);

y = sigmoid (x)。

[注:这里省略了偏置bias,经过实验证明,是否添加偏置对预测结果影响不大]

所以隐藏层的三个节点的值为hidden_output = \sum_{i=0}^3 W·I,其中W、I都为矩阵,W为权重矩阵:每一行代表着三个输入层节点指向同一个节点的3个权重;I 是输入矩阵:由输出层三个节点组成的一个列矩阵。

从隐藏层传播到输出层

从隐藏层到输入层传播方式是一样的,final_output = sigmoid( \sum_{k=0}^2 W·hidden_output )。

二、反向传播。

相信有一定数学基础的人在向前传播这一步都没什么问题,BP算法的难点就在反向传播。

首先我们需要理解为什么可以反向传播更新权重W呢?在这之前我们需要理解误差error,error = targets-final_output,即误差=正确值-预测值,我们要做的就是让”error->0“。

\frac{∂error}{∂W} 这个表达式表示了当权重wj,k 改变时,误差E是如何改变的,正好符合我们的要求。

接下来我们对这个偏导数求导:


图三

换一种表达方式:


图四

其中\alpha 为学习率,E_k为下一层的误差,O_J为前一层的输出的转置,O_k即为当前层的输出。

之后我们就可以进行反向传播了。

基于bp算法预测手写字的python代码如下:

import numpyas np

import scipy.special

#神经网络框架

class neuralNetwork:

#1、初始化神经网络函数

#1.1、为神经网络设置一些参数:输入节点、隐藏节点、输出节点、学习率

    def __init__(self, inputnodes, hiddennodes, outputnodes, learning_rate):

self.inodes = inputnodes

self.hnodes = hiddennodes

self.onodes = outputnodes

self.lr = learning_rate

#1.2、初始化两层权值,self.wih、self.who ,初始化权重都位于(-0.5,0.5)

        self.wih = (np.random.rand(self.hnodes ,self.inodes)-0.5)

self.who = (np.random.rand(self.onodes ,self.hnodes)-0.5)

# 1.3激励函数,即sigmoid函数

        self.activation_function =lambda x: scipy.special.expit(x)

#2、训练神经网络函数

    def train(self,inputs_list , targets_list):

#2.1以下6行代码是和query()函数中的一样的,正向传播过程。

        inputs = np.array(inputs_list,ndmin=2).T

targets =  np.array(targets_list,ndmin=2).T

hidden_inputs = np.dot(self.wih, inputs)

hidden_outputs =self.activation_function(hidden_inputs)

final_inputs = np.dot(self.who, hidden_outputs)

final_outputs =self.activation_function(final_inputs)

#-------------------------------------------------

#2.2核心步骤---反向更新

#2.2.1、计算目标值和实际值的误差error = targets - actual

        output_errors = targets - final_outputs

#2.2.2、计算隐藏层的误差:隐藏层权值的转置 * 输出层的误差

        errors_hidden = np.dot(self.who.T , output_errors)

#2.2.3更新权重: W(j,k) = lr * E_k * sigmoid(O_k) * ( 1-sigmoid(O_k) ) · O_j.T

        self.who +=self.lr * np.dot( output_errors * final_outputs * (1-final_outputs ) , np.transpose(hidden_outputs) )

self.wih +=self.lr * np.dot( errors_hidden * hidden_outputs * (1-hidden_outputs ) , np.transpose(inputs) )

#3、预测神经网络函数

    def query(self ,inputs_list):

#将输入转化为2d数组

        inputs = np.array(inputs_list ,ndmin=2).T

# 3.1将信号传入隐藏层

# 激励函数的输入值:X_hidden =self.wih * I , 其中I为输入层的输入

        hidden_inputs = np.dot(self.wih, inputs)

# 将输入值传入激励函数

        hidden_outputs =self.activation_function(hidden_inputs)

# 3.2将信号从隐藏层传入输出层,隐藏层的输出*权值就是输出层的输入  即self.who * hidden_outputs = final_inputs

        final_inputs = np.dot(self.who, hidden_outputs)

final_outputs =self.activation_function(final_inputs)

return final_outputs

#三层节点设置为784、200、10,学习率为0.1

n = neuralNetwork(784,200,10,0.1)

train_data_file =open("D:/Handwritten numerals/mnist_train.csv")

train_data_list = train_data_file.readlines()

train_data_file.close()

#训练网络1000次

for iin range(60000):

#随机找一行

    j = np.random.randint(len(train_data_list))

#以逗号分开

    all_value = train_data_list[j].split(',')

#将输入数字转化为[0.01——1]

    inputs = (np.asfarray(all_value[1:])/255*0.99)+0.01

    #目标数字

    targets = np.zeros(10)+0.01

    targets[int(all_value[0])]=0.99

    n.train(inputs,targets)

#预测

test_data_file =open("D:/Handwritten numerals/mnist_test.csv")

test_data_list = test_data_file.readlines()

test_data_file.close()

#新建一个分数数组,用于存储预测正确的数

scored = []

for recordin test_data_list:

test_value = record.split(',')

inputs = (np.asfarray(test_value[1:]) /255 *0.99) +0.01

    outputs = n.query(inputs)

#np.argmax()函数:取出一位数组中最大值的索引

    label = np.argmax(outputs)

if label ==int(test_value[0]):

scored.append(1)

else:

scored.append(0)

#预测的准确率

scored_array =np.asfarray(scored)

print('准确率为:',scored_array.sum()/scored_array.size)

注:训练60000次大概可以达到95%的识别率,若是训练600000万次可以达到97%。

引用书籍:《Python神经网络编程》,[英]塔里克·拉希德著,林赐译。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容