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

60行代码手工实现深度神经网络

时间:2023-03-11 21:49:08 科技观察

01准备数据集使用的数据集是sklearn中的乳腺癌数据集,30维特征,569个样本。训练前MinMax标准化缩放到[0,1]区间。按照75/25的比例,分为训练集和验证集。#获取数据集importnumpyasnpimportpandasapdfromsklearnimportdatasetsfromsklearnimportpreprocessingfromsklearn.model_selectionimporttrain_test_splitbreast=datasets.load_breast_cancer()scaler=preprocessing.MinMaxScaler()data=scaler.fit_transform(breast['data'])target=breast['target']X_train_train,X_test,y(data,target)02模型结构图03正向和反向传播公式04NN实现代码importnumpyasnpimportpandasaspd#定义激活函数ReLu=lambdaz:np.maximum(0.0,z)d_ReLu=lambdaz:np.where(z<0,0,1)LeakyReLu=lambdaz:np.maximum(0.01*z,z)d_LeakyReLu=lambdaz:np.where(z<0,0.01,1)Sigmoid=lambdaz:1/(1+np.exp(-z))d_Sigmoid=lambdaz:Sigmoid(z)*(1-Sigmoid(z))#d_Sigmoid=a(1-a)Tanh=np.tanhd_Tanh=lambdaz:1-Tanh(z)**2#d_Tanh=1-a**2classNNClassifier(object):def__init__(self,n=[np.nan,5,5,1],alpha=0.1,ITERNUM=50000,gfunc='ReLu'):self.n=n#每层节点数self.gfunc=gfunc#隐藏层激活函数self.alpha,self.ITERNUM=alpha,ITERNUMself.dfJ=pd.DataFrame(data=np.zeros((ITERNUM,1)),columns=['J'])self.W,self.b=np.nan,np.nan#确定激活函数s每层elf.g=[eval(self.gfunc)foriinrange(len(n))];self.g[-1]=Sigmoid;self.g[0]=np.nan#确定隐藏层激活函数的导数自己。d_gfunc=eval('d_'+self.gfunc)deffit(self,X_train,y_train):X,Y=X_train.T,y_train.reshape(1,-1)m=X.shape[1]#样本数n=self.n;n[0]=X.shape[0]#每层节点数#节点值及参数初始化A=[np.zeros((ni,m))forniinn];A[0]=X#初始化各层节点的输出值Z=[np.zeros((ni,m))forniinn];Z[0]=np.nan#初始化各层节点的中间值W=[np.nan]+[np.随机。randn(n[i],n[i-1])*0.01foriinrange(1,len(n))]#每一层的系数参数b=[np.zeros((ni,1))forniinn];b[0]=np.nan#nBias各层参数#导数初始化dA=[np.zeros(Ai.shape)forAiinA]dZ=[np.zeros(Ai.shape)forAiinA]dW=[np.zeros(Wi.shape)ifisinstance(Wi,np.ndarray)elsenp.nanforWiinW]db=[np.zeros(bi.shape)ifisinstance(bi,np.ndarray)elsenp.nanforbiinb]forkinrange(self.ITERNUM):#---------正向传播------------foriinrange(1,len(n)):Z[i]=np.dot(W[i],A[i-1])+b[i]A[i]=self.g[i](Z[i])J=(1/m)*np.sum(-Y*np.log(A[len(n)-1])-(1-Y)*np.log(1-A[len(n)-1]))self.dfJ.loc[k]['J']=J#--??--------反向传播-------hmax=len(n)-1dA[hmax]=1/m*(-Y/A[hmax]+(1-Y)/(1-A[hmax]))dZ[hmax]=1/m*(A[hmax]-Y)dW[hmax]=np.dot(dZ[hmax],A[hmax-1].T)db[hmax]=np.dot(dZ[hmax],np.ones((m,1)))foriinrange(len(n)-2,0,-1):dA[i]=np.dot(W[i+1].T,dZ[i+1])dZ[i]=dA[i]*self.d_gfunc(Z[i])dW[i]=np.dot(dZ[i],A[i-1].T)db[i]=np.dot(dZ[i],np.ones((m,1)))#------------梯度下降--------foriinrange(1,len(n)):W[i]=W[i]-self.alpha*dW[i]b[i]=b[i]-self.alpha*db[i]#显示进度if(k+1)%1000==0:print('progressrate:{}/{}'.format(k+1,self.ITERNUM),end='\r')self.W,self.b=W,bdefpredict_prob(self,X_test):#--------正向传播------------W,b=self.W,self.bAi=X_test.Tforiinrange(1,len(self.n)):Zi=np.dot(W[i],Ai)+b[i]Ai=self.g[i](Zi)return(Ai.reshape(-1))defpredict(self,X_test):Y_prob=self.predict_prob(X_test)Y_test=Y_prob.copy()Y_test[Y_prob>=0.5]=1Y_test[Y_prob<0.5]=0return(Y_test)05单隐层神经网络设1个隐层,隐层节点数为5,隐藏层使用Sigmoid激活函数#使用Sigmoid激活函数NN=NNClassifier(n=[np.nan,5,1],alpha=0.02,ITERNUM=200000,gfunc='Sigmoid')NN.fit(X_train,y_train)#绘制目标函数迭代曲线%matplotlibinlineNN.dfJ.plot(figsize=(12,8))#测试验证集中的auc分数fromsklearn.metricsimportroc_auc_scoreY_prob=NN.predict_prob(X_test)roc_auc_score(list(y_test),list(Y_prob))隐藏层使用Tanh激活函数。#使用Tanh激活函数NN=NNClassifier(n=[np.nan,5,1],alpha=0.02,ITERNUM=200000,gfunc='Tanh')NN.fit(X_train,y_train)#绘制目标函数迭代曲线%matplotlibinlineNN.dfJ.plot(figsize=(12,8))#测试验证集中的auc分数fromsklearn.metricsimportroc_auc_scoreY_prob=NN.predict_prob(X_test)roc_auc_score(list(y_test),list(Y_prob))隐藏层使用ReLu激活函数。#使用ReLu激活函数NN=NNClassifier(n=[np.nan,5,1],alpha=0.02,ITERNUM=200000,gfunc='ReLu')NN.fit(X_train,y_train)#绘制目标函数迭代curve%matplotlibinlineNN.dfJ.plot(figsize=(12,8))#测试验证集中的auc分数fromsklearn.metricsimportroc_auc_scoreY_prob=NN.predict_prob(X_test)roc_auc_score(list(y_test),list(Y_prob))隐藏层使用LeakyReLu激活函数。#使用LeakyReLu激活函数NN=NNClassifier(n=[np.nan,5,1],alpha=0.02,ITERNUM=200000,gfunc='LeakyReLu')NN.fit(X_train,y_train)#绘制目标函数迭代curve%matplotlibinlineNN.dfJ.plot(figsize=(12,8))#测试验证集中的auc分数fromsklearn.metricsimportroc_auc_scoreY_prob=NN.predict_prob(X_test)roc_auc_score(list(y_test),list(Y_prob))以上实验似乎表明在当前数据集上,隐藏层使用ReLu激活函数是最好的选择,AUC得分最高为0.99958。06双隐层神经网络设置2个隐层,隐层节点数为5,隐层使用ReLu激活函数。#设置两个隐藏层,使用ReLu激活函数NN=NNClassifier(n=[np.nan,5,5,1],alpha=0.02,ITERNUM=200000,gfunc='ReLu')NN.fit(X_train,y_train)#画出目标函数的迭代曲线%matplotlibinlineNN.dfJ.plot(figsize=(12,8))#测试验证集中的auc分数fromsklearn.metricsimportroc_auc_scoreY_prob=NN.predict_prob(X_test)roc_auc_score(list(y_test),list(Y_prob))0.99874的AUC分数低于单隐藏层的最佳分数0.99958,这可能是由于模型的高复杂性。我们尝试将隐藏层节点的数量减少到3,以降低模型的复杂度。#双隐层,隐层节点数为3NN=NNClassifier(n=[np.nan,3,3,1],alpha=0.02,ITERNUM=200000,gfunc='ReLu')NN.fit(X_train,y_train)#绘制目标函数的迭代曲线%matplotlibinlineNN.dfJ.plot(figsize=(12,8))#测试验证集中的auc分数fromsklearn.metricsimportroc_auc_scoreY_prob=NN.predict_prob(X_test)roc_auc_score(list(y_test)),list(Y_prob))AUC分数为0.99979,再次提升。对比sklearn自带的神经网络分类器。#与sklearn中的模型对比fromsklearn.neural_networkimportMLPClassifier#第一隐层神经元数为3,第二隐层神经元数为3MLPClf=MLPClassifier(hidden_??layer_sizes=(3,3),max_iter=200000,activation='relu')MLPClf.fit(X_train,y_train)#绘制目标函数迭代曲线dfJ=pd.DataFrame(data=np.array(MLPClf.loss_curve_),columns=['J'])dfJ.plot(figsize=(12,8))#测试验证集中的auc分数fromsklearn.metricsimportroc_auc_scoreY_prob=MLPClf.predict_proba(X_test)[:,1]roc_auc_score(list(y_test),list(Y_prob))以上实验表明对于当前数据集,选择ReLu激活函数,使用双隐藏层,设置每个隐藏层的节点数为3是一个不错的选择,AUC得分为0.99979。该分数高于使用CV交叉验证进行超参数优化后逻辑回归模型的AUC分数0.99897。