BP神经网络原理以及demo示例

这几天突然对神经网络有兴趣了,就花了两三天的时间学习了一下BP神经网络。开门见山,先把github上的代码demo放上去,先了解一下他们是如何构建一个BP神经网络的。

然后就是一些我对BP神经网络的算法的一些总结。

#-*- coding:utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from sklearn.datasets import make_moons
from sklearn import linear_model
import sklearn

np.random.seed(0)
X,y=sklearn.datasets.make_moons(200,noise=0.20)
plt.scatter(X[:,0],X[:,1],s=40,c=y,cmap=plt.cm.Spectral)

#定义决策边界函数
def plot_decision_boundary(pred_func):
    # Set min and max values and give it some padding
    x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
    y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
    h = 0.01
    # Generate a grid of points with distance h between them
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
    # Predict the function value for the whole gid
    Z = pred_func(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    # Plot the contour and training examples
    plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
    plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Spectral)

#训练逻辑回归分类器
clf=sklearn.linear_model.LogisticRegressionCV()
clf.fit(X,y)
plot_decision_boundary(lambda x:clf.predict(x))
plt.title('Logistic Regression')
# plt.show()
#
num_examples = len(X) # 训练集大小
nn_input_dim = 2 # 输入层节点数
nn_output_dim = 2 # 输出层节点数

# 梯度下降参数
epsilon = 0.01 # 学习率
reg_lambda = 0.01 # 规范化强度

#定义损失函数
def calculate_loss(model):
    W1, b1, W2, b2 = model['W1'], model['b1'], model['W2'], model['b2']
    # 用于计算预测值的前向传播
    z1 = X.dot(W1) + b1
    a1 = np.tanh(z1)
    z2 = a1.dot(W2) + b2
    exp_scores = np.exp(z2)
    probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
    # 计算损失
    corect_logprobs = -np.log(probs[range(num_examples), y])
    data_loss = np.sum(corect_logprobs)
    #添加正则化的损失,可选可不选,为了陷入过拟合
    data_loss += reg_lambda/2 * (np.sum(np.square(W1)) + np.sum(np.square(W2)))
    return 1./num_examples * data_loss

#我们还要实现一个用于计算输出的辅助函数。它会通过定义好的前向传播方法来返回拥有最大概率的类别
def predict(model, x):
    W1, b1, W2, b2 = model['W1'], model['b1'], model['W2'], model['b2']
    # 正向传播
    z1 = x.dot(W1) + b1
    a1 = np.tanh(z1)
    z2 = a1.dot(W2) + b2
    exp_scores = np.exp(z2)
    probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
    return np.argmax(probs, axis=1)

#构建模型
def build_model(nn_hdim, num_passes=20000, print_loss=False):

    #将参数初始化为随机值。我们需要学习这些。
    np.random.seed(0)
    W1 = np.random.randn(nn_input_dim, nn_hdim) / np.sqrt(nn_input_dim)
    b1 = np.zeros((1, nn_hdim))
    W2 = np.random.randn(nn_hdim, nn_output_dim) / np.sqrt(nn_hdim)
    b2 = np.zeros((1, nn_output_dim))

    # 这是用于最终反馈结果的变量
    model = {}

    # 批量梯度下降.
    for i in xrange(0, num_passes):

        # 前向传播
        z1 = X.dot(W1) + b1
        a1 = np.tanh(z1)
        z2 = a1.dot(W2) + b2
        exp_scores = np.exp(z2)
        probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)

        # 反向传播
        delta3 = probs
        delta3[range(num_examples), y] -= 1
        dW2 = (a1.T).dot(delta3)
        db2 = np.sum(delta3, axis=0, keepdims=True)
        delta2 = delta3.dot(W2.T) * (1 - np.power(a1, 2))
        dW1 = np.dot(X.T, delta2)
        db1 = np.sum(delta2, axis=0)

        # A添加规范项 (b1 和b2 没有规范项)
        dW2 += reg_lambda * W2
        dW1 += reg_lambda * W1

        # 梯度下降参数更新
        W1 += -epsilon * dW1
        b1 += -epsilon * db1
        W2 += -epsilon * dW2
        b2 += -epsilon * db2

        # 将参数赋到model中
        model = { 'W1': W1, 'b1': b1, 'W2': W2, 'b2': b2}

        # 选择性打印损失
        # 这项操作代价较大,因为它要用到整个数据集,所以我们会降低使用频率。
        if print_loss and i % 1000 == 0:
          print "Loss after iteration %i: %f" %(i, calculate_loss(model))

    return model

