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

从零开始构建简单人工神经网络:1个隐藏层_0

时间:2023-03-13 00:55:12 科技观察

从头开始构建一个简单的人工神经网络:1个隐藏层从头开始构建一个只有1个输入层和1个输出层的简单神经网络。这个神经网络叫做感知器。然而,能够执行图像分类和股票市场分析等复杂任务的实际神经网络除了输入和输出层之外还有多个隐藏层。我们在上一篇文章中得出结论,Perceptron能够找到线性决策边界。在虚拟数据集的帮助下,我们使用Perceptron来预测某人是否患有糖尿病。然而,Perceptron无法找到非线性决策边界。在本文中,我们将构建一个具有1个输入层、1个隐藏层和1个输出层的神经网络。我们将看到我们构建的神经网络能够找到非线性边界。要生成数据集,建议先创建一个试验数据集。幸运的是,scikit-learn有一些有用的数据集生成器,所以我们不需要自己编写代码。我们将使用make_moons函数。fromsklearnimportdatasetsnp.random.seed(0)feature_set,labels=datasets.make_moons(300,noise=0.20)plt.figure(figsize=(10,7))plt.scatter(feature_set[:,0],feature_set[:,1],c=labels,cmap=plt.cm.Spectral)图1我们生成的数据集有两个类别,分别标记为红点和蓝点。将蓝点视为男性患者,将红点视为女性患者,x轴和y轴上有医疗指标。我们的目标是训练一个机器学习分类器,它可以根据x和y坐标预测正确的类别(男性或女性)。请注意,数据不是线性可分的,我们不能画一条直线将两个类别分开。这意味着除非您手动设计适合特定数据集的非线性特征(例如多项式),否则线性分类器(例如没有任何隐藏层的ANN甚至逻辑回归)将无法拟合数据。具有1个隐藏层的神经网络这是我们的简单网络:图2我们有两个输入:x1和x2。有一个隐藏层,它有3个单元(节点):h1、h2和h3。最后,有两个输出:y1和y2。连接它们的箭头是重量。有两个权重矩阵:w和u。w权重将输入层连接到隐藏层,u权重将隐藏层连接到输出层。我们使用字母w和u以便更容易专注于要关注的计算。您还可以看到我们将输出y1和y2与目标t1和t2进行了比较。在进行计算之前,我们需要介绍最后一个字母。设a为激活前的线性组合。因此,我们有:由于我们无法穷尽所有激活函数和所有损失函数,因此我们将重点放在两个最常见的函数上。S形激活和L2范数损失。有了这个新信息和新符号,输出y等于激活的线性组合。那么,就输出层而言,我们有:由于方法不同,我们将分别考察输出层和隐藏层的反向传播。提醒一下:sigmoid函数是:导数是:输出层的反向传播为了得到更新规则:我们以计算单个权重uij为例。损失w.r.t.的偏导数uij等于:其中i对应上一层(本次变换的输入层),j对应下一层(本次变换的输出层)。可以根据链式法则计算偏导数。关注L2范数损失导数。关注sigmoid导数。最后,三阶偏导数是以下导数:因此,代入上述表达式中的偏导数,我们得到:因此,输出层各个权重的更新规则为:隐藏层和输出的反向传播layer和反向传播类似,wij会依赖:关注链式法则。使用到目前为止我们已经能够通过sigmoid激活和线性模型进行转换的内容,我们得到:反向传播的真正问题来自术语,这是由于没有“隐藏”目标这一事实。权重w11的解决方案如下所示。查看计算过程时,建议先看上图所示的NN图。从这里,我们可以计算出这就是我们想要的。最终表达式是:这个方程的广义形式是:反向传播的推广利用输出层和隐藏层的反向传播结果,我们可以在存在L2范数损失的情况下将它们放入一个公式中并总结反向传播与乙状结肠激活。在隐藏层方面,实现具有1个隐藏层的神经网络的代码现在可以使用Python实现我们刚刚从头开始的神经网络。我们将再次尝试对上面创建的非线性数据进行分类。我们首先为梯度下降定义一些有用的变量和参数,例如训练数据集大小、输入层和输出层的维度。num_examples=len(X)#trainingsetsizenn_input_dim=2#inputlayerdimensionalitynn_output_dim=2#outputlayerdimensionality也定义了梯度下降参数。epsilon=0.01#learningrateforgradientdescentreg_lambda=0.01#regularizationstrength首先,让我们实现上面定义的损失函数。我们使用此函数来评估模型的性能:#Helperfunctiontoevaluatethetotallossonthedatasetdefcalculate_loss(model,X,y):num_examples=len(X)#trainingsetsizeW1,b1,W2,b2=model['W1'],model['b1'],model['W2'],model['b2']#Forwardpropagationtocalculateourpredictionsz1=X.dot(W1)+b1a1=np.tanh(z1)z2=a1.dot(W2)+b2exp_scores=np.exp(z2)probs=exp_scores/np.sum(exp_scores,axis=1,keepdims=True)#Calculatingthelosscorect_logprobs=-np.log(probs[range(num_examples),y])data_loss=np.sum(corect_logprobs)#Addregulationtermtoloss(可选)数据损失+=Config.reg_lambda/2*(np.sum(np.square(W1))+np.sum(np.square(W2)))return1./num_examples*data_loss我们还实现了辅助函数来计算网络的输出.它进行前向传递,返回概率最高的类。defpredict(model,x):W1,b1,W2,b2=model['W1'],model['b1'],model['W2'],model['b2']#Forwardpropagationz1=x.dot(W1)+b1a1=np.tanh(z1)z2=a1.dot(W2)+b2exp_scores=np.exp(z2)probs=exp_scores/np.sum(exp_scores,axis=1,keepdims=True)returnnp.argmax(probs,axis=1)最后是训练神经网络的函数。它使用我们在上面找到的反向传播导数来实现批量梯度下降。此函数在学习神经网络的参数后返回模型。nn_hdim:隐藏层的节点数。num_passes:遍历梯度下降训练数据的次数。print_loss:如果为真,则每1000次迭代打印出损失。defbuild_model(X,y,nn_hdim,num_passes=20000,print_loss=False):#Initializetheparameterstorandomvalues.Weneedtolearnthese.num_examples=len(X)np.random.seed(0)W1=np.random.randn(Config.nn_input_dim,nn_hdim)/np.sqrt(Config.nn_input_dim)b1=np.zeros((1,nn_hdim))W2=np.random.randn(nn_hdim,Config.nn_output_dim)/np.sqrt(nn_hdim)b2=np.zeros((1,Config.nn_output_dim))#Thisiswhatwereturnattheendmodel={}#Gradientdescent.Foreachbatch...foriinrange(0,num_passes):#Forwardpropagationz1=X.dot(W1)+b1a1=np.tanh(z1)z2=a1.dot(W2)+b2exp_scores=np.exp(z2)probs=exp_scores/np.sum(exp_scores,axis=1,keepdims=True)#Backpropagationdelta3=probsdelta3[range(num_examples),y]-=1dW2=(a1.T)。点(delta3)db2=np.sum(delta3,axis=0,keepdims=True)delta2=delta3.dot(W2.T)*(1-np.power(a1,2))dW1=np.dot(X.T,delta2)db1=np.sum(delta2,axis=0)#Addregularizationterms(b1andb2don'tthaveregularizationterms)dW2+=Config.reg_lambda*W2dW1+=Config.reg_lambda*W1#GradientdescentparameterupdateW1+=-Config.epsilon*dW1b1+=-Config.epsilon*db1W2+=-Config.epsilon*dW2b2+=-Config.epsilon*db2#Assignnewparameterstothemodelmodel={'W1':W1,'b1':b1,'W2':W2,'b2':b2}#Optionallyprinttheloss.#Thisisexpensivebecauseitusesthewholedataset,sowedon’twanttodoittoooften.ifprint_lossandi%1000==0:print("Lossafteriteration%i:%f"%(i,calculate_loss(model,X,y)))returnmodel最后是主要方法:defmain():X,y=generate_data()model=build_model(X,y,3,print_loss=True)visualize(X,y,model)每1000次迭代打印输出损失:图3隐藏节点数时层为3现在看看不同的隐藏层大小如何影响结果hidden_??layer_dimensions=[1,2,3,4,5,20,50]fori,nn_hdiminenumerate(hidden_??layer_dimensions):plt.subplot(5,2,i+1)plt.title('HiddenLayersize%d'%nn_hdim)model=build_model(X,y,nn_hdim,20000,print_loss=False)plot_decision_boundary(lambdax:predict(model,x),X,y)plt.show()图4我们可以看到低维隐藏层捕捉到了d的大体趋势阿塔。更高的维度容易过度拟合。他们是在“记忆”数据,而不是拟合整体形状。如果我们在另一个测试集上评估模型,由于更好的泛化能力,具有较小隐藏层大小的模型可能表现更好。我们可以通过更强的正则化来抵消过度拟合,但是为隐藏层选择合适的大小是一种极其“经济”的解决方案。您可以在此GitHub存储库中获取完整代码。nageshsinghc4/Artificial-Neural-Network-from-scratch-python结论在本文中,我们展示了如何使用NumpyPython,从数学上推导出具有1个隐藏层的神经网络,并创建了一个具有1个隐藏层的神经网络。原标题:BuildinganArtificialNeuralNetworkFromScratch:Part2,作者:NageshSinghChauhan