当前位置: 首页 > 科技观察

用Python实现机器学习算法:神经网络

时间:2023-03-22 15:08:08 科技观察

今天继续介绍基于感知机的神经网络模型。我们都知道感知器是一个线性模型,很难给出非线性问题的解。比如大家熟知的异或问题(XOR)就是一个典型的线性不可分问题,普通的感知器很难处理:因此,我们在普通感知器的基础上,扩展了感知器的结构,通过的方式来添加隐藏层是为了让感知器适应非线性问题。这种包含隐藏层结构的感知器模型就是神经网络,也称为多层感知器(MultilayerPerceptron)。关于神经网络的概念和知识有很多:包括输入层、隐藏层、输出层、激活函数、正向传播、反向传播、梯度下降、权值更新等概念。生成数据本节以一个二层网络,即单隐层网络为例,看看如何使用numpy实现一个神经网络模型。在正式搭建神经网络之前,我们先来准备一下数据。定义一个数据生成函数:defcreate_dataset():np.random.seed(1)m=400#数据量N=int(m/2)#每个标签的实例数D=2#数据维度X=np.zeros((m,D))#数据矩阵Y=np.zeros((m,1),dtype='uint8')#标签维度a=4forjinrange(2):ix=range(N*j,N*(j+1))t=np.linspace(j*3.12,(j+1)*3.12,N)+np.random.randn(N)*0.2#thetar=a*np.sin(4*t)+np.random.randn(N)*0.2#半径X[ix]=np.c_[r*np.sin(t),r*np.cos(t)]Y[ix]=jX=X.TY=Y.TreturnX,Y数据可视化展示如下:继续回顾搭建神经网络的基本思路和步骤:定义网络结构(指定输出层、隐藏层、输出的大小层),初始化模型参数,循环:执行正向传播/计算损失/执行反向传播/权值更新定义网络结构假设X为神经网络的输入特征矩阵,y为标签向量。单层神经网络结构如下:网络结构函数定义如下:deflayer_sizes(X,Y):n_x=X.shape[0]#输入层大小n_h=4#hiddenlayersizen_y=Y.shape[0]#Outputlayersizereturn(n_x,n_h,n_y)其中输入层和输出层的大小分别与X和y的形状有关。隐藏层的大小可以由我们手动指定。这里我们指定隐藏层的大小为4。初始化模型参数假设W1是输入层到隐藏层的权重数组,b1是输入层到隐藏层的偏置数组;w2是隐藏层到输出层的权重数组,b2是隐藏层到输出层的偏置数组。所以我们定义参数初始化函数如下:definitialize_parameters(n_x,n_h,n_y):W1=np.random.randn(n_h,n_x)*0.01b1=np.zeros((n_h,1))W2=np.random.randn(n_h,n_x)*0.01b1=np.zeros((n_h,1))随机的。randn(n_y,n_h)*0.01b2=np.zeros((n_y,1))assert(W1.shape==(n_h,n_x))assert(b1.shape==(n_h,1))assert(W2.shape==(n_y,n_h))assert(b2.shape==(n_y,1))parameters={"W1":W1,"b1":b1,"W2":W2,"b2":b2}返回参数其中,我们使用模块np.random。numpy中的randn初始化权重值,使用np.zeros模块初始化bias。通过设置字典进行封装,返回包含初始化参数的结果。在前向传播定义了网络结构并初始化了参数之后,就可以开始神经网络的训练过程了。训练的第一步是执行前向传递计算。假设隐藏层的激活函数是tanh函数,输出层的激活函数是sigmoid函数。前向传播计算表示为:定义前向传播计算函数为:defforward_propagation(X,parameters):#获取每个参数的初始值W1=parameters['W1']b1=parameters['b1']W2=parameters['W2']b2=parameters['b2']#进行前向计算Z1=np.dot(W1,X)+b1A1=np.tanh(Z1)Z2=np.dot(W2,A1)+b2A2=sigmoid(Z2)assert(A2.shape==(1,X.shape[1]))cache={"Z1":Z1,"A1":A1,"Z2":Z2,"A2":A2}returnA2,缓存从参数初始化结果字典中获取各自的参数,然后进行前向传播计算,将前向传播计算的结果保存到缓存字典中,其中A2为sigmoid激活函数激活的输出层的结果。计算当前训练损失在前向传播计算完成后,我们需要确定用当前参数进行计算后输出与标签值之间的损失。和注1一样,损失函数也选择交叉熵损失:定义计算损失函数为:defcompute_cost(A2,Y,parameters):#trainingsamplesizem=Y.shape[1]#calculatecross-entropylosslogprobs=np.multiply(np.log(A2),Y)+np.multiply(np.log(1-A2),1-Y)cost=-1/m*np.sum(logprobs)#维度压缩成本=np。squeeze(cost)assert(isinstance(cost,float))returncost执行反向传播当前向传播和当前损失确定后,需要继续反向传播过程调整权重。中间涉及到各个参数的梯度计算,如下图:根据上面的梯度计算公式定义反向传播函数:defbackward_propagation(parameters,cache,X,Y):m=X.shape[1]#获取W1和W2W1=parameters['W1']W2=parameters['W2']#获取A1和A2A1=cache['A1']A2=cache['A2']#进行反向传播dZ2=A2-YdW2=1/m*np.dot(dZ2,A1.T)db2=1/m*np.sum(dZ2,axis=1,keepdims=True)dZ1=np.dot(W2.T,dZ2)*(1-np.power(A1,2))dW1=1/m*np.dot(dZ1,X.T)db1=1/m*np.sum(dZ1,axis=1,keepdims=True)grads={"dW1":dW1,"db1":db1,"dW2":dW2,"db2":db2}returngrads将各参数的求导计算结果放入字典grad中返回。这里需要提到的是涉及到的数值优化方面的知识。在机器学习中,当学习到的问题具有特定的形式时,机器学习就会被形式化为一个优化问题。无论是梯度下降法、随机梯度下降法、牛顿法、拟牛顿法,还是Adam等高级优化算法,掌握其数学原理都需要时间。权重更新迭代计算的最后一步是根据反向传播的结果更新权重。更新公式如下:权重更新函数可以通过这个公式来定义:defupdate_parameters(parameters,grads,learning_rate=1.2):#GetParameterW1=parameters['W1']b1=parameters['b1']W2=parameters['W2']b2=parameters['b2']#获取梯度dW1=grads['dW1']db1=grads['db1']dW2=grads['dW2']db2=grads['db2']#参数更新W1-=dW1*learning_rateb1-=db1*learning_rateW2-=dW2*learning_rateb2-=db2*learning_rateparameters={"W1":W1,"b1":b1,"W2":W2,"b2":b2}返回参数这样就完成了前向传播-计算损失-反向传播-权值更新的神经网络训练过程。现在,就像之前的讲座一样,为了更pythonic,我们也组合各种模块来定义一个神经网络模型:defnn_model(X,Y,n_h,num_iterations=10000,print_cost=False):np.random。seed(3)n_x=layer_sizes(X,Y)[0]n_y=layer_sizes(X,Y)[2]#初始化模型参数parameters=initialize_parameters(n_x,n_h,n_y)W1=parameters['W1']b1=parameters['b1']W2=parameters['W2']b2=parameters['b2']#梯度下降和参数更新周期foriinrange(0,num_iterations):#前向传播计算A2,cache=forward_propagation(X,parameters)#计算当前损失cost=compute_cost(A2,Y,parameters)#反向传播grads=backward_propagation(parameters,cache,X,Y)#参数更新parameters=update_parameters(parameters,grads,learning_rate=1.2)#打印损失ifprint_costandi%1000==0:print("Costafteriteration%i:%f"%(i,cost))returnparameters模型主体完成后,可以根据训练结果做一个预测函数也可以定义为:defpredict(parameters,X):A2,cache=forward_propagation(X,parameters)predictions=(A2>0.5)returnpredictions接下来,我们将根据之前生成的数据来测试模型:parameters=nn_model(X,Y,n_h=4,num_iterations=10000,print_cost=True)经过9000次迭代后,loss下降到0.21我们来看看测试的准确率:#预测准确率predictions=predict(parameters,X)print('Accuracy:%d'%float((np.dot(Y,predictions.T)+np.dot(1-Y,1-predictions.T))/float(Y.size)*100)+'%')测试精度达到0.9。绘制神经网络决策边界的效果如下:以上就是本节的主要内容,使用numpy手动搭建单层神经网络。