python实现神经网络的正向传播(fp)函数_【神经网络DNN】算法原理 公式推导 python编程实现...

1.前言

如图是一个神经网络的简化结构,隐藏层每一个节点都是一个神经元,比如下图的a1,a2,a3。机器学习中的神经网络是模拟生物神经网络结构,每个神经元与其他神经元相连,当神经元的电位超过了一个‘阈值’,那么它就会被激活,即‘兴奋’起来。

机器学习的神经网络是怎么模拟大脑神经元‘兴奋’这个概念的?结合a1这个神经元做简要的分析:

首先对于a1的定义,我们给出如下的公式..

剖析神经元兴奋的定义“当神经元的电位超过了一个‘阈值’,那么它就会被激活”,对应与上面公式,怎么使得上诉公式达到神经元的效果?

达到某一阀值时候

,即兴奋状态,反之当未达到阀值时

,即未兴奋状态。

所以理想情况下

这个函数应该如下图的红色,因为起特性就是大于零被激活,小于零未激活,所以称之为激活函数。 :

但是红色函数存在不连续,不光滑等不太好的性质...所以在实际情况下,我们一般会使用sigmod函数来作为激活函数(即图中蓝线):

其实我们可以发现,对于神经网络来说,每一个神经元我们都可以理解成一个逻辑回归(LR)模型。这样去理解它或许对你之后的理解有所帮助。对于逻辑回归算法模型的推到及编程可以查看我之前的一篇文章:点击此处跳转

2.前向传播的神经网络运算

由图,输入层的输入矩阵(

)可以表示为:                 隐藏层的输入矩阵(

)可以表示为:

                                                                        

输入层的每个输入

对应每个隐藏层

的权重为

,所以权重的矩阵(

)可以表示为:

由神经元的兴奋启发可以将上式表示为:

由上式子可以整理得;

    (b为偏置单元,对应图1的,x0,a0,在本节介绍中省略)

将矩阵代入上式:

同理,我们对于接下来的隐藏层和输出层也用同样的方法,那么我们最终的输出层就是一个在0,1之间分布的值,当其大于0时,即输入的x属于1这个类别。当其小于0时,输入的x属于0这个类别。

3.梯度下降与代价函数

你可能会因为不清楚第二节的前向传播算法中的权重矩阵(

)是怎么来的,从而导致你对整个算法的过程有些不知所云。这一章节会为你解决这个疑惑。

需要明白的是,在设计一个神经网络算法模型的时候,有些参数是提前人为定义的。

#参数1:

隐藏层的层数

#参数2:

每层隐藏层的神经元个数

#参数3:

输出层的神经元个数

#参数4

定义每次训练的样本数

#参数5

定义训练的次数

#参数6

定义学习率

当上诉参数设定后,将在神经网络中起到怎样的作用呢?结合下图来说明一下:

1.在定义了隐藏层的层数,每层神经元的个数,输出层神经元个数后我们能确定上图中w,b,v,b_,u,b__的矩阵大小。在神经网络第一轮训练时候,上诉矩阵的参数即w11,w12...等的值是人为定义的一系列满足正态分布的随机值。实质上之后你会发现,无论起先w,b的矩阵值如何,通过代价函数的反复迭代都能让其收敛到最低点。

2.定义每次训练的样本数即确定了输入层输入x的个数。

3.人为定义不同的训练的次数,学习率,通过观察准确率的变化,来选择最适合神经网络的参数。

在前言部分为大家介绍到,一个神经网络的每个神经元可以看做一个逻辑回归算法模型。

逻辑回归的代价函数如下:

关于逻辑回归代价函数的推到,我简要说明一下:

1.在二分类问题中,对于每个观察样本:

这个公式很好理解,拆分开来可以这样表示:

2.对于n个出现的样本,样本间相互独立,则n个出现的概率为每一个出现的概率的乘积。

3.为了满足凸函数求最优解的思想,我们对L(w)取对数,并化简:

4.由sigmod函数可以推到出如下结果:

5.有次推导逻辑回归的代价函数:

对于神经网络来说,我们可以由上一章节的前向传播的算法得到最后的输出,之后我们算出这个输出与真实值的误差,然后用同样的方式反向传播回去迭代修正之前w,b,v,b_,u,b__矩阵的值。

而对于每个隐藏层来说,其每个神经元都可以作为一个逻辑回归单元,这样神经网络误差算法的代价函数就可以做出如下表示:

(k表示神经元的序号)

同理我们可以用逻辑回归算法模型的方式来对

做梯度下降算法,即找出满足:

