【问题标题】:Neural Network predictions are always the same while testing an fMRI dataset with pyBrain. Why?使用 pyBrain 测试 fMRI 数据集时,神经网络预测始终相同。为什么?
【发布时间】:2017-01-25 15:42:18
【问题描述】:

我对 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 x 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

【问题讨论】:

    标签: python neural-network pybrain


    【解决方案1】:

    我不能确定——因为我之前没有同时使用过所有这些工具,或者专门从事过此类项目——但我会查看文档并确保您的 nn 是按照您的预期创建。

    这里特别提到:

    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 是不适用于顺序数据的网络。每个输入都被视为独立于任何之前或之后的输入。”。

    您的意思是创建一个“前馈”网络对象吗?

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

    您使用参数 model_id=1, subj_id=1,run_ids=[12] 初始化您的数据集 ds 对象,这表明您只查看单个主题和模型,但在该模型下从该主题“运行”了 12 次,对吗?

    您的代码很可能在语义或语法上没有任何错误,但 PyBrain 库的假定和假定模型、参数和算法存在普遍混淆。所以不要为了代码“错误”而抓狂;这绝对是文档不足的库的常见难题。

    再说一次,我可能不太了解,但根据我使用类似工具和库的经验,将极其复杂的过程简化为仅几十行代码的好处通常是大量的完全不透明且固定的假设。

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

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

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

    再次,您将受益于 PyBrain 对神经网络、数据训练、启发式、数据读取、采样、统计建模、分类等的简化,所有这些都简化为单行或两行命令。有个假设正在做出,吨。这就是文档需要说明的内容,当我们使用此类工具时,我们必须非常小心,这不仅仅是语法正确的问题,而是实际正确的(阅读:预期的)算法, 假设等等。

    祝你好运!

    (附注——尽管缺乏文档,开源库也让您受益于检查源代码以了解 [假设和所有] 他们实际在做什么:https://github.com/pybrain/pybrain

    【讨论】:

    • 嗨,TommyP,感谢您的快速回复。我的意图是像你提到的那样创建一个 FeedForwardNetwork。在模型中,我使用 40 x 64 = 2560 个特征。但我只对大约 100 个样本进行了训练,其余的用于测试。我认为我必须增加样本数量,所以我做了大约 1400-ish 。我仍然遇到同样的问题。每次我在 pybrain 中使用一个函数时,我都会参考文档代码。那里没问题。由于没有愚蠢的错误(我认为),我只需要寻找一个好的解决方案。再次感谢您的输入。 :)
    • 是的,对不起,我看不到任何明显的东西,但我遇到过类似的情况,并且被图书馆的假设绊倒了。这是一件很难追踪的事情。我之前通过实际访问源代码并将代码中的函数调用替换为库中的源代码而取得了成功,这样您就可以添加调试打印语句并修改假定的参数等。祝你好运!
    猜你喜欢
    • 1970-01-01
    • 2013-05-12
    • 2014-09-07
    • 1970-01-01
    • 1970-01-01
    • 2017-12-28
    • 2021-01-07
    • 2015-04-15
    • 2015-07-05
    相关资源
    最近更新 更多