numpy Python酸洗和解酸洗麻木阵列?

3lxsmp7m  于 2022-11-10  发布在  Python
关注(0)|答案(3)|浏览(135)

我有以下两难境地。我正在尝试对表示图像的麻木数组进行筛选,然后再将其取消筛选。
执行此代码:

a1 = np.zeros((1080, 1920, 3), dtype=np.uint8)
print(sys.getsizeof(a1), a1.shape)

a2 = pickle.dumps(a1)
print(sys.getsizeof(a2), type(a2))

a3 = pickle.loads(a2)
print(sys.getsizeof(a3), a3.shape)

生成以下输出:

6220928 (1080, 1920, 3)
6220995 <class 'bytes'>
128 (1080, 1920, 3)

现在,a1大约是6 MB,a2a1的泡菜表示形式,虽然稍长一些,但仍然大致相同。然后我试着解开a2然后我得到..。一些明显不对劲的事情。
a3看起来很好,我可以调用方法,我可以给它的单元格赋值等。
如果我用a1.dumpsnp.loads替换Pickle调用,结果是一样的,因为这两个调用只是调用Pickle。
那么,这种奇怪的尺寸到底是怎么回事?

k97glaaz

k97glaaz1#

sys.getsizeof文档:
以字节为单位返回对象的大小。该对象可以是任何类型的对象。所有内置对象都将返回正确的结果,但这不一定适用于第三方扩展,因为它是特定于实现的。
重点是我的。基本上,不能保证sys.getsizeof会为NumPy对象提供一致或正确的值。

czq61nw1

czq61nw12#

制作阵列和转储。它不一定非得很大。

In [15]: a1 = np.zeros((10,20,30)); a2 = pickle.dumps(a1); a3 = pickle.loads(a2)

nbytes匹配,形状也匹配

In [16]: a1.nbytes, a3.nbytes
Out[16]: (48000, 48000)    
In [17]: a1.shape, a3.shape
Out[17]: ((10, 20, 30), (10, 20, 30))

In [18]: type(a2)
Out[18]: bytes
In [19]: len(a2)
Out[19]: 48154

由于a3getsizeof很小,我怀疑它是一个view的东西。也就是说,getsizeof没有‘看到’它的数据缓冲区。
如果数组有自己的数据,则base将是None。或者它可以是另一个阵列的view。但显然loads通过引用bytes对象构造了这个数组:

In [20]: type(a3.base)
Out[20]: bytes    
In [21]: len(a3.base)
Out[21]: 48000

这看起来像没有某种信息头的a2
无论如何,在检查数组或列表时,getsizeof并不是那么有用。
下面是一个更简单的案例,其中包含一个常见的测试数组:

In [22]: x = np.arange(12).reshape(3,4)
In [23]: sys.getsizeof(x)
Out[23]: 120
In [24]: sys.getsizeof(x.base)
Out[24]: 152
In [25]: x.base
Out[25]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

x实际上是arange创建的数组的view

编辑

我怀疑a3是使用类似以下内容创建的:

a4 = np.ndarray(a1.shape, buffer=a2[154:])
a5=np.frombuffer(a2, dtype='float', offset=154).reshape(a1.shape)

另一个注意事项-pickle允许对象指定它将如何被序列化。对于ndarray,这是使用np.save代码完成的。格式是头缓冲区,后跟数组数据缓冲区的副本。

In [35]: np.save('test.npy',a1)
In [38]: !dir test.npy
 Volume in drive C is Windows
 Volume Serial Number is 4EEB-1BF0

 Directory of C:\Users\paul

10/27/2022  05:43 PM            48,128 test.npy
               1 File(s)         48,128 bytes
bq3bfh9z

bq3bfh9z3#

这是因为a3对象并不拥有ndarray内存,而是将其指向a3.base。因此,sys.getsizeof(A3)不会报告a3.base内存大小。
相反,a1对象确实拥有它的内存(因为a1.base为None,请通过说Help(A1)来检查ndarray的.base的解释)。因此,sys.getsizeof(A1)报告包括整个数组在内的内存大小。

import numpy as np
import sys
import pickle

a1 = np.zeros((1080, 1920, 3), dtype=np.uint8)
print(sys.getsizeof(a1), a1.shape, type(a1))
if a1.base is None: 
    print("a1.base==None, The object a1 owns its memory. Thus the size of a1 is ",sys.getsizeof(a1))

a2 = pickle.dumps(a1)
print(sys.getsizeof(a2), type(a2))

a3 = pickle.loads(a2)
print(sys.getsizeof(a3), a3.shape, type(a3))
if a3.base is not None:
    print("a3.base is not None, The object a3 does not own its memory. Thus the size of a3 is ",sys.getsizeof(a3))

help(a1)

查看更多关于内存使用的讨论here
因此,有时sys.getsizeof()可能不会给您带来直观的结果,这取决于您想要实现什么。这主要取决于您对“对象存储”的定义。

相关问题