Python 多层BP神经网络的实现及应用

神经网络

在深度学习中,其中一种网络架构是前向传播——反向传播,本文就讲解一下反向传播算法(Error Back Propagation),并在不调用深度学习库的情况下实现BP算法的三角函数拟合。

下面的图片是一个简单的多层神经网络(都是自己画的),可以概括为输入层、输出层、隐藏层,相邻层之间存在数学关系,这与我们给模型设置、训练的参数有关。
多层神经网络
这里用更简单的四层的神经网络来讲解,(输入层:1;隐藏层1:2;隐藏层2:2;输出层:1)。拟合三角函数理论上是可以用简单的网络来实现,也就是一个输入一个输出,中间的隐藏层只需一层也能拟合出接近真实值的结果。
输入层就是我们输入的x;输出层的y是网络计算出的结果,而不是目标结果;隐藏层是我们将套公式的过程抽象成多个结点间的数据传递。
其中每层的架构都是:传入值-计算-传出值
输入层-隐藏层-隐藏层-输出层

前向传播(Forward propagation)

层与层之间的通过前向传播公式传递的(当前层的output是下一层的input):
公式1:
在这里插入图片描述
公式2:
在这里插入图片描述
其中z是神经元(结点)的input,a是神经元的output,W是权重,b是偏置,f是激活函数
从第一层开始传递数据,套公式计算,套激活函数(最后一层不要用激活函数),最后一直传递到最后一层,得到该网络的结果。

反向传播(Error Back Propagation)

为了得到好的模型,要更新网络的参数W和b,才能拟合出接近结果的网络,这里就用到了反向传播算法。
这里将神经网络的损失函数记为L(W, b),W,b是指网络中所有的参数。
通过计算L(W, b)(神经网络的损失),用到梯度下降公式,从最后一层开始,逆向求出每一层W, b的梯度。然后再对W, b的值进行更新(更新W,b没有什么先后顺序)。
公式3:
在这里插入图片描述
公式4:
在这里插入图片描述
反向传播更新权重推导:
根据公式3、4可以设公式5为:
公式5:
在这里插入图片描述
再有公式1、2得公式6、7:
公式6:
在这里插入图片描述
公式7:
在这里插入图片描述
由公式(3)(4)(5)(6)(7)推导得:
公式8:
在这里插入图片描述
公式9:
在这里插入图片描述

直到将所有的W和b的梯度计算完,使用负梯度更新所有参数,这算完成了一轮训练。各层之间的计算是一样的,不过是利用到了高数的链式法则来求导,过程中会遇到矩阵相乘,它也只是用到了线性代数,写代码的话很容易掉到两个矩阵尺寸的问题导致无法计算的巨坑中,这时候画图思考就行。
在计算中使用到的激活函数,可以选择sigmoid函数,但是sigmoid的容易崩,对我们拟合三角函数模型的效果不明显,可以换成tanh或ReLu等更高效率的激活函数。


代码部分:
代码解决的问题:拟合y = sin(5/4πx) +8,区间(-5,5)
①创建数据集,产生x和y的值;
②设置网络层。
③创建模型,设置网络参数:导入网络层,设置W,b,设置激活函数和损失函数
④训练模型,导入训练集,设置学习率,模型在前向传播完成后开始BP反向传播更新参数,不断循环,使各层的权重向量和偏置项接近最优解(没有接近就是网络不行,继续改参数)。
⑤训练已经完成,导入数据,测试网络效果(这个代码不是预测,不能计算训练数据以外的)。

代码实现

我写的这份代码可以实现3层以上的神经网络,并且只需要修改每一层的神经元个数就可以自动完成神经网络的编辑。

我将用这个BP神经网络去拟合函数 f(x)=sin(5πx/4)+8(其中x∈(-5,5))

# python-Error Back Propagation
# coding=utf-8
import numpy
import numpy as np
import matplotlib.pyplot as plt


def loss_derivative(output_activations, y):
    return 2 * (output_activations - y)


def tanh(z):
    return np.tanh(z)


def tanh_derivative(z):
    return 1.0 - np.tanh(z) * np.tanh(z)


def mean_squared_error(predictY, realY):
    Y = numpy.array(realY)
    return np.sum((predictY - Y) ** 2) / realY.shape[0]


