【问题标题】:Does ndarray tobytes() create a copy of raw data?ndarray tobytes() 是否创建原始数据的副本?
【发布时间】:2022-01-15 14:44:00
【问题描述】:

我写了一些代码

batch = np.ones([4, 3, 224, 224], dtype="float32")
import time
s = time.time()
batch_bytes = batch.tobytes()
e = time.time()
print(f"{(e-s)*1e3} ms")

这给出了2.2954940795898438 ms的输出

看起来成本不小,我猜这个方法是复制数据字节?

以前以为数据在内存中是以字节为单位存储的,所以有办法直接获取?

那么是否有可能更有效地获取字节?

【问题讨论】:

  • 你希望用这些字节做什么?
  • @hpaulj 一种情况是我们将通过套接字将这些字节(用于序列化)发送到其他机器,我们只需要读取字节而无需再操作。在这种情况下,我们希望在没有复制的情况下有效地获得它。
  • 可能会查找memoryview
  • memoryview 提供像bytes_array[x:y] 这样的对象的内部访问,这意味着我们仍然需要首先获取bytes?...除非我们可以从memoryview(ndarray_object) 获取字节,否则@ 987654329@是否支持memoryview的缓冲协议?
  • 试试data 属性,它是memoryviewstackoverflow.com/questions/69544408/…。我没有使用过memoryview,但已经看到了一些关于它的内容。

标签: numpy numpy-ndarray


【解决方案1】:

是的,它会创建一个副本,因为bytes 类型必须拥有其原始数据的所有权(即,副本是强制性的)。但是,您可以使用以下方法创建一个 视图 Numpy 数组,而无需任何副本:

batch_bytes = batch.reshape(-1).view(np.uint8)

请注意,如果不同,则生成的类型(一维 Numpy 数组)。

【讨论】:

  • 关于viewid() 的精彩解释。 BTW 第二个问题呢?那么数据是以字节存储在内存中的吗(例如我想通过tobytes序列化数组)?也许我把byte 类型和内存字节的概念混在一起了?
  • 如果您特别想要bytes,那么答案中所述的副本是强制性的。在我的机器上,副本在 L3 缓存中成功达到 66 GiB/s,这对于 sequential python 函数非常有用。所以,不,我认为这不可能比batch.tobytes() 更有效地获得bytes 类型的对象。话虽如此,您可能实际上并不需要这个 bytes 对象来了解您接下来要做什么。
【解决方案2】:

是的,ndarray.tobytes() 创建数据的副本并将其存储在计算机内存中的不同位置。这也在 NumPy 的文档 https://numpy.org/doc/stable/reference/generated/numpy.ndarray.tobytes.html

中有所描述

您可以通过打印对象的内存地址轻松地对此进行测试。

import numpy as np
import time

batch = np.ones([4, 3, 224, 224], dtype="float32")
s = time.time()
batch_bytes = batch.tobytes()
e = time.time()
print(f"{(e-s)*1e3} ms")

print(f"Batch object address:       {hex(id(batch))}")
print(f"batch_bytes object address: {hex(id(batch_bytes))}")

给出以下输出:

Batch object address:       0x7f16beab0990
batch_bytes object address: 0x7f16be491010

【讨论】:

  • 具有不同的对象ID是正常的,因为它们属于不同的类型。这并不能证明对象是否在内部引用/共享同一缓冲区(尽管实际上已完成副本)。事实上,两个 Numpy 数组可以引用相同的内存缓冲区,但具有不同的对象 ID。事实上,这在使用 reshape 函数或 Numpy 视图时非常常见。
【解决方案3】:

这里发布了一个相同的问题:Numpy array: get the raw bytes without copying

要从array:ndarray 获取字节,使用array.data 将获得字节的内存视图(引用)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-25
    • 2012-07-02
    • 1970-01-01
    • 2020-08-06
    相关资源
    最近更新 更多