1. ホーム
  2. python

[解決済み] 形状やデータ型を持つ配列が割り当てられない

2022-04-24 10:07:32

質問

Ubuntu 18でnumpyの巨大な配列を割り当てる問題に直面していますが、MacOSでは同じ問題に直面していません。

numpyの配列にメモリを割り当てようとしているのですが、形状が (156816, 36, 53806)

np.zeros((156816, 36, 53806), dtype='uint8')

で、Ubuntu OSではエラーが出るのに

>>> import numpy as np
>>> np.zeros((156816, 36, 53806), dtype='uint8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
numpy.core._exceptions.MemoryError: Unable to allocate array with shape (156816, 36, 53806) and data type uint8

MacOSで出ないんだけど。

>>> import numpy as np 
>>> np.zeros((156816, 36, 53806), dtype='uint8')
array([[[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       ...,

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]]], dtype=uint8)

どこかで読んだことがあるのですが np.zeros 配列に必要なメモリ全体を本当に割り当てるのではなく、0以外の要素に対してのみ割り当てるべきです。Ubuntuマシンには64GBのメモリがあるのに、私のMacBook Proには16GBしかないのです。

のバージョンがあります。

Ubuntu
os -> ubuntu mate 18
python -> 3.6.8
numpy -> 1.17.0

mac
os -> 10.14.6
python -> 3.6.4
numpy -> 1.17.0

追記:Google Colabでも失敗しました

解決するには?

これはおそらく、お使いのシステムの オーバーコミット処理 モードがあります。

デフォルトのモードでは 0 ,

ヒューリスティックなオーバーコミット処理。アドレス空間の明らかなオーバーコミットは拒否されます。典型的なシステムで使用されます。スワップ使用量を減らすためにオーバーコミットを許可する一方で、ひどく乱暴な割り当てが失敗することを保証します。このモードでは、rootは少し多めのメモリを割り当てることができます。これはデフォルトです。

使用されている正確なヒューリスティックはここではうまく説明できませんが、これについては Linux over commit ヒューリスティック このページでは .

を実行することで、現在のオーバーコミット・モードを確認できます。

$ cat /proc/sys/vm/overcommit_memory
0

この場合、アロケートするのは

>>> 156816 * 36 * 53806 / 1024.0**3
282.8939827680588

~カーネルは、明らかにこれだけの物理ページをコミットできるわけがない、と言って、割り当てを拒否しています。

もし(rootで)実行したら。

$ echo 1 > /proc/sys/vm/overcommit_memory

これにより、quot;always overcommit" モードが有効になり、実際にシステムがどんなに大きなアロケーションでも許可することがわかります(少なくとも64ビットメモリアドレス内)。

私は、32GBのRAMを搭載したマシンでこのことを自分でテストしました。 オーバーコミットモードで 0 も出ました。 MemoryError に戻した後 1 が動作します。

>>> import numpy as np
>>> a = np.zeros((156816, 36, 53806), dtype='uint8')
>>> a.nbytes
303755101056

その後、配列内の任意の場所に書き込むことができます。システムは、あなたが明示的にそのページに書き込んだときのみ、物理ページを割り当てます。 このため、疎な配列には注意して使用することができます。