1. 程式人生 > >Pybrain學習筆記-4 基於前饋神經網路的分類器

Pybrain學習筆記-4 基於前饋神經網路的分類器

話不多說,直接上程式碼:

5.test_pybrian_5

#!usr/bin/env python
#_*_coding:utf-8_*_
'''
Created on 2017年4月14日
Topic:Classification with Feed-Forward Neural Networks
@author: Stuart斯圖爾特
'''
from pybrain.datasets import ClassificationDataSet    #分類資料專用資料集工具包
from pybrain.utilities import percentError    #以列表和陣列的形式返回誤差的百分比工具包
from pybrain.tools.shortcuts import buildNetwork
from pybrain.supervised.trainers import BackpropTrainer
from pybrain.structure.modules import SoftmaxLayer
#下面是一些圖形介面以及矩陣運算和隨機陣列運算的工具包,可暫時忽略具體應用,後續會講到
from pylab import ion , ioff , figure , draw , contourf , clf , show , hold , plot
from scipy import  diag , arange , meshgrid , where
from numpy.random import multivariate_normal

#建立一個有二維空間點組成的列表
means = [(-1,0),(2,4),(3,1)]
#建立一個由對角矩陣形成的列表
cov = [diag([1,1]), diag([0.5,1.2]), diag([1.5,0.7])]
#ClassificationDataSet:Specialized data set for classification data. Classes are to be numbered from 0 to nb_classes-1.  
#定義資料集:輸入目標是2維,目標的target的維數是1,資料可被分為3類
alldata = ClassificationDataSet(2, 1, nb_classes=3)

for n in xrange(400):   #外層迴圈400次
    for klass in range(3):    #內層迴圈三次
        input = multivariate_normal(means[klass],cov[klass])     #理解成把輸入資料進行正態分佈的處理,得到更好的資料集
        alldata.addSample(input, [klass])    #得到二維輸入資料

#按照3:1的比例劃分測試集和訓練集        
#tstdata, trndata = alldata.splitWithProportion( 0.25 )
#報錯:AttributeError: 'SupervisedDataSet' object has no attribute '_convertToOneOfMany'
#將這條語句改成下面程式碼段:

tstdata_temp, trndata_temp = alldata.splitWithProportion(0.25)  
#定義測試集,輸入維度是2,target是1,有三類,均是2d向量
tstdata = ClassificationDataSet(2, 1, nb_classes=3)  
for n in xrange(0, tstdata_temp.getLength()):  
    tstdata.addSample( tstdata_temp.getSample(n)[0], tstdata_temp.getSample(n)[1] )  
    
#定義訓練集,  輸入維度是2,target是1,有三類,均是2d向量
trndata = ClassificationDataSet(2, 1, nb_classes=3)  
for n in xrange(0, trndata_temp.getLength()):  
    trndata.addSample( trndata_temp.getSample(n)[0], trndata_temp.getSample(n)[1] )  
    
#將target轉化成一維的輸出,注意網路的output有三層,在分類器中我們想得到的結果是某一明確的分類 
#通過convertToOneOfMany()實現target的降維,並把'target'欄位轉存在'class'欄位中
trndata._convertToOneOfMany( )
tstdata._convertToOneOfMany( )

print "Number of training patterns: ", len(trndata)   #Number of training patterns:  900
print "Input and output dimensions: ", trndata.indim, trndata.outdim    #Input and output dimensions:  2 3
print "First sample (input, target, class):"
print trndata['input'][0], trndata['target'][0], trndata['class'][0]    #[ 0.7295122   0.37413538] [0 0 1] [2]

#呼叫buildNetwork建立前饋神經網路,輸入層是2,隱含層是5,輸出層是3
fnn = buildNetwork( trndata.indim, 5, trndata.outdim, outclass=SoftmaxLayer )

#呼叫反向誤差訓練器
trainer = BackpropTrainer( fnn, dataset=trndata, momentum=0.1, verbose=True, weightdecay=0.01)

#這個網路已經可以進行測試了,但由於想做出一個漂亮易懂的分類器,因此下面將自定義資料範圍,用訓練好的網路進行分類並將分類結果視覺化

#下面為了把分類器控制在一個可繪製方格中,因此隨機生成方格內的二維點

#從-3到6建立一維陣列,間隔為0.2,顯然維度是60
#生成矩陣X , Y,矩陣均為60*60的方陣
ticks = arange(-3.,6.,0.2)    
X, Y = meshgrid(ticks, ticks)   

# need column vectors in dataset, not arrays 定義分類資料集並從X Y矩陣中取樣
griddata = ClassificationDataSet(2,1, nb_classes=3)
for i in xrange(X.size):
    griddata.addSample([X.ravel()[i],Y.ravel()[i]], [0])
#同樣要把target對映成一維資料放到class例項中
griddata._convertToOneOfMany() 
for i in range(20):
    trainer.trainEpochs( 1 )    #訓練網路一次,之所以要訓練一次是想得到每次的訓練結果
    trnresult = percentError( trainer.testOnClassData(),trndata['class'] )
    tstresult = percentError( trainer.testOnClassData(dataset=tstdata ), tstdata['class'] )
    #列印每次訓練的錯誤率
    print "epoch: %4d" % trainer.totalepochs, \
          "  train error: %5.2f%%" % trnresult, \
          "  test error: %5.2f%%" % tstresult
    out = fnn.activateOnDataset(griddata)
    #下面是輸出視覺化的分類結果,涉及pylab模組的使用,後續會講到
    out = out.argmax(axis=1)  # the highest output activation gives the class
    out = out.reshape(X.shape)
    figure(1)
    ioff()  # interactive graphics off
    clf()   # clear the plot
    hold(True) # overplot on
    for c in [0,1,2]:
        here, _ = where(tstdata['class']==c)
        plot(tstdata['input'][here,0],tstdata['input'][here,1],'o')
    if out.max()!=out.min():  # safety check against flat field
        contourf(X, Y, out)   # plot the contour
    ion()   # interactive graphics on
    draw()  # update the plot

ioff()
show()
程式碼說明:

      有關程式碼的解釋都已在註釋中給出,下面主要對標記轉化函式_convertToOneOfMany( )報出的AttributeError進行分析與解釋

      在官方的說明書中,訓練集與測試集按照3:1劃分,並將標記轉化為一維輸出,語句是:

tstdata, trndata = alldata.splitWithProportion( 0.25 )tstdata, trndata = alldata.splitWithProportion( 0.25 )
trndata._convertToOneOfMany( )
tstdata._convertToOneOfMany( )