时,的w和b的值。对

的求解,可以使用链式法则:

对于神经元的求和:

(这个公式可由前向传播算法矩阵运算中得出)

所以

假设:

那么:

所以由梯度下降算法可以求得:

           (

为人为设定的学习率。)

4.BP反向传播算法

通过第四节,我们对于神经网络更新参数w,b有了一定的认识,而在上节最后,原来的更新w,b的问题转为了求解

用一张动态图表示前向(FP)和后向(BP)传播的全过程:

对于输出层来说:

(用均方误差来定义样本的y值和通过算法模型求解出来的y值的距离差距)

其中

对于隐藏层来说:

替换调

,用

替换掉

这个式子说明了反向传播算法的本质,我们先求得输入层

,然后通过

不断后向推到

....

通过一轮一轮反复迭代修正w,b。使得最终的w,b是最能完成分类的参数。

5.编程实现

如果需要更为详细的编程实现过程,点下面链接:

使用Python实现神经网络

import numpy as np

import random

import os, struct

from array import array as pyarray

from numpy import append, array, int8, uint8, zeros

class NeuralNet(object):

# 初始化神经网络,sizes是神经网络的层数和每层神经元个数

def __init__(self, sizes):

self.sizes_ = sizes

self.num_layers_ = len(sizes) # 层数

self.w_ = [np.random.randn(y, x) for x, y in zip(sizes[:-1], sizes[1:])] # w_、b_初始化为正态分布随机数

self.b_ = [np.random.randn(y, 1) for y in sizes[1:]]

# Sigmoid函数,S型曲线,

def sigmoid(self, z):

return 1.0/(1.0+np.exp(-z))

# Sigmoid函数的导函数

def sigmoid_prime(self, z):

return self.sigmoid(z)*(1-self.sigmoid(z))

def feedforward(self, x):

for b, w in zip(self.b_, self.w_):

x = self.sigmoid(np.dot(w, x)+b)

return x

def backprop(self, x, y):

nabla_b = [np.zeros(b.shape) for b in self.b_]

nabla_w = [np.zeros(w.shape) for w in self.w_]

activation = x

activations = [x]

zs = []

for b, w in zip(self.b_, self.w_):

z = np.dot(w, activation)+b

zs.append(z)

activation = self.sigmoid(z)

activations.append(activation)

delta = self.cost_derivative(activations[-1], y) * \

self.sigmoid_prime(zs[-1])

nabla_b[-1] = delta

nabla_w[-1] = np.dot(delta, activations[-2].transpose())

for l in range(2, self.num_layers_):

z = zs[-l]

sp = self.sigmoid_prime(z)

delta = np.dot(self.w_[-l+1].transpose(), delta) * sp

nabla_b[-l] = delta

nabla_w[-l] = np.dot(delta, activations[-l-1].transpose())

return (nabla_b, nabla_w)

def update_mini_batch(self, mini_batch, eta):

nabla_b = [np.zeros(b.shape) for b in self.b_]

nabla_w = [np.zeros(w.shape) for w in self.w_]

for x, y in mini_batch:

delta_nabla_b, delta_nabla_w = self.backprop(x, y)

nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]

nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]

self.w_ = [w-(eta/len(mini_batch))*nw for w, nw in zip(self.w_, nabla_w)]

self.b_ = [b-(eta/len(mini_batch))*nb for b, nb in zip(self.b_, nabla_b)]

# training_data是训练数据(x, y);epochs是训练次数;mini_batch_size是每次训练样本数;eta是learning rate

def SGD(self, training_data, epochs, mini_batch_size, eta, test_data=None):

if test_data:

n_test = len(test_data)

n = len(training_data)

for j in range(epochs):

random.shuffle(training_data)

mini_batches = [training_data[k:k+mini_batch_size] for k in range(0, n, mini_batch_size)]

for mini_batch in mini_batches:

self.update_mini_batch(mini_batch, eta)

if test_data:

print("Epoch {0}: {1} / {2}".format(j, self.evaluate(test_data), n_test))

else:

print("Epoch {0} complete".format(j))

def evaluate(self, test_data):

test_results = [(np.argmax(self.feedforward(x)), y) for (x, y) in test_data]

return sum(int(x == y) for (x, y) in test_results)

def cost_derivative(self, output_activations, y):

return (output_activations-y)

# 预测

def predict(self, data):

value = self.feedforward(data)

return value.tolist().index(max(value))

# 保存训练模型

def save(self):

pass # 把_w和_b保存到文件(pickle)

def load(self):

pass

打赏一下作者:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值