# 创建一个含有三层隐含层的模型
model = build_model(3, print_loss=True)

# 绘制决策边界
plot_decision_boundary(lambda x: predict(model, x))
plt.title("Decision Boundary for hidden layer size 3")
plt.show()


算法部分:

其中xj(j=1,2……n)为神经元i的输入信号,wij为连接权,ui是由输入信号线性组合后的输出,是神经元i的净输入。θi为神经元的阀值,vi为经偏差调整过的值,称为神经元的局部感应区。f(.)是激励函数,yi是神经元i的输出

我个人认为,BP神经网络的算法核心是让全局网络误差达到最小,当误差为0的时候也就是模型最准确的时候,当然误差很可能不是0,为了逼近最小误差,我们要不断的去调节参数w,这个w的调节过程,就是不断迭代权值修去过过程。而这个权值修正,要用到梯度下降的方法,也是BP神经网络的一个核心思想,虽然梯度下降法可以有效的快速收敛,但当函数越来越复杂以后,会特别容易收敛到非最小值点,这就需要有一个更加好的初值和更加合适的学习率。所以说梯度下降的方法并不是完美的,它很有可能会导致寻求的误差最小值是局部最小值而非全局最小值,不过现在已经有了不少的改进方法,如随机梯度下降,批量梯度下降等等。最终在训练完模型后,这个模型就具有类似的预测能力。


这里的w都是权值,x是输入数据,b是阈值,f(x)代表的就是激活函数。如代码部分的demo中,也是按照这个算法来构建误差函数的。


给定n个样本,误差就是训练中给出的分类和学习后分类函数输出的分类的差值,然后平方再加和。这个过程与求方差差不多,反正最后的原则很清楚,方差尽可能小,最好是0。开始的时候会在隐含层和输出层设置两套w,这个w的设定是随机的,因为第一次设置的w极有可能不会是整个网络误差最小,所以超过误差范围就要调整。而图中的函数本身是没有1/2的,这里特意配一个1/2是因为:1,不会影响函数的单调性,2,在求导的时候能够去掉,式子会看上去比较整洁。

图中的d是期望输出,y是实际输出。


整个机制就是如上图这样的。


反向传播。然后对这个误差函数进行求导求偏微分。上图是输出层的误差偏微分。


上图是隐含层偏微分,方法和输出层的推导完全一样。


最后就是权值的修正过程:



总结:我们会先设置两套w作为两层网络各自的“超平面”的系数,然后输入一次完整的训练过程,就会有一个误差值出现,因为在给出的w很可能不合适。接着就是一次一次的进行w的调整。调整的方法是,首先找到一个误差和自变量的关系,然后求误差极值。误差存在的点就是误差最小的点,这和回归分析的最小二乘法的思想几乎一样。只是在最后的w迭代的两个公式中,用的就是试探的方法。思想就是往误差小的一边走一小步,如果还不够小就在走一步,这就是一次一次的迭代过程。直到最后找到一个误差满足要求的点,把这一点的w都记录下来,或者达到设定的训练次数,网络就训练完毕了。上图的η(学习率)就是这个每次走的“一小步”。


github中代码demo:https://github.com/NSAryan12/nn-from-scratch/blob/master/nn-from-scratch.ipynb

参考书籍:白话大数据与机器学习---高扬,卫峥,尹会生著。


  • 5
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值