机器学习--神经网络

时间:2022-12-25 15:09:22

机器学习–神经网络

如有错误或者疑问,欢迎交流,转载请注明出处

前向传播

神经网络的预测过程,由输入特征前向计算预测输出
机器学习--神经网络

除了输入层以外,隐藏层和输出层都是以sigmoid函数作为激活函数,输入层和隐藏层都加了偏置+1

import numpy as np
form sigmoid import * #自己写一个sigmoid函数
def nn_predict(theta1,theta2,X):
    ''' INPUT: theta1: 输入层到隐藏层参数 (hidden feature dim,input feature dim) ndarray theta2: 隐藏层到输出层参数 (output label dim,hidden feature dim) ndarray X: (m,n) ndarray m是测试样本数目 '''
    m = x.shape[0]
    num_labels = theta2.shape[0]
    x = np.c_[np.ones(m),x] #加上偏置
    z2 = x.dot(theta1.T)
    a2 = sigmoid(z2)
    a2 = np.c_[np.ones(m),a2] #加上偏置

    z3 = a2.dot(theta2.T)
    a3 = sigmoid(z3)
    prediction = np.argmax(a3,axis=1) #返回概率最大的index

    return prediction

反向传播学习

利用反向传播算法,根据带标签数据学习网络参数
1.定义损失函数
2.损失函数对参数求导
3.梯度法更新参数

  • cross entropy loss
    因为参考了安主的Coursera Machine Learning课程,用了这个损失函数

    J(θ)=1mmi=1Kk=1[y(i)klog((h(x(i)))k)(1y(i)k)log(1(h(x(i)))k)]

    其中m是训练样本数目,K是标签数目,感觉是逻辑回归损失函数的广泛定义,标签y是onehot编码的[0,0,0,1,…,0],类似这种

  • 残差
    残差就是损失函数对某个节点的输入的求导吧,求认证~
    所以

    对输出层的第j个节点的输入求导,有点绕~,固定住损失函数的k,针对一个样例分析,即固定i

    δ(3)j=====z(3)j(yjlogg(z(3)j)(1yj)log(1g(z(3)j)))(yj1g(z(3)j)+(1yj)11g(z(3)j))g(z(3)j)z(3)j(yj1g(z(3)j)+(1yj)11g(z(3)j))(g(z(3)j)(1g(z(3)j))yj(1g(z(3)j)+(1yj)g(z(3)j)g(z(3)j)yj

    写成向量的样子 δ(3)=a(3)y
    然后回传到隐藏层,其实是在做链式求导吧~

    δ(2)=(θ(2))Tδ(3)g(z(2)) 就是把导数求到了隐藏层的输入而已吧~

    最终要求的其实是损失函数对参数的求导

    Δ(l)=δ(l+1)(a(l))T

    直观理解就是损失函数求导至l+1层的输入,而l+1层的输入是由参数 θ 与l层的输出线性组合得到的,所以继续链式求导就行了

#backpropagation
for i in range(m):#m是训练样本数目
    a1 = X[i]#(input_layer_size+1,) ndarray
    a1 = a1.reshape(1,input_layer_size+1)#这句为了形状正确~
    z2 = a1.dot(theta1.T)#theta1(hidden_layer_size,input_layer_size+1)
    a2 = sigmoid(z2)
    a2 = np.c_[np.ones(1),a2]#增加偏置

    z3 = a2.dot(theta2.T)#theta2(output_layer_size,hidden_layer_size+1)
    a3 = sigmoid(z3)

    delta3 = (a3 - yk[i])#yk:onehot label

    z2 = np.c_[np.ones(1),z2]
    delta2 = delta3.dot(theta2) * sigmoid_gradient(z2)
    theta2_grad = theta2_grad + delta3.T.dot(a2)
    theta1_grad = theta1_grad + delta2.T.dot(a1)[1:] #偏置项不反向传递误差
theta1_grad[:,0] = theta1_grad[:,:] / m
theta2_grad[:,0] = theta2_grad[:,:] / m

代码可以借鉴一下,和公式有出路,感觉只要写好公式,注意点矩阵的形状,问题不大。