机器学习之深刻理解神经网络理论基础、BP算法及其Python实现

  人工神经网络(Artificial Neural Networks,ANN)系统是 20 世纪 40 年代后出现的。它是由众多的神经元可调的链接权值链接而成,具备大规模并行处理、分布式信 息存储、良好的自组织自学习能力等特色。BP(Back Propagation)算法又称为偏差反向传播算法,是人工神经网络中的一种监督式的学习算法。BP 神经网络算法在理 论上能够逼近任意函数,基本的结构由非线性变化单元组成,具备很强的非线性映射能力。并且网络的中间层数、各层的处理单元数及网络的学习系数等参数可根据具体状况设定,灵活性很大,在优化、信号处理与模式识别、智能控制、故障诊断等许 多领域都有着普遍的应用前景。html


神经元模型python

神经网络中最基本的成分是神经元模型。在这个模型中,神经元接收到来自n个其余神经元传递过来的输入信号,这些输入信号经过带权重的链接进行传递,神经元接收到的总数入值将与神经元的阈值进行比较,而后经过激活函数处理以产生神经元的输出。
这里写图片描述
理想中的激活函数是下图中(a)所表示的阶跃函数,它将输入值映射为输出值0或者1,然而,阶跃函数具备不连续性、不光滑等不太好的性质,所以实际经常使用Sigrnoid函数做为激活函数,典型的Sigrnoid函数是下图中(b)所示,它把可能在较大范围内变化的输入值挤压到(0,1)输出值范围内。
这里写图片描述
git


多层前向神经网络github

常见的神经网络层级结构是多层前向神经网络web

多层前向神经网络由三部分组成:输出层、隐藏层、输出层,每层由单元组成;算法

输入层由训练集的实例特征向量传入,通过链接结点的权重传入下一层,前一层的输出是下一层的输入;隐藏层的个数是任意的,输入层只有一层,输出层也只有一层;网络

除去输入层以外,隐藏层和输出层的层数和为n,则该神经网络称为n层神经网络,以下图为2层的神经网络;
这里写图片描述
app

一层中加权求和,根据非线性方程进行转化输出;理论上,若是有足够多的隐藏层和足够大的训练集,能够模拟出任何方程;dom

使用神经网络以前,必需要肯定神经网络的层数,以及每层单元的个数;机器学习

为了加速学习过程,特征向量在传入输入层前,一般须要标准化到0和1之间;

离散型变量能够被编码成每个输入单元对应一个特征值可能赋的值,好比:特征值A可能去三个值(a0,a1,a2),那么可使用3个输入单元来表明A

若是A= a 0 a_0 ,则表明 a 0 a_0 的单元值取1,其他取0;
若是A= a 1 a_1 ,则表明 a 1 a_1 的单元值取1,其他取0;
若是A= a 2 a_2 ,则表明 a 2 a_2 的单元值取1,其他取0;
这里写图片描述

神经网络既解决分类(classification)问题,也能够解决回归(regression)问题。对于分类问题,若是是两类,则能够用一个输出单元(0和1)分别表示两类;若是多余两类,则每个类别用一个输出单元表示,因此输出层的单元数量一般等一类别的数量。

没有明确的规则来设计最佳个数的隐藏层,通常根据实验测试偏差和准确率来改进实验。


偏差逆传播算法(BP算法)

经过迭代来处理训练集中的实例;

对比通过神经网络后预测值与真实值之间的差;

反方向(从输出层=>隐藏层=>输入层)来最小化偏差,来更新每一个链接的权重;

算法详细介绍:

输入:数据集、学习率、一个多层神经网络构架;

输出:一个训练好的神经网络;

初始化权重和偏向:随机初始化在-1到1之间(或者其余),每一个单元有一个偏向;对于每个训练实例X,执行如下步骤:

一、由输入层向前传送:

结合神经网络示意图进行分析:
这里写图片描述

由输入层到隐藏层:
O j = i w i j x i + θ j O_j=\sum\limits_{i}^{}w_{ij}x_i+\theta_j
由隐藏层到输出层:
O k = j w j k O j + θ k O_k=\sum\limits_{j}^{}w_{jk}O_j+\theta_k
两个公式进行总结,能够获得:
I j = i w i j O i + θ j I_j=\sum\limits_{i}^{}w_{ij}O_i+\theta_j
I j I_j 为当前层单元值, O i O_i 为上一层的单元值, w i j w_{ij} 为两层之间,链接两个单元值的权重值, θ j \theta_j 为每一层的偏向值。咱们要对每一层的输出进行非线性的转换,示意图以下:
这里写图片描述

当前层输出为 I j I_j ,f为非线性转化函数,又称为激活函数,定义以下:
f ( x ) = 1 1 + e x f(x)=\frac{1}{1+e^{-x}}
即每一层的输出为:
O j = 1 1 + e I j O_j=\frac{1}{1+e^{-I_j}}

