Python pickle文件异常大

3 投票
1 回答
6217 浏览
提问于 2025-04-18 16:13

我制作了一个pickle文件,里面存储了10万个80x80像素的图像中每个像素的灰度值。

还有一个包含10万个整数的数组,这些整数的值都是一位数。

我大致估算了一下这个pickle文件的总大小,

4 byte x 80 x 80 x 100000 = 2.88 GB 

再加上那个整数数组,应该不会太大。

但是生成的pickle文件竟然超过了16GB,这样解压和加载文件就要花好几个小时,最后还会卡住,因为它占用了所有的内存资源。

我是不是在计算上出了什么问题,还是说是我保存文件的方式有问题?

我用以下方式保存了文件。

from PIL import Image
import pickle
import os
import numpy
import time

trainpixels = numpy.empty([80000,6400])
trainlabels = numpy.empty(80000)
validpixels = numpy.empty([10000,6400])
validlabels = numpy.empty(10000)
testpixels = numpy.empty([10408,6400])
testlabels = numpy.empty(10408)

i=0
tr=0
va=0
te=0
for (root, dirs, filenames) in os.walk(indir1):
    print 'hello'
    for f in filenames:
        try:
                im = Image.open(os.path.join(root,f))
                Imv=im.load()
                x,y=im.size
                pixelv = numpy.empty(6400)
                ind=0
                for ii in range(x):
                        for j in range(y):
                                temp=float(Imv[j,ii])
                                temp=float(temp/255.0)
                                pixelv[ind]=temp
                                ind+=1
                if i<40000:
                        trainpixels[tr]=pixelv
                        tr+=1
                elif i<45000:
                        validpixels[va]=pixelv
                        va+=1
                else:
                        testpixels[te]=pixelv
                        te+=1
                print str(i)+'\t'+str(f)
                i+=1
        except IOError:
                continue
trainimage=(trainpixels,trainlabels)
validimage=(validpixels,validlabels)
testimage=(testpixels,testlabels)

output=open('data.pkl','wb')

pickle.dump(trainimage,output)
pickle.dump(validimage,output)
pickle.dump(testimage,output)

如果你发现我的计算或代码有什么问题,请告诉我!

1 个回答

2

Python的Pickles并不是一种节省存储空间的方法,因为你存储的是对象,而不仅仅是“数据”。

下面这个测试案例在我的系统上占用了24kb,这只是一个小的、稀疏的numpy数组存储在一个pickle里:

import os
import sys
import numpy
import pickle

testlabels = numpy.empty(1000)
testlabels[0] = 1
testlabels[99] = 0

test_labels_size = sys.getsizeof(testlabels) #80

output = open('/tmp/pickle', 'wb')
test_labels_pickle = pickle.dump(testlabels, output)

print os.path.getsize('/tmp/pickle')

另外,我不太明白你为什么认为Python中的一个数字大小是4kb——非numpy的整数实际上是24字节(可以通过sys.getsizeof(1)查看),而numpy数组的最小大小是80字节(可以通过sys.getsizeof(numpy.array([0], float))查看)。

正如你在回复我评论时所说的,你有理由继续使用Pickle,所以我不会再试图说服你不要存储对象,但要注意存储对象的开销。

作为一个选择:减少你的训练数据的大小/少存储一些对象。

撰写回答