java线程安全迭代器_多线程迭代器

自己hack的迭代器总觉得卡,可能是两个处理器之间工作不连贯,batch size高了会使CPU上下起伏,卡顿(看着流水图也心塞),低了GPU的Utilization不高。所以最好的方案应该就是多线程了。

后续评论(正文请忽略)

后面再来估计,似乎官方的版本也是没有多线程的(比如mx.img.ImageIter?),只是计算引擎在那里使人产生错觉,或者是在调用某些特别的函数时,在某处调用了多线程。(待验证)

看了下,似乎正好有个通用interface。

class mxnet.io.PrefetchingIter(iters, rename_data=None, rename_label=None)

Performs pre-fetch for other data iterators.

This iterator will create another thread to perform iter_next and then store the data in memory. It potentially accelerates the data read, at the cost of more memory usage.

Parameters:

iters (DataIter or list of DataIter) – The data iterators to be pre-fetched.

rename_data (None or list of dict) – The i-th element is a renaming map for the i-th iter, in the form of {‘original_name’ : ‘new_name’}. Should have one entry for each entry in iter[i].provide_data.

rename_label (None or list of dict) – Similar to rename_data.

Examples

>>> iter1 = mx.io.NDArrayIter({'data':mx.nd.ones((100,10))}, batch_size=25)

>>> iter2 = mx.io.NDArrayIter({'data':mx.nd.ones((100,10))}, batch_size=25)

>>> piter = mx.io.PrefetchingIter([iter1, iter2],

... rename_data=[{'data': 'data_1'}, {'data': 'data_2'}])

>>> print(piter.provide_data)

[DataDesc[data_1,(25, 10L),,NCHW],

DataDesc[data_2,(25, 10L),,NCHW]]

如果要更多的线程,估计可以将迭代器反复迭代。

NOTE

上面的结论还没试。

试了下,CPU的波动问题似乎没有得到解决,不过从GPU的utilization来看,这部分应该是有效的。

21 Jun, 2017 再记

前面写了几段发现还不适合发布,最近发现些其他问题,想到这还没完结,正好放这了。

Previous Note

前面提到的PrefetchingIter最好单独开一个变量来存储返回值:

后续内部自定义调用更灵活

线程相关

第2点还没有详细的试验,但这样做肯定是安全的,并且至少第一点是一个优势。

Concern

谈谈新的问题。

通常多线程成为噩梦的重要原因是同步is prone to bugs,这在以传递ref为特色的设计里面尤为使人忧虑。比如这段测试:

import mxnet as mx

import numpy as np

m_ = np.random.randint(-10,10,(4,5,6,7))

m= mx.nd.array(m_)

m_it = mx.io.PrefetchingIter(mx.io.NDArrayIter(m))

d=m_it.next().data[0]

m[:]=0 #-> 0....

d.asnumpy().sum() # dangerous !!!!

# 0

Solution

显然,使用强制拷贝是最合理的:

import mxnet as mx

import numpy as np

m_ = np.random.randint(-10,10,(4,5,6,7))

m= mx.nd.array(m_)

#m_it = mx.io.NDArrayIter(m)

m_it = mx.io.PrefetchingIter(mx.io.NDArrayIter(m))

d=m_it.next().data[0].copy()

m[:]=0 #-> 0....

d.asnumpy().sum()

# -118.0

Followup

另一个附带的问题是,拷贝的目的地在哪:

import mxnet as mx

import numpy as np

m_ = np.random.randint(-10,10,(4,5,6,7))

m= mx.nd.array(m_,mx.cpu(1))

m.copy().context

# cpu(1)

一个称心的返回值 😃

17 July, 2017 记

内存空间释放重利用

在空间管理上还存在一些问题。看github上的讨论,意思是mxnet将内存作为池来管理,所以即使释放了内存也不会从nvidia上看到变化。(其中一个问题是怎样释放掉一个变量,发现直接赋值为None可以解决问题)

但还是遇到一些问题,比如下面这段:

import mxnet as mx

def test():

m=mx.nd.zeros((999,999,550),mx.gpu()) # 4GB 的 total dedicated memory

return mx.io.NDArrayIter(m,batch_size=1)

用下面这个这段可以顺利运行:

from test import test, mx

import time

it_ = test()

it_ = None

time.sleep(2) # 似乎要这样运作一下

it_ = test() # 没问题

但这段就不行了:

from test import test, mx

import time

it_ = test()

it = mx.io.PrefetchingIter(it_)

it_ = None

it =None

time.sleep(2)

it_ = test()

it = mx.io.PrefetchingIter(it_) # 提示 Out of Memory

检查io.py时发现一个可能行的方案:

from test import test, mx

import time

it_ = test()

it = mx.io.PrefetchingIter(it_)

it.__del__() # 加入这个

it_ = None

it =None

time.sleep(2)

it_ = test()

it = mx.io.PrefetchingIter(it_) # 没有问题!

21 Jul, 2017 记

关于 __del__()与内存

另一最近遇到的一个例子是example/ssd里面的。

需要把图片里面的目标检测出来。使用的是for来一次次读,然后检测的结构。过了一会发现内存上去了,后面就被killed掉了,于是只好过一段时间自己中断掉,然后重新启动。后面发现可能要长期使用,这样手工中断就有些吃不消了,又不想跑到里面去改迭代器。跟着里面走了一会儿,发现出现了PrefetchingIter(于是乎,陡然间想起多年前的寒假,在某kernel里面讲到出现系统kill的情况),于是在这段函数结束前,调用__del__(),内存搞定。(函数结束没有结束线程应该是没问题的)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值