CNN(Convolutional Neural Networks)没有原理只有实现

来源:互联网 发布:python 接口测试框架 编辑:程序博客网 时间:2024/04/28 16:29

零.说明:

       本文的所有代码均可在 DML 找到,欢迎点星星。

        注.CNN的这份代码非常慢,基本上没有实际使用的可能,所以我只是发出来,代表我还是实践过而已

一.引入:

           CNN这个模型实在是有些年份了,最近随着深度学习的兴起又开始焕发青春了,把imagenet测试的准确度提高了非常多,一个是Alex的工作,然后最近好像Zeiler又有突破性的成果,可惜这些我都没看过,主要是imagenet的数据太大了,我根本没有可能跑得动,所以学习的积极性有些打折扣。不说那么多,还是先实现一个最基础的CNN再说吧:


二.实现:

         好吧,基本是根据DeepLearnToolbox的结构按照 Notes on Convolutional Neural Networks 来写的,大家可以先看这里的代码讲解:【面向代码】学习 Deep Learning(三)Convolution Neural Network(CNN)

         本来是想根据Notes那篇文章来写的,只是最后发现如果给subsampling层加上sigmoid之后整个结构就不收敛了~~~,我用numeric_grad_check检测发现梯度计算也是对的,不明所以~~~这份代码我也上传了(old),不过下面的代码最后就只能改成稍简化版的,貌似通常情况下CNN的pooling(subsampling)层也是没有sigmoid的,先这样吧,这个东西理解起来简单还是写了我两个下午……伤……

      代码: DML/CNN/cnn.py

         

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. from __future__ import division  
  2. import numpy as np  
  3. import scipy as sp  
  4. from scipy.signal import convolve as conv  
  5. from dml.tool import sigmoid,expand,showimage  
  6. from numpy import rot90  
  7. ''''' 
  8.     this algorithm have refered to the DeepLearnToolBox(https://github.com/rasmusbergpalm/DeepLearnToolbox) 
  9.     also:[1]:"Notes on Convolutional Neural Networks" Jake Bouvrie 2006 - How to implement CNNs 
  10.     I want to implement as [1] described,where the subsampling layer have sigmoid function 
  11.      but finally it does not converge,but I can pass the gradcheck!! 
  12.      (this version is dml/CNN/cnn.py.old ,if you can figure out what is wrong in the code,PLEASE LET ME KNOW) 
  13.     at last I changed code back to simple version,delete the sigmoid in 's' layer   
  14.     ps:this code in python is too slow!don't use it do anything except reading. 
  15. '''  
  16. class LayerC:  
  17.     def __init__(self,types='i',out=0,scale=0,kernelsize=0):  
  18.         self.types=types  
  19.         self.a=None  
  20.         self.b=None  
  21.         self.d=None  
  22.         if (types=='i'):  
  23.             pass  
  24.         elif (types=='c'):  
  25.             self.out=out  
  26.             self.kernelsize=kernelsize  
  27.             self.k=None  
  28.         elif (types=='s'):  
  29.             self.scale=scale  
  30.             self.Beta={}  
  31.             self.dBeta={}  
  32.   
  33. class CNNC:  
  34.     def __init__(self,X,y,layers,opts):  
  35.         self.X=np.array(X)  
  36.         self.y=np.array(y)  
  37.         self.layers=layers  
  38.         self.opts=opts  
  39.         inputmap = 1  
  40.         mapsize = np.array(self.X[0].shape)  
  41.           
  42.         for i in range(len(self.layers)):  
  43.             if self.layers[i].types=='s':  
  44.                 mapsize = mapsize / self.layers[i].scale  
  45.                 assert np.sum(np.floor(mapsize)== mapsize)==mapsize.size  
  46.                 self.layers[i].b={}  
  47.                 self.layers[i].db={}  
  48.                 for j in range(inputmap):  
  49.                     self.layers[i].b.setdefault(j,0)  
  50.                     self.layers[i].db.setdefault(j,0)  
  51.                     self.layers[i].Beta.setdefault(j,1)  
  52.                     self.layers[i].dBeta.setdefault(j,0.0)  
  53.                 pass  
  54.             if self.layers[i].types=='c':  
  55.                 mapsize = mapsize - self.layers[i].kernelsize + 1  
  56.                 fan_out = self.layers[i].out*self.layers[i].kernelsize**2   
  57.                 self.layers[i].k={}  
  58.                 self.layers[i].dk={}    
  59.                 self.layers[i].b={}  
  60.                 self.layers[i].db={}  
  61.                 for j in range(self.layers[i].out):  
  62.                       
  63.                     fan_in = inputmap*self.layers[i].kernelsize**2  
  64.                     for t in range(inputmap):  
  65.                         self.layers[i].k.setdefault(t,{})  
  66.                         self.layers[i].k[t].setdefault(j)  
  67.                         self.layers[i].k[t][j]=(np.random.rand(self.layers[i].kernelsize,self.layers[i].kernelsize)-\  
  68.                                                 0.5)*2*np.sqrt(6/(fan_out+fan_in))  
  69.                         self.layers[i].dk.setdefault(t,{})  
  70.                         self.layers[i].dk[t].setdefault(j)  
  71.                         self.layers[i].dk[t][j]=np.zeros(self.layers[i].k[t][j].shape)  
  72.                     self.layers[i].b.setdefault(j,0)  
  73.                     self.layers[i].db.setdefault(j,0)     
  74.                 inputmap=self.layers[i].out  
  75.             if self.layers[i].types=='i':  
  76.                 pass  
  77.         fvnum = np.prod(mapsize)*inputmap;   
  78.         onum = self.y.shape[0];  
  79.         self.ffb=np.zeros((onum,1))  
  80.         self.ffW=(np.random.rand(onum, fvnum)-0.5)*2*np.sqrt(6/(onum+fvnum))  
  81.     def cnnff(self,x):  
  82.         #print x  
  83.         self.layers[0].a={}  
  84.         self.layers[0].a.setdefault(0)  
  85.         self.layers[0].a[0]=x.copy()  
  86.         inputmap=1  
  87.         n=len(self.layers)  
  88.           
  89.         for l in range(1,n):  
  90.             if self.layers[l].types=='s':  
  91.                 for j in range(inputmap):  
  92.                   
  93.                     temp=np.ones((self.layers[l].scale,self.layers[l].scale))/(self.layers[l].scale**2)  
  94.                     z=conv(self.layers[l-1].a[j],np.array([temp]), 'valid')  
  95.                     z=np.array(z)[:,::self.layers[l].scale,::self.layers[l].scale]  
  96.   
  97.                     if self.layers[l].a==None:  
  98.                         self.layers[l].a={}  
  99.                     self.layers[l].a.setdefault(j)  
  100.                     self.layers[l].a[j] =z  
  101.                       
  102.   
  103.             if self.layers[l].types=='c':  
  104.                 if self.layers[l].a==None:  
  105.                     self.layers[l].a={}  
  106.                 for j in range(self.layers[l].out): #for each outmaps  
  107.                     z = np.zeros(self.layers[l-1].a[0].shape - np.array([0,self.layers[l].kernelsize-1,self.layers[l].kernelsize-1]))  
  108.                     for i in range(inputmap):       #cumulate from inputmaps  
  109.                         z+=conv(self.layers[l-1].a[i],np.array([self.layers[l].k[i][j]]),'valid')             
  110.                     self.layers[l].a.setdefault(j)  
  111.                     self.layers[l].a[j]=sigmoid(z+self.layers[l].b[j])  
  112.                 inputmap = self.layers[l].out  
  113.                   
  114.         self.fv=None  
  115.         for j in range(len(self.layers[n-1].a)):  
  116.             sa=self.layers[n-1].a[j].shape  
  117.             p=self.layers[n-1].a[j].reshape(sa[0],sa[1]*sa[2]).copy()  
  118.             if (self.fv==None):  
  119.                 self.fv=p  
  120.             else:  
  121.                 self.fv=np.concatenate((self.fv,p),axis=1)  
  122.         self.fv=self.fv.transpose()  
  123.         self.o=sigmoid(np.dot(self.ffW,self.fv) + self.ffb)  
  124.   
  125.           
  126.   
  127.     def cnnbp(self,y):  
  128.         n=len(self.layers)  
  129.         self.e=self.o-y  
  130.         self.L=0.5*np.sum(self.e**2)/self.e.shape[1]  
  131.         self.od=self.e*(self.o*(1-self.o))  
  132.           
  133.         self.fvd=np.dot(self.ffW.transpose(),self.od)  
  134.         if self.layers[n-1].types=='c':  
  135.             self.fvd=self.fvd*(self.fv*(1-self.fv))  
  136.         sa=self.layers[n-1].a[0].shape  
  137.         fvnum=sa[1]*sa[2]  
  138.         for j in range(len(self.layers[n-1].a)):  
  139.             if self.layers[n-1].d==None:  
  140.                 self.layers[n-1].d={}  
  141.             self.layers[n-1].d.setdefault(j)  
  142.             self.layers[n-1].d[j]=self.fvd[(j*fvnum):((j+1)*fvnum),:].transpose().reshape(sa[0],sa[1],sa[2])  
  143.   
  144.         for l in range(n-2,-1,-1):  
  145.             if self.layers[l].types=='c':  
  146.                 for j in range(len(self.layers[l].a)):  
  147.                     if self.layers[l].d==None:  
  148.                         self.layers[l].d={}  
  149.                     self.layers[l].d.setdefault(j)  
  150.                     self.layers[l].d[j]=self.layers[l].a[j]*(1-self.layers[l].a[j])*\  
  151.                                         np.kron(self.layers[l+1].d[j],np.ones(( self.layers[l+1].scale,self.layers[l+1].scale))/(self.layers[l+1].scale**2))  
  152.                       
  153.                       
  154.             elif self.layers[l].types=='s':  
  155.                 for j in range(len(self.layers[l].a)):  
  156.                     if self.layers[l].d==None:  
  157.                         self.layers[l].d={}  
  158.                     self.layers[l].d.setdefault(j)  
  159.                     z=np.zeros(self.layers[l].a[0].shape)  
  160.                     for i in range(len(self.layers[l+1].a)):  
  161.                         rotated=np.array([rot90(self.layers[l+1].k[j][i],2)])  
  162.                         z=z+conv(self.layers[l+1].d[i],rotated,'full')  
  163.                     self.layers[l].d[j]=z  
  164.   
  165.         for l in range(1,n):  
  166.             m=self.layers[l].d[0].shape[0]  
  167.             if self.layers[l].types=='c':  
  168.                 for j in range(len(self.layers[l].a)):  
  169.                     for i in range(len(self.layers[l-1].a)):  
  170.                         #self.layers[l].dk[i][j]=rot90(conv(self.layers[l-1].a[i],rot90(self.layers[l].d[j],2),'valid'),2)  
  171.                         self.layers[l].dk[i][j]=self.layers[l].dk[i][j]*0  
  172.                         for t in range(self.layers[l].d[0].shape[0]):  
  173.                             self.layers[l].dk[i][j]+=rot90(conv(self.layers[l-1].a[i][t],rot90(self.layers[l].d[j][t],2),'valid'),2)  
  174.                           
  175.                         self.layers[l].dk[i][j]=self.layers[l].dk[i][j]/m  
  176.                     self.layers[l].db[j]=np.sum(self.layers[l].d[j])/m  
  177.         self.dffW=np.dot(self.od,self.fv.transpose())/self.od.shape[1]  
  178.         self.dffb = np.mean(self.od,1).reshape(self.ffb.shape);  
  179.   
  180.   
  181.     def cnnapplygrads(self,alpha=0.1):  
  182.         n=len(self.layers)  
  183.         for l in range(1,n):  
  184.             if self.layers[l].types=='c':  
  185.                 for j in range(len(self.layers[l].a)):  
  186.                     for i in range(len(self.layers[l-1].a)):  
  187.                         self.layers[l].k[i][j]-=alpha*self.layers[l].dk[i][j]  
  188.                     self.layers[l].b[j]-=alpha*self.layers[l].db[j]  
  189.                 pass  
  190.           
  191.         self.ffW-=alpha*self.dffW  
  192.         self.ffb-=alpha*self.dffb  
  193.   
  194.     def train(self):  
  195.         m=self.X.shape[0]  
  196.         batchsize=self.opts['batchsize']  
  197.         numbatches = m/batchsize  
  198.         print numbatches  
  199.         self.rL = []  
  200.         for i in range(self.opts['numepochs']):  
  201.             print 'the %d -th epoch is running'% (i+1)  
  202.             kk=np.random.permutation(m)  
  203.             for j in range(numbatches):  
  204.                 print 'the %d -th batch is running , totally  %d batchs'% ((j+1),numbatches)  
  205.                 batch_x=self.X[kk[(j)*batchsize:(j+1)*batchsize],:,:].copy()  
  206.                 batch_y=self.y[:,kk[(j)*batchsize:(j+1)*batchsize]].copy()  
  207.                 self.cnnff(batch_x)  
  208.                 self.cnnbp(batch_y)  
  209.                 self.cnnapplygrads(alpha=self.opts['alpha'])  
  210.   
  211.                 if len(self.rL)==0:  
  212.                     self.rL.append(self.L)  
  213.                 else:  
  214.                     p=self.rL[len(self.rL)-1]  
  215.                     self.rL.append(p*0.99+0.1*self.L)  
  216.                 print self.L  
  217.     def gradcheck(self,test_x,test_y):  
  218.         #github上有这部分代码  
  219.   
  220.     def test(self,test_x,test_y):  
  221.         self.cnnff(np.array(test_x))  
  222.         p=self.o.argmax(axis=0)  
  223.         bad= np.sum(p!=np.array(test_y).argmax(axis=0))  
  224.         print p,np.array(test_y).argmax(axis=0)  
  225.         print bad  
  226.         print np.array(test_y).shape[1]  
  227.         er=bad/np.array(test_y).shape[1]  
  228.         print er  
  229.     def pred(self,test_x):  
  230.         self.cnnff(np.array(test_x))  
  231.         p=self.o.argmax(axis=0)  
  232.         return p  

三.测试

    因为python跑这个实在是太慢了,主要原因我觉得是convolution函数(我用的scipy.signal.convolve)比matlab里慢太多了,所以跑MNIST以50为一个patch跑SGD一轮要二三十分钟,所以建议不要使用这份代码,你可以去用DeepLearnToolbox比这都快……

  使用代码来测试:test/CNN_test/test_cnn.py

          

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. layers=[LayerC('i'),  
  2.         LayerC('c',out=6,kernelsize=5),  
  3.         LayerC('s',scale=2),  
  4.         LayerC('c',out=12,kernelsize=5),  
  5.         LayerC('s',scale=2)]  
  6. opts={}  
  7. opts['batchsize']=40  
  8. opts['numepochs']=1  
  9. opts['alpha']=1  
  10.   
  11. a=CNNC(X,groundTruth,layers,opts)  
  12. #a.gradcheck(test_x[1:3,:,:],test_groundTruth[:,1:3])  
  13. a.train()  
  14. a.test(test_x,test_groundTruth)  

  这是一轮的结果,89.99%的准确度,应该还是正常的:  

               

      

0 0
原创粉丝点击