class BP:
    def __init__(self, sizes, activity, activity_derivative, loss_derivative):
        self.num_layers = len(sizes)
        self.sizes = sizes
        self.biases = [np.zeros((nueron, 1)) for nueron in sizes[1:]]
        self.weights = [np.random.randn(next_layer_nueron, nueron) for nueron, next_layer_nueron in
                        zip(sizes[:-1], sizes[1:])]
        self.activity = activity
        self.activity_derivative = activity_derivative
        self.loss_derivative = loss_derivative

    def predict(self, a):
        re = a.T
        n = len(self.biases) - 1
        for i in range(n):
            b, w = self.biases[i], self.weights[i]
            re = self.activity(np.dot(w, re) + b)
        re = np.dot(self.weights[n], re) + self.biases[n]
        return re.T

    def update_batch(self, batch, learning_rate):
        temp_b = [np.zeros(b.shape) for b in self.biases]
        temp_w = [np.zeros(w.shape) for w in self.weights]
        for x, y in batch:
            delta_temp_b, delta_temp_w = self.update_parameter(x, y)
            temp_w = [w + dw for w, dw in zip(temp_w, delta_temp_w)]
            temp_b = [b + db for b, db in zip(temp_b, delta_temp_b)]
        self.weights = [sw - (learning_rate / len(batch)) * w for sw, w in zip(self.weights, temp_w)]
        self.biases = [sb - (learning_rate / len(batch)) * b for sb, b in zip(self.biases, temp_b)]

    def update_parameter(self, x, y):
        temp_b = [np.zeros(b.shape) for b in self.biases]
        temp_w = [np.zeros(w.shape) for w in self.weights]
        activation = x
        activations = [x]
        zs = []
        n = len(self.biases)
        for i in range(n):
            b, w = self.biases[i], self.weights[i]
            z = np.dot(w, activation) + b
            zs.append(z)
            if i != n - 1:
                activation = self.activity(z)
            else:
                activation = z
            activations.append(activation)
        d = self.loss_derivative(activations[-1], y)
        temp_b[-1] = d
        temp_w[-1] = np.dot(d, activations[-2].T)
        for i in range(2, self.num_layers):
            z = zs[-i]
            d = np.dot(self.weights[-i + 1].T, d) * self.activity_derivative(z)
            temp_b[-i] = d
            temp_w[-i] = np.dot(d, activations[-i - 1].T)
        return (temp_b, temp_w)

    def fit(self, train_data, epochs, batch_size, learning_rate, validation_data=None):
        n = len(train_data)
        for j in range(epochs):
            np.random.shuffle(train_data)
            batches = [train_data[k:k + batch_size] for k in range(0, n, batch_size)]
            for batch in batches:
                self.update_batch(batch, learning_rate)
            if (validation_data != None):
                val_pre = self.predict(validation_data[0])
                print("Epoch", j + 1, '/', epochs, '  val loss:%12.12f' % mean_squared_error(val_pre, validation_data[1]))


def load_data(step):
    x = np.array([numpy.mgrid[-5: 5: 10 / step]]).T
    y = numpy.sin(5 * numpy.pi * x / 4) + 8
    return x, y


if __name__ == "__main__":
    numpy.random.seed(7)
    step = 500
    beta = 1e-3
    layer = [1, 32, 64, 128, 32, 1]
    x, y = load_data(step)
    data = [(np.array([x_value]), np.array([y_value])) for x_value, y_value in zip(x, y)]
    model = BP(layer, tanh, tanh_derivative, loss_derivative)
    model.fit(train_data=data, epochs=2000, batch_size=64, learning_rate=beta, validation_data=(x, y))
    predict = model.predict(x)
    plt.plot(x, y, "-r", linewidth=2, label='origin')
    plt.plot(x, predict, "-b", linewidth=1, label='predict')
    plt.legend()
    plt.grid(True)
    plt.show()

最终结果

最终结果是这样:
在这里插入图片描述
总的来说还是不错的,能够较好的完成函数的拟合,试了一下其他三角函数效果也不错。
待改进空间:这份代码我只实现了SGD,还有Momentum,AdaGrad,RMSProp,Adam还没实现,将来有空就给他补上吧

  • 6
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
BP神经网络是一种常见的神经网络模型,可以用于解决二分类问题,即将数据分为两类。在Python中,实现BP神经网络的方法有很多,常用的有Keras、TensorFlow等框架。 以Keras为例,可以先定义一个有多层神经网络模型,然后进行训练和测试。首先需要导入相关的库: ``` import numpy as np from keras.models import Sequential from keras.layers.core import Dense, Activation from keras.optimizers import SGD ``` 定义一个多层感知器模型: ``` model = Sequential() # 定义模型 model.add(Dense(10, input_dim=2)) # 添加第一层,输入维度为2,输出维度为10 model.add(Activation('relu')) # 添加ReLU激活函数 model.add(Dense(1)) # 添加输出层,输出维度为1 model.add(Activation('sigmoid')) # 添加Sigmoid激活函数 ``` 接下来需要设定模型的优化器、学习率、损失函数、训练数据等参数: ``` sgd = SGD(lr=0.1) # 设定优化器和学习率 model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy']) # 编译模型 X_train = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) # 训练数据 y_train = np.array([0, 1, 1, 0]) # 训练数据的标签 ``` 最后进行训练: ``` model.fit(X_train, y_train, epochs=1000) # 训练模型 ``` 训练时,模型会根据训练数据逐渐调整参数,使得预测结果与实际标签的误差最小化。训练完成后,可以通过测试数据进行测试: ``` X_test = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) # 测试数据 y_test = np.array([0, 1, 1, 0]) # 测试数据的标签 loss, acc = model.evaluate(X_test, y_test) # 测试模型 print('loss: ', loss) print('accuracy: ', acc) ``` 测试时,模型会根据测试数据对结果进行预测,并计算误差和准确率。通过上述方法,即可在Python中利用BP神经网络实现二分类问题的解决。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值