神经网络NN算法实现[pyhton](吴恩达Machine Learning)

来源:互联网 发布:淘宝店铺页尾怎么设置 编辑:程序博客网 时间:2024/05/17 06:28

简介

因最近在学习机器学习和深度学习,最开始从吴恩达的《Machine Learning》开始学起,然后又学习了台湾大学李宏毅的《机器学习》视频课程,接着开始在网易云课堂学习吴恩达的《深度学习工程师》系列课。最开始学习神经网络感觉还可以,挺简单的,但是学到反向传播有点小懵逼,于是看了下网上的代码,自己实现了下。

神经网络算法概述

因前向传播很好理解,就不多说了。神经网络算法有三层结构,输入层、隐藏层、输出层。网上有很多图像表示。
这里写图片描述
不管什么算法,大致考虑三个部分,以神经网络算法为例。

  1. 预测函数,predict function,就是你设计的模型函数,如predict function(w, b) = w*x + b,w,b为矩阵,以上图为例:
    a1 = activation(w1*x + b1)
    a2 = activation(w2 * a1+ b2)
    predict function = a2
    activation为激活函数,一般为使目标非线性化,如sigmoid(x) = 1/(1+e^-x),ReLU(x) = max(0, x)

  2. 计算合理的参数,如w1,b1,w2,b2等,常用的是梯度下降法,神经网络Back Propagation算法难理解的就是这个,例如上面式子:
    w1 := w1 - rate*dw1
    w2 := w2 - rate*dw2
    b1 := b1 - rate*db1
    b2 := b2 - rate*db2
    理论上只要能合理的计算参数,使预测函数朝着最优前进的参数即可。

  3. 计算代价函数cost function,使之尽量小,举例如
    cost function = (1/m) * 累加符(predict function(i) - y(i))^2, i = 1,2,3,…,m.(m为训练集个数)

综上,大多算法都是考虑以上三个部分,因为我上面举例是比较简单的,其它变化有这些函数使用不同的还有一些优化问题,防止过度拟合以及考虑算法效率等各种问题。

Back Propagation算法

给定训练集{(x1, y1), (x2, y2), (x3, y3), … ,(xm, ym)}, 以及你自己搭建的神经网络, 共L层。

  1. 前向传播,计算出每层单元al, 这里的x, w, b, a, z都是矩阵,xi为训练集(xi, yi), 如上:
    a0 = xi;
    z1 = w1 * x + b1;
    a1 = activation1(z1);
    z2 = w2 * a1 + b2;
    a2 = activation2(z2);

    zl = wl * al-1 + bl;
    al = activationl(zl);
    ….
    zL = wL * aL-1 + bL;
    aLi = activationL(zL).

  2. 计算每一层单元的误差delta, yi为训练集(xi, yi), activationT(x)为,activation(x)的导函数,如上:
    deltaL = aLi - yi;
    deltaL-1 = (wL.T * deltaL) .* activationL(aL-1);
    deltaL-2 = (wL-1.T * deltaL-1) .* activationL-1(aL-2);

    delta1 = (w2.T * delta2) .* activation2(a1)

  3. 将每一层单元的误差传递给参数w,b, D初始化为0, 如上:
    D1 = D1 + delta1 * a0.T = D1 + delta1 * x.T;
    D2 = D2 + delta2 * a1.T;
    D3 = D3 + delta3 * a2.T;

    DL = DL + deltaL-1 * aL-1.T;

  4. 将1,2,3遍历m次后,更新参数w,b, 如上:
    w1 = w1 - rate * (1/m) * (D1 + lambda * w1);
    b1 = b1 - rate * delta1;
    w2 = w2 - rate * (1/m) * (D2 + lambda * w2);
    b2 = b2 - rate * delta2;

    wL = wL - rate * (1/m) * (DL + lambda * wL);
    bL = bL - rate * deltaL;

根据更新后的参数w, b,可以计算出新的预测函数predict function, 也可以计算出新的代价函数cost function.上面所得,可以看出dw = (1/m) * (D + lambda * w), 对错吗,自行找资料或者自行证明吧。

代码

未借助框架, 只用了numpy里的矩阵运算,当然用框架很简单,我搭的网络三层,个数为输入层1,隐藏层3,5,输出层1.

