首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用pyBrain测试fMRI数据集时,神经网络预测总是相同的。为什么?

使用pyBrain测试fMRI数据集时,神经网络预测总是相同的。为什么?
EN

Stack Overflow用户
提问于 2016-09-17 22:31:55
回答 1查看 129关注 0票数 0

我对fMRI分析非常陌生。我试图通过观察他们的大脑图像来确定一个人正在思考的对象(9个对象中的哪个)。我正在使用https://openfmri.org/dataset/ds000105/上的数据集。因此,我使用神经网络通过输入2D切片的大脑图像来获得9个对象中的1个对象的输出。下面的代码中有关于每个步骤和图像的详细信息。

代码语言:javascript
复制
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 x 1)

因此,我假设9个值中的最高值应该被分配给答案。但当我使用y_testi进行验证时,情况并非如此。此外,对于每个测试样本,我都会获得类似的X_test值。为何会这样呢?

代码语言:javascript
复制
 #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的一些值:

代码语言:javascript
复制
.
.
.

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%。但是,实际的值一直在变化。

代码语言:javascript
复制
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   

这里的输出比较是:

代码语言:javascript
复制
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]

所有的预测都是针对第一项的。我不知道问题出在哪里。总误差似乎在减少,这是一个好兆头:

代码语言:javascript
复制
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
EN

回答 1

Stack Overflow用户

发布于 2016-09-17 23:03:17

我不能确定--因为我以前没有一起使用过所有这些工具,也没有专门在这类项目中工作过--但我会查看文档,确保您的nn是按照您的期望创建的。

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

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

“如果设置了recurrent标志,将创建一个RecurrentNetwork,否则将创建一个FeedForwardNetwork。”,您可以在此处阅读:

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

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

您的意思是创建一个"FeedForward“网络对象吗?

您可以通过循环遍历索引并激活基于FeedForwardNetwork对象实例化的每个"input"字段来进行测试,文档建议将其视为独立于其他输入。这可能就是为什么你每次都会得到如此相似的结果,而你却期待着更好的收敛。

您使用参数model_id=1, subj_id=1,run_ids=[12]初始化dataset ds对象,这表明您只关注一个主题和模型,但在该模型下从该主题“运行”了12个,对吧?

您的代码很可能在语义或语法上没有任何错误,而是PyBrain库中假定和假定的模型、参数和算法造成了普遍的混淆。因此,不要费力地寻找代码“错误”;这绝对是文档不足的库的一个常见问题。

再说一次,我可能是错误的,但根据我使用类似工具和库的经验,大多数情况下,采用极其复杂的过程并将其简化为几十行代码的好处是伴随着大量完全不透明和固定的假设。

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

因为没有明显的代码语法错误--比如意外地循环遍历等同于列表[0,0,0,0,0,0]的范围迭代器;您可以验证这一点,因为您在打印y_test时重用了i索引整数,而nn.activate(X_test[i])的结果是不变的--所以最有可能发生的情况是,您基本上每次都重新开始测试,这就是为什么每次打印输出的nn.activate(...)方法的结果都会得到相同的结果,不仅相似,而且完全相同。

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

同样,您将从PyBrain简化的神经网络、数据训练、启发式、数据读取、采样、统计建模、分类等方面获得好处,所有这些都简化为单行或两行命令。有很多假设正在被提出。这就是文档需要阐明的,当我们使用这样的工具时,我们必须非常非常小心,这不仅仅是一个正确的语法问题,而是一个实际正确的(read: expected)算法、假设等等。

祝好运!

(附注--开源库,尽管缺少文档,也可以让您检查源代码以了解假设和它们实际做的所有事情:https://github.com/pybrain/pybrain )

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39547947

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档