使用pyBrain测试fMRI数据集时,神经网络预测始终相同。为什么?

时间:2016-09-17 14:31:55

标签: python neural-network pybrain

我对fMRI分析很新。我试图通过查看他们的脑图像来确定一个人正在考虑哪个对象(9个对象)。我在https://openfmri.org/dataset/ds000105/上使用数据集。因此,我通过输入大脑图像的2D切片来使用神经网络,以将输出作为9个对象中的1个。有关每个步骤的详细信息以及下面代码中的图像。

import os, mvpa2, pyBrain
    import numpy as np
    from os.path import join as opj
    from mvpa2.datasets.sources import OpenFMRIDataset
    from pybrain.datasets import SupervisedDataSet,classification

path = opj(os.getcwd() , 'datasets','ds105')

of = OpenFMRIDataset(path)

#12th run of the 1st subject
ds = of.get_model_bold_dataset(model_id=1, subj_id=1,run_ids=[12])

#Get the unique list of 8 objects (sicissors, ...) and 'None'.
target_list = np.unique(ds.sa.targets).tolist()

#Returns Nibabel Image instance
img = of.get_bold_run_image(subj=1,task=1,run=12)

# Getting the actual image from the proxy image
img_data = img.get_data()

#Get the middle voxelds of the brain samples
mid_brain_slices = [x/2 for x in img_data.shape]

# Each image in the img_data is a 3D image of 40 x 64 x 64 voxels, 
# and there are 121 such samples taken periodically every 2.5 seconds.
# Thus, a single person's brain is scanned for about 300 seconds (121 x 2.5).
# This is a 4D array of 3 dimensions of space and 1 dimension of time, 
# which forms a matrix of (40 x 64 x 64 x 121) 

# I only want to extract the slice of the 2D images brain in it's top view 
# i.e. a series of 2D images 40 x 64
# So, i take the middle slice of the brain, hence compute the middle_brain_slices

DS = classification.ClassificationDataSet(40*64, class_labels=target_list)

# Loop over every brain image
for i in range(0,121):

    #Image of brain at i th time interval
    brain_instance = img_data[:,:,:,i]

    # We will slice the brain to create 2D plots and use those 'pixels'
    # as the features

    slice_0 = img_data[mid_brain_slices[0],:,:,i] #64 x 64
    slice_1 = img_data[:,mid_brain_slices[1],:,i] #40 x 64
    slice_2 = img_data[:,:,mid_brain_slices[2],i] #40 x 64

    #Note : we may actually only need one of these slices (the one with top view)

    X = slice_2 #Possibly top view

    # Reshape X from 40 x 64 to 1D vector 2560 x 1
    X = np.reshape(X,40*64)

    #Get the target at this intance (y)
    y = ds.sa.targets[i]
    y = target_list.index(y)

    DS.appendLinked(X,y)


print DS.calculateStatistics()
print DS.classHist
print DS.nClasses
print DS.getClass(1)

# Generate y as a 9 x 1 matrix with eight 0's and only one 1 (in this training set)
DS._convertToOneOfMany(bounds=[0, 1])

#Split into Train and Test sets
test_data, train_data = DS.splitWithProportion( 0.25 )
#Note : I think splitWithProportion will also internally shuffle the data

#Build neural network
from pybrain.tools.shortcuts import buildNetwork
from pybrain.structure.modules   import SoftmaxLayer
nn = buildNetwork(train_data.indim, 64, train_data.outdim, outclass=SoftmaxLayer)

from pybrain.supervised.trainers import BackpropTrainer
trainer = BackpropTrainer(nn, dataset=train_data, momentum=0.1, learningrate=0.01 , verbose=True, weightdecay=0.01) 
trainer.trainUntilConvergence(maxEpochs = 20)

nn.activate(X_test[i])应该采用2560输入并生成概率输出,对吗?在预测的y向量中(形状9×1)

因此,我假设应该为9个值中的最高值分配答案。但是当我用y_test [i]验证它时,情况并非如此。此外,我为每个测试样本获得了类似的X_test值。为什么会这样?

 #Just splitting the test and trainset 
 X_train = train_data.getField('input')
 y_train = train_data.getField('target')
 X_test = test_data.getField('input')
 y_test = test_data.getField('target')

 #Testing the network
  for i in range(0,len(X_test)):
     print nn.activate(X_test[i])
     print y_test[i]

当我包含上面的代码时,这里有一些X_test的值:

.
.
.

nn.activated =  [ 0.44403205  0.06144328  0.04070154  0.09399672  0.08741378  0.05695479 0.08178353  0.0623408   0.07133351]
y_test [0 1 0 0 0 0 0 0 0]

