在python中的进程之间共享连续numpy数组
虽然我已经找到了许多类似于我的问题的答案,但我不认为这里已经直接提到了这个问题——我还有几个问题要问。共享连续numpy阵列的动机如下:在python中的进程之间共享连续numpy数组,python,numpy,multiprocessing,shared-memory,caffe,Python,Numpy,Multiprocessing,Shared Memory,Caffe,虽然我已经找到了许多类似于我的问题的答案,但我不认为这里已经直接提到了这个问题——我还有几个问题要问。共享连续numpy阵列的动机如下: 我使用一个在Caffe上运行的卷积神经网络对图像进行回归,得到一系列连续的值标签 这些图像需要特定的预处理和数据扩充 (1)标签的连续性(它们是浮动)和(2)数据扩充的约束意味着我在python中预处理数据,然后使用Caffe中的内存数据层将其作为连续的numpy数组提供 将训练数据加载到内存中相对较慢。我想将其并行化,以便: (1) 我正在编写的pyth
- 我使用一个在Caffe上运行的卷积神经网络对图像进行回归,得到一系列连续的值标签李>
- 这些图像需要特定的预处理和数据扩充
- (1)标签的连续性(它们是浮动)和(2)数据扩充的约束意味着我在python中预处理数据,然后使用Caffe中的内存数据层将其作为连续的numpy数组提供
- 将训练数据加载到内存中相对较慢。我想将其并行化,以便:
import numpy as np
from multiprocessing import Array
contArr = np.ascontiguousarray(np.zeros((n_images, n_channels, img_height, img_width)), dtype=np.float32)
sm_contArr = Array(contArr.ctypes.?, contArr?)
然后用
p.append(Process(target=some_worker_function, args=(data_to_load, sm_contArr)))
p.start()
谢谢
编辑:我知道有许多库在不同的维护状态下具有类似的功能。我更愿意将此限制为纯python和numpy,但如果不可能,我当然愿意使用一个 将numpy的ndarray
环绕多处理的RawArray()
有多种方法可以跨进程共享内存中的numpy阵列。让我们来看看如何使用多处理模块来实现这一点
第一个重要的观察结果是,numpy提供了np.frombuffer()
函数来围绕支持缓冲协议的预先存在的对象(例如bytes()
,bytearray()
,array()
等等)包装一个ndarray接口。这将从只读对象创建只读数组,从可写对象创建可写数组
我们可以将其与多处理提供的共享内存RawArray()。请注意,Array()
不能用于此目的,因为它是一个带有锁的代理对象,并且不会直接公开缓冲区接口。当然,这意味着我们需要自己为numpified数组提供适当的同步
关于ndarray包装的rawArray,有一个复杂的问题:当多处理在进程之间发送这样一个数组时——实际上,它需要在创建数组后将数组发送给两个工作进程——它会对数组进行pickle,然后取消对它们的pickle。不幸的是,这导致它创建了Ndarray的副本,而不是在内存中共享它们
解决方案虽然有点难看,但是保持原始数组的原样,直到它们被转移到工作进程,并且仅在每个工作进程启动后将它们包装在数据数组中
此外,最好是通过多处理.Queue
直接与数组通信,无论是普通的RawArray还是ndarray包装的数组,但这也不起作用。RawArray不能放在这样的队列中,而ndarray包装的队列将被pickle和unpickle,因此实际上是复制的
解决方法是将所有预分配阵列的列表发送到工作进程,并通过队列将索引传递到该列表中。这非常类似于传递令牌(索引),任何持有令牌的人都可以在相关数组上操作
主程序的结构可以如下所示:
#/usr/bin/env蟒蛇3
#-*-编码:utf-8-*-
将numpy作为np导入
导入队列
从多处理导入冻结支持中,设置启动方法
从多处理导入事件、进程、队列
从multiprocessing.sharedTypes导入RawArray
def创建共享数组(大小,dtype=np.int32,num=2):
dtype=np.dtype(dtype)
如果“bBhHiIlLfd”中的dtype.isbuiltin和dtype.char:
typecode=dtype.char
其他:
类型代码,大小='B',大小*dtype.itemsize
返回[范围(num)内的uu的RawArray(类型代码,大小)]
def main():
my_dtype=np.32
#125000000(大小)*4(数据类型)*2(数量)~=1 GB内存使用率
数组=创建共享数组(125000000,dtype=my\u dtype)
q_free=队列()
q_used=队列()
bail=Event()
对于范围内的arr_id(len(数组)):
q_free.put(arr_id)#使用分配的数组索引预填充空闲队列
pr1=MyDataLoader(数组、q_空闲、q_使用、bail、,
数据类型=我的数据类型,步骤=1024)
pr2=MyDataProcessor(阵列、无q_、使用q_、bail、,
数据类型=我的数据类型,步骤=1024)
pr1.start()
pr2.start()
pr2.join()
打印(“\n{}joined.”格式(pr2.name))
pr1.join()
打印(“{}joined.”格式(pr1.name))
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
冻结支持()
#在Windows上,只有“生成”可用。
#此外,这还测试了阵列的正确共享,而不存在“欺骗”。
设置启动方法('spawn')
main()
这将准备一个包含两个arra的列表