import numpy as npimport matplotlib.pyplot as plt#前向传播构造网络def add_layer(previous_layer_units, weight, bias, activation_function=None):    Wx_b_plus = np.dot(weight, previous_layer_units) + bias    if activation_function is None:        next_layer_units = Wx_b_plus    else:        next_layer_units = activation_function(Wx_b_plus)    return next_layer_units#激活函数sigmoiddef Sigmoid(x):    return 1/(1 + np.exp(-x))#激活函数的导数,x为矩阵点乘def SigmoidT(x):    return x * (1-x)#反向传播, back propagationdef back_propagation(x, y, m, w1, b1, w2, b2, w3, b3, lambd, rate):    D1 = np.zeros(w1.shape)    D2 = np.zeros(w2.shape)    D3 = np.zeros(w3.shape)    for i in range(m):        #1.前向传播, forward propagation        a1 = add_layer(x[i], w1, b1, activation_function=Sigmoid)        a2 = add_layer(a1, w2, b2, activation_function=Sigmoid)        a3 = add_layer(a2, w3, b3, activation_function=Sigmoid)        #2.计算每一层每个单元的误差delta, computing delta        delta3 = a3 - y[i]        delta2 = np.dot(w3.T, delta3) * SigmoidT(a2)        delta1 = np.dot(w2.T, delta2) * SigmoidT(a1)        #3.利用每一层单元的误差, 将其传递给权重weight, 并累加        D1 = D1 + np.dot(delta1, x[i].T)        D2 = D2 + np.dot(delta2, a1.T)        D3 = D3 + np.dot(delta3, a2.T)    #4.计算平均值, 加入超参数lambd控制更新    D1 = (1/m) * (D1 + lambd * w1)    D2 = (1/m) * (D2 + lambd * w2)    D3 = (1/m) * (D3 + lambd * w3)    #5.更新权重, 加入梯度下降速率rate    w1 = w1 - rate * D1    b1 = b1 - rate * delta1    w2 = w2 - rate * D2    b2 = b2 - rate * delta2    w3 = w3 - rate * D3    b3 = b3 - rate * delta3    #6.计算成本函数, compute cost function    J = 0    for i in range(m):        a1 = add_layer(x[i], w1, b1, activation_function=Sigmoid)        a2 = add_layer(a1, w2, b2, activation_function=Sigmoid)        a3 = add_layer(a2, w3, b3, activation_function=Sigmoid)        J = J + (a3 - y[i]) * (a3 - y[i])    J = J / m    return J, w1, b1, w2, b2, w3, b3#训练def train(x, y, m, lambd, rate, iters, ax):    w1 = np.random.rand(3, 1) * 0.01    b1 = np.zeros((3, 1))    w2 = np.random.rand(5, 3) * 0.01    b2 = np.zeros((5, 1))    w3 = np.random.rand(1, 5) * 0.01    b3 = np.zeros((1, 1))    for i in range(iters):        J, w1, b1, w2, b2, w3, b3 = back_propagation(x, y, m, w1, b1, w2, b2, w3, b3, lambd, rate)        print(J) #打印loss        try:            ax.lines.remove(lines[0])        except Exception:            pass        prediction_value = np.zeros(x.shape)        for i in range(m):            a1 = add_layer(x[i], w1, b1, activation_function=Sigmoid)            a2 = add_layer(a1, w2, b2, activation_function=Sigmoid)            a3 = add_layer(a2, w3, b3, activation_function=Sigmoid)            prediction_value[i] = a3        lines = ax.plot(x, prediction_value, 'r-', lw=5)        plt.pause(0.2)x_data = np.linspace(-10, 10, 200, dtype=np.float32)y = np.zeros(x_data.shape)for i in range(200):    if x_data[i] < 0:        y[i] = 1    else:        y[i] = 0plt.ion()fig = plt.figure()ax = fig.add_subplot(1, 1, 1)ax.scatter(x_data, y)plt.show()train(x_data, y, 200, 0, 0.5, 100, ax)

结果

蓝色的为原函数,红色的为训练出来的预测函数predict function
这里写图片描述

结束语

因为我使用的都是最简单的函数,而且未经过任何优化处理,所以当你预测非常复杂的函数会出现各种问题。当然,我只是用最简单的来展现神经网络算法的思路,不足之处请见谅。