生活随笔
收集整理的這篇文章主要介紹了
CNN(Convolutional Neural Networks)没有原理只有实现
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
零.說明:
? ? ? ?本文的所有代碼均可在?DML?找到,歡迎點星星。
? ? ? ? 注.CNN的這份代碼非常慢,基本上沒有實際使用的可能,所以我只是發(fā)出來,代表我還是實踐過而已
一.引入:
? ? ? ? ? ?CNN這個模型實在是有些年份了,最近隨著深度學(xué)習(xí)的興起又開始煥發(fā)青春了,把imagenet測試的準(zhǔn)確度提高了非常多,一個是Alex的工作,然后最近好像Zeiler又有突破性的成果,可惜這些我都沒看過,主要是imagenet的數(shù)據(jù)太大了,我根本沒有可能跑得動,所以學(xué)習(xí)的積極性有些打折扣。不說那么多,還是先實現(xiàn)一個最基礎(chǔ)的CNN再說吧:
二.實現(xiàn):
? ? ? ? ?好吧,基本是根據(jù)DeepLearnToolbox的結(jié)構(gòu)按照?Notes on Convolutional Neural Networks?來寫的,大家可以先看這里的代碼講解:【面向代碼】學(xué)習(xí) Deep Learning(三)Convolution Neural Network(CNN)
? ? ? ? ?本來是想根據(jù)Notes那篇文章來寫的,只是最后發(fā)現(xiàn)如果給subsampling層加上sigmoid之后整個結(jié)構(gòu)就不收斂了~~~,我用numeric_grad_check檢測發(fā)現(xiàn)梯度計算也是對的,不明所以~~~這份代碼我也上傳了(old),不過下面的代碼最后就只能改成稍簡化版的,貌似通常情況下CNN的pooling(subsampling)層也是沒有sigmoid的,先這樣吧,這個東西理解起來簡單還是寫了我兩個下午……傷……
? ? ? 代碼:?DML/CNN/cnn.py
? ? ? ? ?
[python]?view plaincopy
from?__future__?import?division?? import?numpy?as?np?? import?scipy?as?sp?? from?scipy.signal?import?convolve?as?conv?? from?dml.tool?import?sigmoid,expand,showimage?? from?numpy?import?rot90?? ''? ? ? ? ? ? ? ? ?? class?LayerC:?? ????def?__init__(self,types='i',out=0,scale=0,kernelsize=0):?? ????????self.types=types?? ????????self.a=None?? ????????self.b=None?? ????????self.d=None?? ????????if?(types=='i'):?? ????????????pass?? ????????elif?(types=='c'):?? ????????????self.out=out?? ????????????self.kernelsize=kernelsize?? ????????????self.k=None?? ????????elif?(types=='s'):?? ????????????self.scale=scale?? ????????????self.Beta={}?? ????????????self.dBeta={}?? ?? class?CNNC:?? ????def?__init__(self,X,y,layers,opts):?? ????????self.X=np.array(X)?? ????????self.y=np.array(y)?? ????????self.layers=layers?? ????????self.opts=opts?? ????????inputmap?=?1?? ????????mapsize?=?np.array(self.X[0].shape)?? ?????????? ????????for?i?in?range(len(self.layers)):?? ????????????if?self.layers[i].types=='s':?? ????????????????mapsize?=?mapsize?/?self.layers[i].scale?? ????????????????assert?np.sum(np.floor(mapsize)==?mapsize)==mapsize.size?? ????????????????self.layers[i].b={}?? ????????????????self.layers[i].db={}?? ????????????????for?j?in?range(inputmap):?? ????????????????????self.layers[i].b.setdefault(j,0)?? ????????????????????self.layers[i].db.setdefault(j,0)?? ????????????????????self.layers[i].Beta.setdefault(j,1)?? ????????????????????self.layers[i].dBeta.setdefault(j,0.0)?? ????????????????pass?? ????????????if?self.layers[i].types=='c':?? ????????????????mapsize?=?mapsize?-?self.layers[i].kernelsize?+?1?? ????????????????fan_out?=?self.layers[i].out*self.layers[i].kernelsize**2??? ????????????????self.layers[i].k={}?? ????????????????self.layers[i].dk={}???? ????????????????self.layers[i].b={}?? ????????????????self.layers[i].db={}?? ????????????????for?j?in?range(self.layers[i].out):?? ?????????????????????? ????????????????????fan_in?=?inputmap*self.layers[i].kernelsize**2?? ????????????????????for?t?in?range(inputmap):?? ????????????????????????self.layers[i].k.setdefault(t,{})?? ????????????????????????self.layers[i].k[t].setdefault(j)?? ????????????????????????self.layers[i].k[t][j]=(np.random.rand(self.layers[i].kernelsize,self.layers[i].kernelsize)-\?? ????????????????????????????????????????????????0.5)*2*np.sqrt(6/(fan_out+fan_in))?? ????????????????????????self.layers[i].dk.setdefault(t,{})?? ????????????????????????self.layers[i].dk[t].setdefault(j)?? ????????????????????????self.layers[i].dk[t][j]=np.zeros(self.layers[i].k[t][j].shape)?? ????????????????????self.layers[i].b.setdefault(j,0)?? ????????????????????self.layers[i].db.setdefault(j,0)????? ????????????????inputmap=self.layers[i].out?? ????????????if?self.layers[i].types=='i':?? ????????????????pass?? ????????fvnum?=?np.prod(mapsize)*inputmap;??? ????????onum?=?self.y.shape[0];?? ????????self.ffb=np.zeros((onum,1))?? ????????self.ffW=(np.random.rand(onum,?fvnum)-0.5)*2*np.sqrt(6/(onum+fvnum))?? ????def?cnnff(self,x):?? ?????????? ????????self.layers[0].a={}?? ????????self.layers[0].a.setdefault(0)?? ????????self.layers[0].a[0]=x.copy()?? ????????inputmap=1?? ????????n=len(self.layers)?? ?????????? ????????for?l?in?range(1,n):?? ????????????if?self.layers[l].types=='s':?? ????????????????for?j?in?range(inputmap):?? ?????????????????? ????????????????????temp=np.ones((self.layers[l].scale,self.layers[l].scale))/(self.layers[l].scale**2)?? ????????????????????z=conv(self.layers[l-1].a[j],np.array([temp]),?'valid')?? ????????????????????z=np.array(z)[:,::self.layers[l].scale,::self.layers[l].scale]?? ?? ????????????????????if?self.layers[l].a==None:?? ????????????????????????self.layers[l].a={}?? ????????????????????self.layers[l].a.setdefault(j)?? ????????????????????self.layers[l].a[j]?=z?? ?????????????????????? ?? ????????????if?self.layers[l].types=='c':?? ????????????????if?self.layers[l].a==None:?? ????????????????????self.layers[l].a={}?? ????????????????for?j?in?range(self.layers[l].out):??? ????????????????????z?=?np.zeros(self.layers[l-1].a[0].shape?-?np.array([0,self.layers[l].kernelsize-1,self.layers[l].kernelsize-1]))?? ????????????????????for?i?in?range(inputmap):????????? ????????????????????????z+=conv(self.layers[l-1].a[i],np.array([self.layers[l].k[i][j]]),'valid')????????????? ????????????????????self.layers[l].a.setdefault(j)?? ????????????????????self.layers[l].a[j]=sigmoid(z+self.layers[l].b[j])?? ????????????????inputmap?=?self.layers[l].out?? ?????????????????? ????????self.fv=None?? ????????for?j?in?range(len(self.layers[n-1].a)):?? ????????????sa=self.layers[n-1].a[j].shape?? ????????????p=self.layers[n-1].a[j].reshape(sa[0],sa[1]*sa[2]).copy()?? ????????????if?(self.fv==None):?? ????????????????self.fv=p?? ????????????else:?? ????????????????self.fv=np.concatenate((self.fv,p),axis=1)?? ????????self.fv=self.fv.transpose()?? ????????self.o=sigmoid(np.dot(self.ffW,self.fv)?+?self.ffb)?? ?? ?????????? ?? ????def?cnnbp(self,y):?? ????????n=len(self.layers)?? ????????self.e=self.o-y?? ????????self.L=0.5*np.sum(self.e**2)/self.e.shape[1]?? ????????self.od=self.e*(self.o*(1-self.o))?? ?????????? ????????self.fvd=np.dot(self.ffW.transpose(),self.od)?? ????????if?self.layers[n-1].types=='c':?? ????????????self.fvd=self.fvd*(self.fv*(1-self.fv))?? ????????sa=self.layers[n-1].a[0].shape?? ????????fvnum=sa[1]*sa[2]?? ????????for?j?in?range(len(self.layers[n-1].a)):?? ????????????if?self.layers[n-1].d==None:?? ????????????????self.layers[n-1].d={}?? ????????????self.layers[n-1].d.setdefault(j)?? ????????????self.layers[n-1].d[j]=self.fvd[(j*fvnum):((j+1)*fvnum),:].transpose().reshape(sa[0],sa[1],sa[2])?? ?? ????????for?l?in?range(n-2,-1,-1):?? ????????????if?self.layers[l].types=='c':?? ????????????????for?j?in?range(len(self.layers[l].a)):?? ????????????????????if?self.layers[l].d==None:?? ????????????????????????self.layers[l].d={}?? ????????????????????self.layers[l].d.setdefault(j)?? ????????????????????self.layers[l].d[j]=self.layers[l].a[j]*(1-self.layers[l].a[j])*\?? ????????????????????????????????????????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))?? ?????????????????????? ?????????????????????? ????????????elif?self.layers[l].types=='s':?? ????????????????for?j?in?range(len(self.layers[l].a)):?? ????????????????????if?self.layers[l].d==None:?? ????????????????????????self.layers[l].d={}?? ????????????????????self.layers[l].d.setdefault(j)?? ????????????????????z=np.zeros(self.layers[l].a[0].shape)?? ????????????????????for?i?in?range(len(self.layers[l+1].a)):?? ????????????????????????rotated=np.array([rot90(self.layers[l+1].k[j][i],2)])?? ????????????????????????z=z+conv(self.layers[l+1].d[i],rotated,'full')?? ????????????????????self.layers[l].d[j]=z?? ?? ????????for?l?in?range(1,n):?? ????????????m=self.layers[l].d[0].shape[0]?? ????????????if?self.layers[l].types=='c':?? ????????????????for?j?in?range(len(self.layers[l].a)):?? ????????????????????for?i?in?range(len(self.layers[l-1].a)):?? ?????????????????????????? ????????????????????????self.layers[l].dk[i][j]=self.layers[l].dk[i][j]*0?? ????????????????????????for?t?in?range(self.layers[l].d[0].shape[0]):?? ????????????????????????????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)?? ?????????????????????????? ????????????????????????self.layers[l].dk[i][j]=self.layers[l].dk[i][j]/m?? ????????????????????self.layers[l].db[j]=np.sum(self.layers[l].d[j])/m?? ????????self.dffW=np.dot(self.od,self.fv.transpose())/self.od.shape[1]?? ????????self.dffb?=?np.mean(self.od,1).reshape(self.ffb.shape);?? ?? ?? ????def?cnnapplygrads(self,alpha=0.1):?? ????????n=len(self.layers)?? ????????for?l?in?range(1,n):?? ????????????if?self.layers[l].types=='c':?? ????????????????for?j?in?range(len(self.layers[l].a)):?? ????????????????????for?i?in?range(len(self.layers[l-1].a)):?? ????????????????????????self.layers[l].k[i][j]-=alpha*self.layers[l].dk[i][j]?? ????????????????????self.layers[l].b[j]-=alpha*self.layers[l].db[j]?? ????????????????pass?? ?????????? ????????self.ffW-=alpha*self.dffW?? ????????self.ffb-=alpha*self.dffb?? ?? ????def?train(self):?? ????????m=self.X.shape[0]?? ????????batchsize=self.opts['batchsize']?? ????????numbatches?=?m/batchsize?? ????????print?numbatches?? ????????self.rL?=?[]?? ????????for?i?in?range(self.opts['numepochs']):?? ????????????print?'the?%d?-th?epoch?is?running'%?(i+1)?? ????????????kk=np.random.permutation(m)?? ????????????for?j?in?range(numbatches):?? ????????????????print?'the?%d?-th?batch?is?running?,?totally??%d?batchs'%?((j+1),numbatches)?? ????????????????batch_x=self.X[kk[(j)*batchsize:(j+1)*batchsize],:,:].copy()?? ????????????????batch_y=self.y[:,kk[(j)*batchsize:(j+1)*batchsize]].copy()?? ????????????????self.cnnff(batch_x)?? ????????????????self.cnnbp(batch_y)?? ????????????????self.cnnapplygrads(alpha=self.opts['alpha'])?? ?? ????????????????if?len(self.rL)==0:?? ????????????????????self.rL.append(self.L)?? ????????????????else:?? ????????????????????p=self.rL[len(self.rL)-1]?? ????????????????????self.rL.append(p*0.99+0.1*self.L)?? ????????????????print?self.L?? ????def?gradcheck(self,test_x,test_y):?? ?????????? ?? ????def?test(self,test_x,test_y):?? ????????self.cnnff(np.array(test_x))?? ????????p=self.o.argmax(axis=0)?? ????????bad=?np.sum(p!=np.array(test_y).argmax(axis=0))?? ????????print?p,np.array(test_y).argmax(axis=0)?? ????????print?bad?? ????????print?np.array(test_y).shape[1]?? ????????er=bad/np.array(test_y).shape[1]?? ????????print?er?? ????def?pred(self,test_x):?? ????????self.cnnff(np.array(test_x))?? ????????p=self.o.argmax(axis=0)?? ????????return?p??
三.測試
? ? 因為python跑這個實在是太慢了,主要原因我覺得是convolution函數(shù)(我用的scipy.signal.convolve)比matlab里慢太多了,所以跑MNIST以50為一個patch跑SGD一輪要二三十分鐘,所以建議不要使用這份代碼,你可以去用DeepLearnToolbox比這都快……
? 使用代碼來測試:test/CNN_test/test_cnn.py
? ? ? ? ??
[python]?view plaincopy
layers=[LayerC('i'),?? ????????LayerC('c',out=6,kernelsize=5),?? ????????LayerC('s',scale=2),?? ????????LayerC('c',out=12,kernelsize=5),?? ????????LayerC('s',scale=2)]?? opts={}?? opts['batchsize']=40?? opts['numepochs']=1?? opts['alpha']=1?? ?? a=CNNC(X,groundTruth,layers,opts)?? ?? a.train()?? a.test(test_x,test_groundTruth)??
? 這是一輪的結(jié)果,89.99%的準(zhǔn)確度,應(yīng)該還是正常的: ?
? ? ? ? ? ? ? ?
? ? ??
總結(jié)
以上是生活随笔為你收集整理的CNN(Convolutional Neural Networks)没有原理只有实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。