Pybrain学习笔记-4 基于前馈神经网络的分类器

来源:互联网 发布:c语言播放音乐linux 编辑:程序博客网 时间:2024/06/05 02:58

 Pybrain学习笔记-4 基于前馈神经网络的分类器

注:原创博文,转载请注明出处:http://blog.csdn.net/m0_37887016
参考文档:http://www.pybrain.org/docs/index.html

引言:

      通过前面的学习已经清楚了pybrain的基础模块功能,也学会了利用神经网络模型进行一些基本的数据操作,下面让我们正式实践一下,通过分类器深刻理解一下利用神经网络解决分类问题的整体流程。

分类器整体思路分析:

在给出代码前,有必要讲一下使用神经网络构造分类器的整体思路。

      本次神经网络分类器目的,是给出一个二维空间点,我们可以将其读入训练好的神经网络模型,通过模型得到这个二维空间点的所属分类。因此,大致的流程如下:

      先建立一个前馈神经网路,然后再建立满足分类要求的数据集,从数据集中采样出训练集对网络进行训练,使得网络达到所需精度。最后利用测试集进行测试,再实现输出结果的绘制。

注:有关网络的建立、数据集的建立、网络的训练方法可以参考我的前几篇博文。

构建神经网络分类器:

话不多说,直接上代码:

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 buildNetworkfrom pybrain.supervised.trainers import BackpropTrainerfrom pybrain.structure.modules import SoftmaxLayer#下面是一些图形界面以及矩阵运算和随机数组运算的工具包,可暂时忽略具体应用,后续会讲到from pylab import ion , ioff , figure , draw , contourf , clf , show , hold , plotfrom scipy import  diag , arange , meshgrid , wherefrom 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:  900print "Input and output dimensions: ", trndata.indim, trndata.outdim    #Input and output dimensions:  2 3print "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,输出层是3fnn = 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 plotioff()show()
代码说明:

      有关代码的解释都已在注释中给出,下面主要对标记转化函数_convertToOneOfMany( )报出的AttributeError进行分析与解释

      在官方的说明书中,训练集与测试集按照3:1划分,并将标记转化为一维输出,语句是:

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

但是在编译时报错如下:

AttributeError:'SuperviseDataSet' object has no attribute '_convertToOneOfMany'

        按照错误提示,SuperviseDataSet类中不存在_convertToOneOfMany()这个方法。回头看,这很对啊,我之前建立的alldata是ClassificationDataSet类的一个实例,而通过查看源代码,我们使用的_convertToOneOfMany()方法也正好在ClassificationDataSet中,我们已经引好了各种数据集的工具包,引包调用,天经地义,可为什么报出找不到方法这样的错误呢?


找了很长时间的原因才发现问题所在,首先打开spiltWithProportion()方法的源码:

def splitWithProportion(self, proportion = 0.5):        """Produce two new datasets, the first one containing the fraction given        by `proportion` of the samples."""        indicies = random.permutation(len(self))        separator = int(len(self) * proportion)        leftIndicies = indicies[:separator]        rightIndicies = indicies[separator:]        leftDs = SupervisedDataSet(inp=self['input'][leftIndicies].copy(),                                   target=self['target'][leftIndicies].copy())        rightDs = SupervisedDataSet(inp=self['input'][rightIndicies].copy(),                                    target=self['target'][rightIndicies].copy())        return leftDs, rightDs

        有没有发现,spiltWithProportion()方法所返回的参数有两个,即leftDs和rightDs,整个源码函数的作用实际上是按照随机的一个比例,将所处理的数据集分成两个部分,并作为SupervisedDataSet类型的数据返回。因此Python在调用方法的时候实际上是在找SupervisedDataSet中的函数,也就找不到_convertToOneOfMany()了。

      有关于后面的替换代码,是参考了stackoverflow论坛的解决方案,(传送门)。

      好了,最后给出程序跑过一遍后的效果,参考一下:

      控制台打印出了网络在训练20次过程中的细节,用错误分类的比率给出,然后打印出了分类的结果图。




      我们发现分类的结果并不是十分的精确,这与训练数据和训练次数都有一定的关系,若想获得更精确的结果,可以建立更大的数据集,同时扩大训练次数。

      至此,利用神经网络编写的分类器就实现了。

      pybrain的强大之处就在于其具有强大的API来支撑神经网络进行各种数据的处理。从而极大地缩小了代码量,增强了代码的可移植性。然而官方的案例只针对于有监督数据。接下来将考虑将pybrain用于无监督数据集的处理问题,这也是我们学习pybrain的初衷,因为在NLP领域的很多问题都是针对于无监督的文本数据的分析与处理,可见仅在神经网络的路上,我们要走的路还长着呢。

      后续我将从神经网络的具体算法入手,并结合pybrain的源码,进行实验与学习,road still long。

      Ps:程序小猿,个人能力和表达能力有限,如有错误欢迎指正交流。码字不易,转载请注明出处(笔芯)。






1 0
原创粉丝点击