2014-01-05 4 views
20

많은 numpy 배열로 작업하고 있습니다. 최근에 너무 많은 메모리를 씹기 시작 했으므로 numpy.memmap 인스턴스로 바꾸고 싶습니다. 문제는, 지금은 배열의 크기를 조정해야한다는 것입니다. 이것은 보통의 배열에서 꽤 잘 작동하지만, memmaps에서이를 시도하면 데이터가 공유 될 수 있고, 심지어 refcheck를 비활성화하는 것이 도움이되지 않는다고 불평한다.numpy.memmap 배열의 크기 조정

a = np.arange(10) 
a.resize(20) 
a 
>>> array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 

a = np.memmap('bla.bin', dtype=int) 
a 
>>> memmap([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 

a.resize(20, refcheck=False) 
--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-41-f1546111a7a1> in <module>() 
----> 1 a.resize(20, refcheck=False) 

ValueError: cannot resize this array: it does not own its data 

기본 mmap 버퍼 크기를 조정하면 완벽하게 작동합니다. 문제는 이러한 변경을 배열 객체에 반영하는 방법입니다. 이 workaround을 본 적이 있지만 불행히도 배열의 크기를 조정하지는 않습니다. mmap 크기 조정에 대해서도 numpy documentation이 있지만 1.8.0 버전에서는 분명히 작동하지 않습니다. 다른 아이디어, inbuilt 크기 조정 수표를 무시하는 방법?

+0

내가 모르는 뭔가가 있어야합니다 같은 ...이 코드는 나를 위해 잘 실행 느낀다. 그것은 당신을 위해 실행됩니까? 이게 니가하고 싶은게 아니야? http://codepad.org/eEWmYBHZ –

+0

@three_pineapples 그는 배열의 전체 크기를 변경하려고합니다. 코드가 단지 모양을 바꿉니다. –

+0

@ali_m 아, 알았습니다. 나는 질문에서 그것을 얻지 않았다. 그러나 내가 말했던 것처럼, 나는 내가 무엇인가 놓치고있다라고 생각했다! –

답변

10

배열을 만들 때 OWNDATA 플래그가 False라는 것이 문제입니다. 주의해야 할 점은이 배열을 작성하고 사본은 요구 사항이 충족되는지 확인하기 위해 할 수 있다는 것이다

>>> a = np.require(np.memmap('bla.bin', dtype=int), requirements=['O']) 
>>> a.shape 
(10,) 
>>> a.flags 
    C_CONTIGUOUS : True 
    F_CONTIGUOUS : True 
    OWNDATA : True 
    WRITEABLE : True 
    ALIGNED : True 
    UPDATEIFCOPY : False 
>>> a.resize(20, refcheck=False) 
>>> a.shape 
(20,) 

: 당신이 배열을 만들 때 사실로 플래그를 요구하여 그것을 변경할 수 있습니다. 당신이 디스크에 다시 크기의 배열을 저장하려는 경우 재해야 할 때

, 당신은 numpy.memmap대로 A .npy 형식의 파일로 memmap 열기를 저장할 수 있습니다

편집 절약을 해결하기 위해 을 열고 memmap으로 사용 : 다른 방법을 제공

>>> a[9] = 1 
>>> np.save('bla.npy',a) 
>>> b = np.lib.format.open_memmap('bla.npy', dtype=int, mode='r+') 
>>> b 
memmap([0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 

편집 :

닫으 얻을 수 있습니다 당신이 다시 크기가 찾고있는 기본의 mmap (a.base 또는 a._mmap, UINT8 형식으로 저장) 및 memmap "다시로드"내가 잘못 본게 아니라면

>>> a = np.memmap('bla.bin', dtype=int) 
>>> a 
memmap([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 
>>> a[3] = 7 
>>> a 
memmap([0, 0, 0, 7, 0, 0, 0, 0, 0, 0]) 
>>> a.flush() 
>>> a = np.memmap('bla.bin', dtype=int) 
>>> a 
memmap([0, 0, 0, 7, 0, 0, 0, 0, 0, 0]) 
>>> a.base.resize(20*8) 
>>> a.flush() 
>>> a = np.memmap('bla.bin', dtype=int) 
>>> a 
memmap([0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 
+2

흥미 롭습니다. 불행히도, 저에게 그것은 항상 메모리에 복사본을 만드는 것처럼 보입니다. 배열에 쓰려고하면, 배열을 flush, delete, reopen하기 전에 이전과 같이 다시 비 웁니다.그래서 나는 데이터가 실제로 디스크에 쓰여진 적이 결코 없다고 생각합니다. – Michael

+0

어떻게 저장했는지 나중에 memmap으로 다시 열 수있는 예제를 추가했습니다. – wwwslinger

+0

@wwwslinger 대답은 'a'가 너무 커서 코어 메모리에 맞지 않는 경우입니다 (왜 메모리를 사용하지 않을까요? 매핑 된 배열?), 코어에 다른 복사본을 만들면 분명히 몇 가지 문제가 발생할 것입니다. 올바른 크기의 새로운 메모리 맵핑 된 배열을 처음부터 새로 만든 다음, 그 배열을'a' 내용으로 채 웁니다. –

3

,이 wwwslinger의 두 번째 솔루션은 무엇 @ 있지만없이 본질적으로 달성 수동 비트의 새로운 memmap의 크기를 지정할 필요 : 새로운 배열이 이전보다 더 할 필요가있을 때이 잘 작동

In [1]: a = np.memmap('bla.bin', mode='w+', dtype=int, shape=(10,)) 

In [2]: a[3] = 7 

In [3]: a 
Out[3]: memmap([0, 0, 0, 7, 0, 0, 0, 0, 0, 0]) 

In [4]: a.flush() 

# this will append to the original file as much as is necessary to satisfy 
# the new shape requirement, given the specified dtype 
In [5]: new_a = np.memmap('bla.bin', mode='r+', dtype=int, shape=(20,)) 

In [6]: new_a 
Out[6]: memmap([0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 

In [7]: a[-1] = 10 

In [8]: a 
Out[8]: memmap([ 0, 0, 0, 7, 0, 0, 0, 0, 0, 10]) 

In [9]: a.flush() 

In [11]: new_a 
Out[11]: 
memmap([ 0, 0, 0, 7, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 0]) 

을,하지만 난 방법의 유형이 허용됩니다 생각하지 않는다 새로운 배열이 더 작 으면 자동으로 잘릴 메모리 매핑 파일의 크기.

@ wwwslinger의 대답과 같이 수동으로베이스의 크기를 조정하면 파일이 잘릴 수 있지만 파일의 크기는 줄어들지 않습니다. 예를 들어

:

# this creates a memory mapped file of 10 * 8 = 80 bytes 
In [1]: a = np.memmap('bla.bin', mode='w+', dtype=int, shape=(10,)) 

In [2]: a[:] = range(1, 11) 

In [3]: a.flush() 

In [4]: a 
Out[4]: memmap([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 

# now truncate the file to 40 bytes 
In [5]: a.base.resize(5*8) 

In [6]: a.flush() 

# the array still has the same shape, but the truncated part is all zeros 
In [7]: a 
Out[7]: memmap([1, 2, 3, 4, 5, 0, 0, 0, 0, 0]) 

In [8]: b = np.memmap('bla.bin', mode='r+', dtype=int, shape=(5,)) 

# you still need to create a new np.memmap to change the size of the array 
In [9]: b 
Out[9]: memmap([1, 2, 3, 4, 5]) 
+0

이것은 게시 한 해결 방법 중 하나와 비슷한 방식입니다. 나는 인 클로즈 (inplace) 솔루션을 선호한다. 객체를 훨씬 더 캡슐화하는 것을 막을 수 있기 때문이다. 어쨌든, 이것은 아마도 내가 결국 살아야 할 것입니다. – Michael

+0

@Michael 아직 이슈가 없다면 numpy 관리자에게이 문제를보고해야합니다. 적어도 np.memmap 클래스의 docstring은 현재 메모리 매핑 된 배열의 크기를 조정할 수 없다는 사실을 반영하여 업데이트해야합니다. –

+0

나는 그렇지 않다. 그러나 이것에 대한 쉬운 해결책이없는 것처럼 보일 것이다. – Michael