2008年6月3日星期二

Python变量存储

这次毕设虽然题目挺无聊的,但是为了抓住这个机会练习一下包括Python在内的很多东西,我多少还是认真完成的。因为我的毕设用的是“过完备”的特征提取,所以一张图片的特征维数达到了412160之多...这样所有训练图片的特征一次性存在内存里是不可能的,所以我就使用了各种各样的数据存取操作。我现在了解到的Python相比Matlab唯一的一点美中不足就是数据结构不够统一所导致的数据存储没有统一的函数。从最最基本的以ASCII格式存储矩阵的io.save,到man里面很是推崇的cPickle。我这次各种需求的数据都尝试过了,所以小小的总结一段:

1、对于一个或多个数据类型不同且体积较小(比如1000维以内),而且含有Python特有的数据类型比如list,字典等等的变量,统一变成一个字典然后使用cPickle.dump。这样将来load出来数据类型不变,会节约大量的格式转换代码。

2、对于较大的变量,比如我使用的图像特征,双精度1*412160,以及训练时使用的一个核心矩阵,int8整数,375*412160,无论使用ASCII还是cPickle都会速度非常慢,且极其消耗硬盘空间。这时就要考虑是用2进制来存储。我之前一直纠缠于这个问题甚至最后自己写了一个用ASCII读取int8的函数,就是因为我在使用scipy.io.savemat存储int8类的矩阵时,读出来仍然是双精度,那可是375*412160的矩阵啊,我的内存当时就崩了...后来查了一下scipy.io.mio的源代码,原来里面有这样一段:
np_to_mtypes = {
'f8': miDOUBLE,
'c32': miDOUBLE,
'c24': miDOUBLE,
'c16': miDOUBLE,
'f4': miSINGLE,
'c8': miSINGLE,
'i4': miINT32,
'i2': miINT16,
'u2': miUINT16,
'u1': miUINT8,
'S1': miUINT8,
}
这相当于python到matlab数据类型的一个转换码表。我注意到'u1': miUINT8这一段,意识到savemat是可以保留一些数据类型的。
所以应该:
a = ones(5, dtype = 'u1')
scipy.io.savemat('test.mat', {'a':a})
这样load出来就完全没有问题了...只是要注意,uint8是0~255的。
所以之前一直有问题的原因就是python下面的int8在matlab里是不存在的,所以mio会自动转化为双精度来存储。但是我又必须使用int8,因为int8是-128~+127的。不过还好Python的格式转换不会占用多余的内存。
所以,对于较大型的数据矩阵,使用scipy.io.mio,存取速度非常快,有压缩,节约硬盘空间。注意的话,可妥善保存数据类型。

没有评论: