【问题标题】:Numpy inplace dtype conversionNumpy就地dtype转换
【发布时间】:2017-12-25 09:06:32
【问题描述】:

16Gb 机器内存不足错误。我怀疑转换是否真的到位。

import numpy as np
x = np.ones(int(1.5e9), dtype=np.int64)  # 12 Gb
x.astype(np.float64, copy=False)  # gives out of memory error.

如何进行就地内存转换?我想转换数据类型并保留值。例如 1.0f 变成整数 1。

In-place type conversion of a NumPy array

【问题讨论】:

  • 大概可以分部分做。 y = x.view(dtype=np.float64); y[:10000] = x[:10000].astype(np.float64)
  • 您链接到的问题如何不足以解决您的问题?对我来说,这就像一个完全相同的副本。

标签: numpy memory type-conversion


【解决方案1】:

关于copy参数:

默认情况下,astype 总是返回一个新分配的数组。如果这 设置为 false,dtype、order 和 subok 满足要求,而是返回输入数组 一份。

所以这是有条件的。

In [540]: x=np.arange(10)
In [542]: x.dtype
Out[542]: dtype('int32')
In [543]: z=x.astype('float32',copy=False)
In [544]: z
Out[544]: array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.], dtype=float32)
In [545]: x.__array_interface__
Out[545]: 
{'data': (188221848, False),
 'descr': [('', '<i4')],
 'shape': (10,),
 'strides': None,
 'typestr': '<i4',
 'version': 3}
In [546]: z.__array_interface__
Out[546]: 
{'data': (191273640, False),
 'descr': [('', '<f4')],
 'shape': (10,),
 'strides': None,
 'typestr': '<f4',
 'version': 3}

z 有不同的内存位置。


您链接中接受的答案似乎有效

In [549]: z=x.view('float32')
In [550]: z[:]=x
In [551]: z
Out[551]: array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.], dtype=float32)
In [552]: x
Out[552]: 
array([         0, 1065353216, 1073741824, 1077936128, 1082130432,
       1084227584, 1086324736, 1088421888, 1090519040, 1091567616])
In [553]: z
Out[553]: array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.], dtype=float32)
In [555]: x.__array_interface__
Out[555]: 
{'data': (188221848, False),
 'descr': [('', '<i4')],
 'shape': (10,),
 'strides': None,
 'typestr': '<i4',
 'version': 3}
In [556]: z.__array_interface__
Out[556]: 
{'data': (188221848, False),
 'descr': [('', '<f4')],
 'shape': (10,),
 'strides': None,
 'typestr': '<f4',
 'version': 3}

这是因为z 与x 共享内存,但与dtype 不同。当从 x 复制到 z 时,它们将被转换为匹配新的 dtype。内存位置被保留。但是我不能保证没有临时缓冲区。


如果不清楚,将int32 转换为float32 需要更改底层字节。整数的位表示与浮点数不同。

In [594]: np.array(1, 'int32').tobytes()
Out[594]: b'\x01\x00\x00\x00'
In [595]: np.array(1, 'float32').tobytes()
Out[595]: b'\x00\x00\x80?'

【讨论】:

  • float32 和 int32 都使用相同数量的内存。但是 astype 仍然会创建新副本,这不是必需且效率低下...
  • 效率与它有什么关系。每个 4 字节块必须经过相同的转换过程。它是否被写回相同或不同的内存位置不应该对“速度”产生太大影响。
  • 我猜复制比执行操作要慢,因为 cpu 不必读/写额外的内存缓存行。预取应该屏蔽内存延迟。不知道如果没有复制,预取是否会更好。 stackoverflow.com/questions/3928995/how-do-cache-lines-work 复制肯定会降低内存效率。
  • 内存缓存可能对非常大的数组很重要。我只是做了一些计时。对于arange(10000),第二种方法稍微快一些;为arange(1000000) 15x。时间仍在 ns/µs 范围内。
  • z[:]=x 重写所有数据字节(就地)。 z float 是查看它们的正确方法。 x.view('float32') 显示正确的 1.0。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
相关资源
最近更新 更多