内容:bp神经网络bp网络原理及实例主要思想:解决adaline网络不能线性划分和异或的问题如果将维度的线性不可分问题转化为高维,则为这个问题很可能会变成线性可分问题。主要难点:在adaline网络中,按照梯度下降法调整节点连接权重是比较简单的,只需要将计算期望与样本期望进行比较,计算误差即可。通过误差计算梯度也很简单,但是在bp网络中,因为涉及到多个隐藏层,中间层的误差不好计算,所以没必要可以直接计算局部梯度解:如果按正常梯度下降调整权重,则公式应为$\Delta\omega=\eta*\delta_j(n)*y_j(n)\\\Delta\omega:调整后的权重值:学习率\\y_j(n):神经元j的输出信号\\\delta_j(n):局部梯度$问题的关键是求解输出层的局部梯度$$\delta_j(n)=e_j(n)*\varphi^`(v_j(n))\\e:error\\\varphi:激活函数\\v_j(n):隐藏层中的神经元输出(非输出信号)$$,根据差分链推导规则,可以计算$$\delta_j(n)=\varphi^`(v_j(n))\sum_k\delta_k(n)w_{kj}(n)$$这里需要注意,k=j+1,为j的下一层节点。bp网络在解决调参问题后,可以分为两个阶段:前向阶段,计算样本期望;后向阶段,根据输出层的误差调整各节点的权值。例子现在我们面对一个这样的长网络,简单分析一下网络,三个输入节点,其中一个有偏置,两层三节点隐藏层,每个都有一个偏置和一个输出节点。参数描述权重和各层输入:$$\begin{align*}X=\left[\begin{matrix}x_{0}\\x_{1}\\x_{2}\\\end{matrix}\右]\W^0=\left[\begin{矩阵}w^0_{10}&w^0_{20}\\w^0_{11}&w^0_{21}\\w^0_{21}&w^0_{22}\end{矩阵}\right]\\\W^1=\left[\begin{矩阵}w^1_{10}&w^1_{20}\\w^1_{11}&w^1_{21}\\w^1_{21}&w^1_{22}\end{矩阵}\right]\W^2=\left[\begin{矩阵}w^2_{10}\\w^2_{11}\\w^2_{21}\end{matrix}\right]\\end{align*}$$正向过程$$X^T*W^0=V^0|_{2*1}\quadV^0=\left[Y^0_0,V^0_1,V^0_2\right]^T\quadY^0|_{3*1}=\varphi(V^0)\quadY^0*W^1=V^1|_{2*1}\\$$$$Y^1=\left[Y^1_0,V^1_1,V^1_2\right]^T\quadY^1|_{3*1}=\varphi(V^1)\quadY^1*W^2=V^2|_{1*1}\quadY^2|_{1*1}=\varphi(V^2)$$对于V^0,加上一个偏置Y^0_0,构成紫色层的输入。计算出的样本期望为$Y^2$,是网络和过程输出层的总输出(层前的橙色权重)$$\delta^2|_{1*1}=e*\varphi^`(v^2)\quad\Delta\omega^2|_{3*1}=\eta*\delta^2*y^1(n)\quadw^2=w^2+\Deltaw^2$$第二隐藏层(紫色层)$$\delta^1|_{2*1}=\frac{\varphi^`(v^1)}{_{1*1}}\sum_k\delta^2_k(n)w^2(n)\\=\frac{\varphi^`(v^1)}{_{1*1}}*\left[\begin{matrix}\delta^2*w^2_{01}\\\delta^2*w^2_{02}\end{matrix}\right]\\$$$$\\Delta\omega^1|_{3*1}=\eta*\frac{y^0(n)}{_{3*3}}*\frac{\delta^1}{_{1*2}}^T\quadw^1=w^1+\frac{y^0(n)^T}{_{3*1}}$$因为调整权重变化的公式中不应该包含bias,所以省略了bias的权重输入层(绿色层)$$\delta^0|_{2*1}=\frac{\varphi^`(v^0)}{_{2*1}}\sum_k\delta^1_k(n)w^1(n)\\=\left[\begin{矩阵}\varphi^`(v^0_1)(\delta^1_1*w^1_{11}+\delta^1_2*w^1_{12})\\\varphi^`(v^0)(\delta^1_1*w^1_{21}+\delta^1_2*w^1_{22}\\\end{矩阵}\right]|_{2*1}\\$$$$\\\Delta\omega^0|_{3*1}=\eta*\frac{X}{_{3*1}}*\frac{\delta^0}{_{1*2}}^T\quad~~~~w^1=w^1+\frac{X}{_{3*1}}$$对于一组输入,bp网络编程实现一次调整这个,网络结构和数据类型都是双月数据,三个输入层,我其中偏差为1。第一个隐藏层,即输入层之后的层,有20个节点,第二个隐藏层有10个节点。输出层是工作流:fromgraphvizimportDigraphdot=Digraph(comment='TheRoundTable')dot.node('A',"generateddata")dot.node('B',"参数确定/权重确定")dot.node('C','网络构建/调参')dot.node('D','决策曲面图')dot.edges(["AB","BC","CD"])dot1]()实验步骤导入相关包并生成数据importnumpyasnpimportmatplotlib.pyplotaspltimportpandasaspdimportrandom#数据生成"""最后生成train_data变量存储数据"""defhalfmoon(rad,width,d,n_samp):'''生成半月数据@paramrad:Radius@paramwidth:Width@paramd:Distance@paramn_samp:Quantity'''ifn_samp%2!=0:#确保数量是doublen_samp+=1data=np.zeros((3,n_samp))#生成0矩阵,生成3行n_samp列的矩阵aa=np.random.random((2,int(n_samp/2)))radius=(rad-宽度/2)+宽度*aa[0,:]theta=np.pi*aa[1,:]x=radius*np.cos(theta)y=radius*np.sin(theta)label=np.ones((1,len(x)))#Class1的标签x1=radius*np.cos(-theta)+rad#在x的基础上向右移动rad单位y1=radius*np.sin(-theta)+d#向下移动d个单位基于y的相反数label1=0*np.ones((1,len(x1)))#class2data[0,:]=np.concatenate([x,x1])data[1,:]=np.连接([y,y1])数据[2,:]=np.concatenate([label,label1],axis=1)#合并数据返回datadataNum=1000data=halfmoon(10,5,5,dataNum)pos_data=data[:,0:int(dataNum/2)]neg_data=data[:,int(dataNum/2):dataNum]plt.figure()plt.scatter(pos_data[0,:],pos_data[1,:],c="b",s=10)plt.scatter(neg_data[0,:],neg_data[1,:],c="r",s=10)plt.show()train_data=[]test_data=[]tmp=[]i=0fori在范围内(1000):tmp.append(i)random.shuffle(tmp)fori在范围内(len(tmp)):train_data.append(数据[:,tmp[i]])train_data=np.array(train_data).T确定应该使用的参数包括两个隐藏层的每层节点数、输入层节点数、学习率为每一层生成随机权重#参数确定·inp_num=3#输入层节点数out_num=1#输出层节点数hid_num_1=20#第一个隐藏层有20个节点hid_num_2=10#第二个隐藏层有10个节点w1=0.2*np.random.random((inp_num,hid_num_1))#初始化输入层的权重矩阵w2=0.2*np.random.random((hid_num_1,hid_num_2))#初始化第一个隐藏层的权重矩阵w3=0.2*np.random.random((hid_num_2,out_num))#初始化第二个隐藏层的权重矩阵inp_lrate=0.3#输入层权重学习率hid_lrate=0.3#隐藏层学习权重学习率out_lrate=0.3#输出层Learningratea=1#sigmoid函数参数激活函数和误差函数的定义defget_act(a,x):#激活函数act_vec=[]foriinx:act_vec.append((1/(1+math.exp(-1*a*i))))act_vec=np.array(act_vec)returnact_vecdefget_err(e):#错误函数return0.5*np.dot(e,e)learningprocessimportmath'''循环使用生成的1000个节点直到误差函数小于设定的阈值'''err_store=[]have=Truewhile(have):e_store=[]forcountinrange(0,1000):t_label=np.zeros(out_num)#输出结果存储#正向处理tmp=[]tmp.append(train_data[0][count])tmp.append(train_data[1][count])tmp.append(1)#三个输入hid_value_1=np.dot(np.array(tmp),w1)#hid_value_1=v1hid_act_1=get_act(a,hid_value_1)#hid_act_1=y1hid_value_2=np.dot(hid_act_1,w2)#hid_value_2=v2hid_act_2=get_act(a,hid_value_2)#hid_act_2=y2hid_value_3=np.dot(hid_act_2,w3)#输出层的输出值tmp_1=[]tmp_1.append(hid_value_3)out_act=get_act(a,tmp_1)#输出层激活函数值/最终计算结果#反向处理e=train_data[2][count]-out_act#误差计算e_store.append(get_err(e))#存储误差函数out_delta=a*e*out_act*(1-out_act)#输出层误差梯度hid_delta_2=a*hid_act_2*\(1-hid_act_2)*np.dot(w3,out_delta)#第二个隐藏层误差梯度hid_delta_1=a*hid_act_1*\(1-hid_act_1)*np.dot(w2,hid_delta_2)#第一个隐藏层的误差梯度foriinrange(0,out_num):w3[:,i]+=out_lrate*out_delta*hid_act_2foriinrange(0,hid_num_2):w2[:,i]+=hid_lrate*hid_delta_2[i]*hid_act_1foriinrange(0,hid_num_1):w1[:,i]+=inp_lrate*hid_delta_1[i]*np.array(tmp)err_sum=0foritemine_store:err_sum+=itemerr_store.append(err_sum)if(err_sum<0.1):#0.1是设定的误差阈值have=Falseerrorsurfacedrawingx=[]foriteminrange(len(err_store)):x.append(item)plt.figure()plt.scatter(x,err_store)
