• 用Python实现BP神经网络(附代码)


    用Python实现出来的机器学习算法都是什么样子呢? 前两期线性回归及逻辑回归项目已发布(见文末链接),今天来讲讲BP神经网络。

    BP神经网络

    全部代码

    https://github.com/lawlite19/MachineLearning_Python/blob/master/NeuralNetwok/NeuralNetwork.py

    神经网络model

    先介绍个三层的神经网络,如下图所示

    输入层(input layer)有三个units(

    用Python实现BP神经网络(附代码)

    为补上的bias,通常设为1)

    用Python实现BP神经网络(附代码)

    表示第j层的第i个激励,也称为为单元unit

    用Python实现BP神经网络(附代码)

    为第j层到第j+1层映射的权重矩阵,就是每条边的权重

    用Python实现BP神经网络(附代码)

    所以可以得到:

    隐含层:

    用Python实现BP神经网络(附代码)

    用Python实现BP神经网络(附代码)

    用Python实现BP神经网络(附代码)

    输出层

    用Python实现BP神经网络(附代码)

    其中,S型函数

    用Python实现BP神经网络(附代码)

    ,也成为激励函数

    可以看出

    用Python实现BP神经网络(附代码)

    为3x4的矩阵,

    用Python实现BP神经网络(附代码)

    为1x4的矩阵

    用Python实现BP神经网络(附代码)

    ==》j+1的单元数x(j层的单元数+1)

    代价函数

    假设最后输出的

    用Python实现BP神经网络(附代码)

    ,即代表输出层有K个单元

    用Python实现BP神经网络(附代码)

    其中,

    用Python实现BP神经网络(附代码)

    代表第i个单元输出与逻辑回归的代价函数

    用Python实现BP神经网络(附代码)

    差不多,就是累加上每个输出(共有K个输出)

    正则化

    L-->所有层的个数

    用Python实现BP神经网络(附代码)

    -->第l层unit的个数

    正则化后的代价函数为

    用Python实现BP神经网络(附代码)

    用Python实现BP神经网络(附代码)

    共有L-1层,然后是累加对应每一层的theta矩阵,注意不包含加上偏置项对应的theta(0)

    正则化后的代价函数实现代码:

    # 代价函数

    def nnCostFunction(nn_params,input_layer_size,hidden_layer_size,num_labels,X,y,Lambda):

    length = nn_params.shape[0] # theta的中长度

    # 还原theta1和theta2

    Theta1 = nn_params[0:hidden_layer_size*(input_layer_size+1)].reshape(hidden_layer_size,input_layer_size+1)

    Theta2 = nn_params[hidden_layer_size*(input_layer_size+1):length].reshape(num_labels,hidden_layer_size+1)

    # np.savetxt("Theta1.csv",Theta1,delimiter=',')

    m = X.shape[0]

    class_y = np.zeros((m,num_labels)) # 数据的y对应0-9,需要映射为0/1的关系

    # 映射y

    for i in range(num_labels):

    class_y[:,i] = np.int32(y==i).reshape(1,-1) # 注意reshape(1,-1)才可以赋值

    '''去掉theta1和theta2的第一列,因为正则化时从1开始'''

    Theta1_colCount = Theta1.shape[1]

    Theta1_x = Theta1[:,1:Theta1_colCount]

    Theta2_colCount = Theta2.shape[1]

    Theta2_x = Theta2[:,1:Theta2_colCount]

    # 正则化向theta^2

    term = np.dot(np.transpose(np.vstack((Theta1_x.reshape(-1,1),Theta2_x.reshape(-1,1)))),np.vstack((Theta1_x.reshape(-1,1),Theta2_x.reshape(-1,1))))

    '''正向传播,每次需要补上一列1的偏置bias'''

    a1 = np.hstack((np.ones((m,1)),X))

    z2 = np.dot(a1,np.transpose(Theta1))

    a2 = sigmoid(z2)

    a2 = np.hstack((np.ones((m,1)),a2))

    z3 = np.dot(a2,np.transpose(Theta2))

    h = sigmoid(z3)

    '''代价'''

    J = -(np.dot(np.transpose(class_y.reshape(-1,1)),np.log(h.reshape(-1,1)))+np.dot(np.transpose(1-class_y.reshape(-1,1)),np.log(1-h.reshape(-1,1)))-Lambda*term/2)/m

    return np.ravel(J)

    反向传播BP

    上面正向传播可以计算得到J(θ),使用梯度下降法还需要求它的梯度

    BP反向传播的目的就是求代价函数的梯度

    假设4层的神经网络,

    用Python实现BP神经网络(附代码)

    记为-->l层第j个单元的误差

    用Python实现BP神经网络(附代码)

    《===》

    用Python实现BP神经网络(附代码)

    (向量化)

    用Python实现BP神经网络(附代码)

    用Python实现BP神经网络(附代码)

    没有

    用Python实现BP神经网络(附代码)

    ,因为对于输入没有误差

    因为S型函数

    用Python实现BP神经网络(附代码)

    的倒数为:

    用Python实现BP神经网络(附代码)

    所以上面的

    用Python实现BP神经网络(附代码)

    用Python实现BP神经网络(附代码)

    可以在前向传播中计算出来

    反向传播计算梯度的过程为:

    用Python实现BP神经网络(附代码)

    用Python实现BP神经网络(附代码)

    是大写的

    用Python实现BP神经网络(附代码)

    for i=1-m:-

    用Python实现BP神经网络(附代码)

    -正向传播计算

    用Python实现BP神经网络(附代码)

    (l=2,3,4...L)

    -反向计算

    用Python实现BP神经网络(附代码)

    用Python实现BP神经网络(附代码)

    ...

    用Python实现BP神经网络(附代码)

    -

    用Python实现BP神经网络(附代码)

    -

    用Python实现BP神经网络(附代码)

    用Python实现BP神经网络(附代码)

    最后

    用Python实现BP神经网络(附代码)

    ,即得到代价函数的梯度

    实现代码:

    # 梯度

    def nnGradient(nn_params,input_layer_size,hidden_layer_size,num_labels,X,y,Lambda):

    length = nn_params.shape[0]

    Theta1 = nn_params[0:hidden_layer_size*(input_layer_size+1)].reshape(hidden_layer_size,input_layer_size+1)

    Theta2 = nn_params[hidden_layer_size*(input_layer_size+1):length].reshape(num_labels,hidden_layer_size+1)

    m = X.shape[0]

    class_y = np.zeros((m,num_labels)) # 数据的y对应0-9,需要映射为0/1的关系

    # 映射y

    for i in range(num_labels):

    class_y[:,i] = np.int32(y==i).reshape(1,-1) # 注意reshape(1,-1)才可以赋值

    '''去掉theta1和theta2的第一列,因为正则化时从1开始'''

    Theta1_colCount = Theta1.shape[1]

    Theta1_x = Theta1[:,1:Theta1_colCount]

    Theta2_colCount = Theta2.shape[1]

    Theta2_x = Theta2[:,1:Theta2_colCount]

    Theta1_grad = np.zeros((Theta1.shape)) #第一层到第二层的权重

    Theta2_grad = np.zeros((Theta2.shape)) #第二层到第三层的权重

    Theta1[:,0] = 0;

    Theta2[:,0] = 0;

    '''正向传播,每次需要补上一列1的偏置bias'''

    a1 = np.hstack((np.ones((m,1)),X))

    z2 = np.dot(a1,np.transpose(Theta1))

    a2 = sigmoid(z2)

    a2 = np.hstack((np.ones((m,1)),a2))

    z3 = np.dot(a2,np.transpose(Theta2))

    h = sigmoid(z3)

    '''反向传播,delta为误差,'''

    delta3 = np.zeros((m,num_labels))

    delta2 = np.zeros((m,hidden_layer_size))

    for i in range(m):

    delta3[i,:] = h[i,:]-class_y[i,:]

    Theta2_grad = Theta2_grad+np.dot(np.transpose(delta3[i,:].reshape(1,-1)),a2[i,:].reshape(1,-1))

    delta2[i,:] = np.dot(delta3[i,:].reshape(1,-1),Theta2_x)*sigmoidGradient(z2[i,:])

    Theta1_grad = Theta1_grad+np.dot(np.transpose(delta2[i,:].reshape(1,-1)),a1[i,:].reshape(1,-1))

    '''梯度'''

    grad = (np.vstack((Theta1_grad.reshape(-1,1),Theta2_grad.reshape(-1,1)))+Lambda*np.vstack((Theta1.reshape(-1,1),Theta2.reshape(-1,1))))/m

    return np.ravel(grad)

    BP可以求梯度的原因

    实际是利用了链式求导法则

    因为下一层的单元利用上一层的单元作为输入进行计算

    大体的推导过程如下,最终我们是想预测函数与已知的y非常接近,求均方差的梯度沿着此梯度方向可使代价函数最小化。可对照上面求梯度的过程。

    用Python实现BP神经网络(附代码)

    求误差更详细的推导过程:

    用Python实现BP神经网络(附代码)

    梯度检查

    检查利用BP求的梯度是否正确

    利用导数的定义验证:

    用Python实现BP神经网络(附代码)

    求出来的数值梯度应该与BP求出的梯度非常接近

    验证BP正确后就不需要再执行验证梯度的算法了

    实现代码:

    # 检验梯度是否计算正确

    # 检验梯度是否计算正确

    def checkGradient(Lambda = 0):

    '''构造一个小型的神经网络验证,因为数值法计算梯度很浪费时间,而且验证正确后之后就不再需要验证了'''

    input_layer_size = 3

    hidden_layer_size = 5

    num_labels = 3

    m = 5

    initial_Theta1 = debugInitializeWeights(input_layer_size,hidden_layer_size);

    initial_Theta2 = debugInitializeWeights(hidden_layer_size,num_labels)

    X = debugInitializeWeights(input_layer_size-1,m)

    y = 1+np.transpose(np.mod(np.arange(1,m+1), num_labels))# 初始化y

    y = y.reshape(-1,1)

    nn_params = np.vstack((initial_Theta1.reshape(-1,1),initial_Theta2.reshape(-1,1))) #展开theta

    '''BP求出梯度'''

    grad = nnGradient(nn_params, input_layer_size, hidden_layer_size,

    num_labels, X, y, Lambda)

    '''使用数值法计算梯度'''

    num_grad = np.zeros((nn_params.shape[0]))

    step = np.zeros((nn_params.shape[0]))

    e = 1e-4

    for i in range(nn_params.shape[0]):

    step[i] = e

    loss1 = nnCostFunction(nn_params-step.reshape(-1,1), input_layer_size, hidden_layer_size,

    num_labels, X, y,

    Lambda)

    loss2 = nnCostFunction(nn_params+step.reshape(-1,1), input_layer_size, hidden_layer_size,

    num_labels, X, y,

    Lambda)

    num_grad[i] = (loss2-loss1)/(2*e)

    step[i]=0

    # 显示两列比较

    res = np.hstack((num_grad.reshape(-1,1),grad.reshape(-1,1)))

    print res

    权重的随机初始化

    神经网络不能像逻辑回归那样初始化theta为0,因为若是每条边的权重都为0,每个神经元都是相同的输出,在反向传播中也会得到同样的梯度,最终只会预测一种结果。

    所以应该初始化为接近0的数

    实现代码

    # 随机初始化权重theta

    def randInitializeWeights(L_in,L_out):

    W = np.zeros((L_out,1+L_in)) # 对应theta的权重

    epsilon_init = (6.0/(L_out+L_in))**0.5

    W = np.random.rand(L_out,1+L_in)*2*epsilon_init-epsilon_init # np.random.rand(L_out,1+L_in)产生L_out*(1+L_in)大小的随机矩阵

    return W

    预测

    正向传播预测结果

    实现代码

    # 预测

    def predict(Theta1,Theta2,X):

    m = X.shape[0]

    num_labels = Theta2.shape[0]

    #p = np.zeros((m,1))

    '''正向传播,预测结果'''

    X = np.hstack((np.ones((m,1)),X))

    h1 = sigmoid(np.dot(X,np.transpose(Theta1)))

    h1 = np.hstack((np.ones((m,1)),h1))

    h2 = sigmoid(np.dot(h1,np.transpose(Theta2)))

    '''

    返回h中每一行最大值所在的列号

    - np.max(h, axis=1)返回h中每一行的最大值(是某个数字的最大概率)

    - 最后where找到的最大概率所在的列号(列号即是对应的数字)

    '''

    #np.savetxt("h2.csv",h2,delimiter=',')

    p = np.array(np.where(h2[0,:] == np.max(h2, axis=1)[0]))

    for i in np.arange(1, m):

    t = np.array(np.where(h2[i,:] == np.max(h2, axis=1)[i]))

    p = np.vstack((p,t))

    return p

    输出结果

    梯度检查:

    用Python实现BP神经网络(附代码)

    随机显示100个手写数字

    用Python实现BP神经网络(附代码)

    显示theta1权重

    用Python实现BP神经网络(附代码)

    训练集预测准确度

    用Python实现BP神经网络(附代码)

    归一化后训练集预测准确度

    用Python实现BP神经网络(附代码)

  • 相关阅读:
    配置Mysql远程访问
    mysql Access denied for user root@localhost错误处理备忘
    MsSql判断表是否有自增标识
    .net用NPOI生成Word表格
    TensorFlow-卷积
    Java中int与Integer的区别
    由经纬度坐标得到腾讯地图的瓦片/切片行列号
    vs code上配置Scala
    VMware虚拟机上配置CentOS联网
    使用PuTTy在CentOS下安装web.py与简单的文件传输
  • 原文地址:https://www.cnblogs.com/nice107/p/8204197.html
Copyright © 2020-2023  润新知