这样就能够经过输入值正向获得每一层的输出值。
二、根据偏差反向传送 对于输出层:其中 T k T_k 是真实值, O k O_k 是预测值:
E r r k = O k ( 1 O k ) ( T k O k ) Err_k=O_k(1-O_k)(T_k-O_k)
对于隐藏层:
E r r j = O j ( 1 O j ) k E r r k w j k Err_j=O_j(1-O_j)\sum\limits_{k}^{}Err_kw_{jk}
权重更新:其中 l l 为学习率:
Δ w i j = ( l ) E r r j O i \Delta w_{ij}=(l)Err_jO_i
w i j = w i j + Δ w i j w_{ij}=w_{ij}+\Delta w_{ij}
偏向更新:
Δ θ j = ( l ) E r r j \Delta \theta_j=(l)Err_j
θ j = θ j + Δ θ j \theta_j=\theta_j+\Delta \theta_j

三、终止条件

① 偏重的更新低于某个阈值;
②预测的错误率低于某个阈值;
③达到预设必定的循环次数;

算法举例:
这里写图片描述
这里写图片描述


反向传播详细推导过程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
状况2:隐藏单元的权值 训练法则
在这里插入图片描述


BP神经网络的python实现

须要先导入numpy模块

import numpy as np

定义非线性转化函数,因为还须要用到给函数的导数形式,所以一块儿定义

def tanh(x):
    return np.tanh(x)
def tanh_deriv(x):
    return 1.0 - np.tanh(x)*np.tanh(x)
def logistic(x):
    return 1/(1 + np.exp(-x))
def logistic_derivative(x):
    return logistic(x)*(1-logistic(x))

设计BP神经网络的形式(几层,每层多少单元个数),用到了面向对象,主要是选择哪一种非线性函数,以及初始化权重。layers是一个list,里面包含每一层的单元个数。

class NeuralNetwork:
    def __init__(self, layers, activation='tanh'):
        """
        :param layers: A list containing the number of units in each layer.
        Should be at least two values
        :param activation: The activation function to be used. Can be
        "logistic" or "tanh"
        """
        if activation == 'logistic':
            self.activation = logistic
            self.activation_deriv = logistic_derivative
        elif activation == 'tanh':
            self.activation = tanh
            self.activation_deriv = tanh_deriv
 
        self.weights = []
        for i in range(1, len(layers) - 1):
            self.weights.append((2*np.random.random((layers[i - 1] + 1, layers[i] + 1))-1)*0.25)
            self.weights.append((2*np.random.random((layers[i] + 1, layers[i + 1]))-1)*0.25)

实现算法

def fit(self, X, y, learning_rate=0.2, epochs=10000):
        X = np.atleast_2d(X)
        temp = np.ones([X.shape[0], X.shape[1]+1])
        temp[:, 0:-1] = X
        X = temp
        y = np.array(y)
 
        for k in range(epochs):
            i = np.random.randint(X.shape[0])
            a = [X[i]]
 
            for l in range(len(self.weights)):
                a.append(self.activation(np.dot(a[l], self.weights[l])))
            error = y[i] - a[-1]
            deltas = [error * self.activation_deriv(a[-1])]
 
            for l in range(len(a) - 2, 0, -1):
                deltas.append(deltas[-1].dot(self.weights[l].T)*self.activation_deriv(a[l]))
            deltas.reverse()
 
            for i in range(len(self.weights)):
                layer = np.atleast_2d(a[i])
                delta = np.atleast_2d(deltas[i])
                self.weights[i] += learning_rate * layer.T.dot(delta)

实现预测

def predict(self, x):
        x = np.array(x)
        temp = np.ones(x.shape[0]+1)
        temp[0:-1] = x
        a = temp
        for l in range(0, len(self.weights)):
            a = self.activation(np.dot(a, self.weights[l]))
        return a

咱们给出一组数进行预测,咱们上面的程序文件保存名称为BP

from BP import NeuralNetwork
import numpy as np
 
nn = NeuralNetwork([2,2,1], 'tanh')
x = np.array([[0,0], [0,1], [1,0], [1,1]])
y = np.array([1,0,0,1])
nn.fit(x,y,0.1,10000)
for i in [[0,0], [0,1], [1,0], [1,1]]:
    print(i, nn.predict(i))

结果以下:

([0, 0], array([ 0.99738862]))
([0, 1], array([ 0.00091329]))
([1, 0], array([ 0.00086846]))
([1, 1], array([ 0.99751259]))

链式求导过程举例
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


参考:神经网络理论基础


相关博客:

一、机器学习系列之机器学习之决策树(Decision Tree)及其Python代码实现

二、机器学习系列之机器学习之Validation(验证,模型选择)

三、机器学习系列之机器学习之Logistic回归(逻辑蒂斯回归)

四、机器学习系列之机器学习之拉格朗日乘数法

五、机器学习系列之机器学习之深刻理解SVM

六、机器学习系列之机器学习之深刻理解K-means、与KNN算法区别及其代码实现


##具体更多资源可前往机器学习专题