nn.activated =  [ 0.44403205  0.06144328  0.04070154  0.09399672  0.08741378  0.05695479 0.08178353  0.0623408   0.07133351]
y_test [1 0 0 0 0 0 0 0 0]

nn.activated =  [ 0.44403205  0.06144328  0.04070154  0.09399672  0.08741378  0.05695479 0.08178353  0.0623408   0.07133351]
y_test [0 0 0 0 0 0 1 0 0]
.
.
.

因此,无论样本值如何,测试样本在每种情况下的索引0的概率为44.4%。实际值虽然不断变化。

print 'print predictions: ' , trainer.testOnClassData (dataset=test_data)

x = []
for item in y_test:
    x.extend(np.where(item == 1)[0])
print 'print actual: ' , x   

这里,输出比较是:

print predictions:  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
print actual:  [7, 0, 4, 8, 2, 0, 2, 1, 0, 6, 1, 4]

所有预测都是第一项。我不知道问题是什么。总错误似乎在减少,这是一个好兆头:

Total error:  0.0598287764931
Total error:  0.0512272330797
Total error:  0.0503835076374
Total error:  0.0486402801867
Total error:  0.0498354140541
Total error:  0.0495447833038
Total error:  0.0494208449895
Total error:  0.0491162599037
Total error:  0.0486775862084
Total error:  0.0486638648161
Total error:  0.0491337891419
Total error:  0.0486965691406
Total error:  0.0490016912735
Total error:  0.0489939195858
Total error:  0.0483910986235
Total error:  0.0487459940103
Total error:  0.0485516142106
Total error:  0.0477407360102
Total error:  0.0490661144891
Total error:  0.0483103097669
Total error:  0.0487965594586

1 个答案:

答案 0 :(得分:1)

我无法确定 - 因为我以前没有使用过所有这些工具,或者专门在这类项目中工作过 - 但我会查看文档并确保你的{{1}正如你所期望的那样创建。

具体来说,它在这里提到:

http://pybrain.org/docs/api/tools.html?highlight=buildnetwork#pybrain.tools.shortcuts.buildNetwork

“如果设置了重复标记,将创建RecurrentNetwork,否则为FeedForwardNetwork。”,您可以在此处阅读:

http://pybrain.org/docs/api/structure/networks.html?highlight=feedforwardnetwork

“FeedForwardNetworks是不适用于顺序数据的网络。每个输入都被视为独立于任何先前或后续输入。”。

您的意思是创建“FeedForward”网络对象吗?

您正在测试循环索引并激活基于nn对象实例化的每个"input"字段,文档建议将其视为独立于其他输入。这可能就是为什么每当你期望更好的收敛时,你会得到如此类似的结果。

使用参数FeedForwardNetwork初始化数据集ds对象,建议您只查看单个主题和模型,但在该模型下从该主题进行12次“运行”,对吧?

很可能你的代码没有任何语义或语法错误,但是PyBrain库假定和假设的模型,参数和算法存在一般性的混淆。所以不要撕掉你的头发寻找代码“错误”;对于文档不足的库来说,这绝对是一个常见的困难。

同样,我可能不在基础上,但根据我对类似工具和库的经验,最常见的是采用极其复杂的过程并将其简化为几十行代码的好处,附带一个TON完全不透明和固定的假设。

我的猜测是,您实际上是在“新”或独立的训练数据上重新运行“新”测试,而没有您认为在之前的代码行中设置的所有实际信息和参数。你是完全正确的,最高值(读:最大概率)是“最有可能”(这正是每个值,一个“可能性”)的答案,特别是如果你的概率数组代表unimodal distribution

因为没有明显的代码语法错误 - 比如意外地在范围迭代器上循环等效于列表model_id=1, subj_id=1,run_ids=[12];您可以验证,因为您在打印[0,0,0,0,0,0]中重复使用i索引整数并且y_test的结果不变 - 那么最有可能发生的是你是基本上每次都重新启动测试,这就是为什么你得到一个相同的结果,而不仅仅是相似但是对于nn.activate(X_test[i])方法的结果的每次打印都是相同的。

这是一个复杂但写得很好且说得很好的问题,但不幸的是,我认为不会有一个简单或明显的解决方案。

同样,您可以获得PyBrain简化神经网络,数据训练,启发式,数据读取,采样,统计建模,分类等等的好处,所有这些都可以简化为单行或双行命令。 的假设,是他们的TONS。这就是需要所需的文档,并且当我们使用这些工具时我们必须非常小心,这不仅仅是一个正确的语法问题,而是一个实际上正确的(读取:预期的)算法,假设和所有。

祝你好运!

(PS - 尽管缺乏文档,开源库也可以帮助您检查源代码以查看[假设和所有]他们实际正在做的事情:https://github.com/pybrain/pybrain