在Pybrain中保存神经网络测试输出
我用pybrain做了一个有监督的神经网络,它运行得很好。当我用“trainer.testOnData(test_data, verbose=True)”来测试时,我可以看到输出结果(还有错误信息),但我也想把这些结果保存下来,以便以后分析。我在pybrain的文档里找不到相关的内容。有没有人用过pybrain,知道我该怎么做吗?谢谢(希望这不是个显而易见的问题)。
2 个回答
我可能来得有点晚,但我刚刚在寻找数据集测试中网络结果和真实值的方向时发现了你的问题。
简单来说,这些信息并不在里面,但为了进行统计分析和可视化,它应该是有的。那么我们来解决这个问题吧!
不过,我们不需要去修改独立库的代码。因为如果你改了第三方库的东西,可能会导致你的代码变得不稳定(除非你明确说明补丁应用的地方,但这样做真的不太好)。其实有一个很好的、非常符合Python风格的解决方案——面向对象编程的力量。
首先,找到你需要的函数代码:
import inspect
print inspect.getsource(BackpropTrainer.testOnData)
把这段代码复制下来,准备好运用面向对象编程的强大功能来解决你的问题。创建一个自定义类(你可以把它放在一个单独的模块中并导入,或者直接在你的代码中实现),并让它继承自原来的类(在这个例子中是 BackpropTrainer
),然后把你在第一步得到的函数粘贴进去(记得把函数名改成一个不会和现有函数冲突的名字)。
class myOwn_BackpropTrainer(BackpropTrainer):
def myOwn_testOnData(self, dataset=None, verbose=False):
"""Compute the MSE of the module performance on the given dataset.
If no dataset is supplied, the one passed upon Trainer initialization is
used."""
if dataset == None:
dataset = self.ds
dataset.reset()
if verbose:
print '\nTesting on data:'
errors = []
importances = []
ponderatedErrors = []
gt_values = []
for seq in dataset._provideSequences():
self.module.reset()
e, i = dataset._evaluateSequence(self.module.activate, seq, verbose)
importances.append(i)
for input, target in seq:
gt_values.append([self.module.activate(input), target])
errors.append(e)
ponderatedErrors.append(e / i)
if verbose:
print 'All errors:', ponderatedErrors
assert sum(importances) > 0
avgErr = sum(errors) / sum(importances)
if verbose:
print 'Average error:', avgErr
print ('Max error:', max(ponderatedErrors), 'Median error:',
sorted(ponderatedErrors)[len(errors) / 2])
return gt_values, avgErr
注意那些用双空格分开的行,以及我自己声明的 gt_values
变量和 return
语句中的变化。现在我可以简单地用我们的类实例替换 BackpropTrainer
类的实例,并调用我们新的函数:
load_dataset(ds)
trainer = t3_BackpropTrainer(net, ds, learningrate = 0.04, momentum=0.7, weightdecay=0.02, verbose=True)
result, _ = trainer.t3_testOnData(verbose = True)
现在 result
变量存储了一个包含网络结果和真实值的数组,可以用来进行可视化或统计收集。
通过这种方式,你可以把所有的自定义内容保留在自己的代码中,而不去动原来的第三方库代码。这样你就可以轻松地与他人分享你的代码,更新库时也不用担心你的补丁会消失,避免了很多麻烦。
我和你遇到了一样的问题,简单回答一下:没有简单的方法可以做到这一点。
不过当然是可以实现的。
修改pybrain的代码
这似乎是最简单的解决办法,这里有BackpropTrainer.testOnData
的源代码。你可以看到,如果verbose
设置为True
,它会打印出所有的错误。
if verbose:
print('All errors:', ponderatedErrors)
assert sum(importances) > 0
avgErr = sum(errors) / sum(importances)
if verbose:
print('Average error:', avgErr)
print(('Max error:', max(ponderatedErrors), 'Median error:',
sorted(ponderatedErrors)[len(errors) / 2]))
return avgErr
我们可以通过把最后一行改成下面的方式,让它返回所有错误和avgErr
:
return avgErr, ponderatedErrors
然后你只需简单地解包结果来获取这些值:
avgErr, allErrors = trainer.testOnData(dataSet, verbose=True)
或者当你不想要所有错误的时候:
avgErr, _ = trainer.testOnData(dataSet, verbose=True)
这就是最简单的解决方案。但并不是每个人都喜欢修改外部库的源代码。
改变标准输出,将其捕获到文件并进行转换
这个过程需要几个步骤,因为testOnData
从来不会返回所有错误,只是打印出来,这意味着你需要把字符串转换成一些有用的东西(我们试试用列表)。
将stdout
改为打印到文件
这很简单:
import sys
sys.stdout = open('./OURFILE', 'w+')
所以现在当我们运行testOnData
时,输出会保存在文件中。
处理字符串
我们对文件的第二行感兴趣,所以我们只需获取它:
our_file = open('./OURFILE', 'r')
our_file.next() # get rid of first line
our_line = our_file.next() # save second line
因为pybrain的写法,我们的行看起来是这样的:
('所有错误:', 这里是错误列表)
现在,我不是正则表达式的高手,所以我只会数数列表开始的位置。
still_string = our_line[16:-1]
这会给我们一个只包含列表的字符串。到这里,你可以使用eval
将字符串转换成正确的列表:
list_of_errors = eval(still_string)
希望这些对你有帮助。