6

次のコードを検討してください。

import numpy as np
a = np.zeros(50)
a[10:20:2] = 1
b = c = a[10:40:4]
print b.flags  # You'll see that b and c are not C_CONTIGUOUS or F_CONTIGUOUS

私の質問:

bと の両方bc連続させる方法はありますか ( への参照のみ)。この操作でnp.may_share_memory(b,a)戻ってきたら全然大丈夫です。False

近いがうまくいかないものは次のとおりです。 np.ascontiguousarray/新しい配列np.asfortranarrayを返すため。


私の使用例は、非常に大きな 3D フィールドが a のサブクラスに格納されている場合ですnumpy.ndarray。メモリを節約するために、これらのフィールドを、実際に処理したいドメインの部分に切り詰めたいと思います。

a = a[ix1:ix2,iy1:iy2,iz1:iz2]

サブクラスのスライスは、オブジェクトのスライスよりもいくらか制限されてndarrayいますが、これは機能するはずであり、「正しいことを行います」 - サブクラスに添付されたさまざまなカスタム メタデータは、期待どおりに変換/保持されます。残念ながら、これは を返すためview、numpy は後で大きな配列を解放しないため、実際にはここでメモリを節約しません。

完全に明確にするために、私は2つのことを達成しようとしています:

  • クラス インスタンスのメタデータを保持します。スライスは機能しますが、他の形式のコピーについてはわかりません。
  • 元の配列が自由にガベージ コレクションできるようにする
4

3 に答える 3

6

アレックス・マーテリによると

「大規模ではあるが一時的なメモリの使用が完了したときにすべてのリソースをシステムに返すことを保証する唯一の本当に信頼できる方法は、その使用をサブプロセスで発生させ、メモリを大量に消費する作業を終了させることです。」

ただし、次のようにすると、少なくとも一部のメモリが解放されるようです: 警告: 空きメモリを測定する私の方法は Linux 固有です:

import time
import numpy as np

def free_memory():
    """
    Return free memory available, including buffer and cached memory
    """
    total = 0
    with open('/proc/meminfo', 'r') as f:
        for line in f:
            line = line.strip()
            if any(line.startswith(field) for field in ('MemFree', 'Buffers', 'Cached')):
                field, amount, unit = line.split()
                amount = int(amount)
                if unit != 'kB':
                    raise ValueError(
                        'Unknown unit {u!r} in /proc/meminfo'.format(u=unit))
                total += amount
    return total

def gen_change_in_memory():
    """
    https://stackoverflow.com/a/14446011/190597 (unutbu)
    """
    f = free_memory()
    diff = 0
    while True:
        yield diff
        f2 = free_memory()
        diff = f - f2
        f = f2
change_in_memory = gen_change_in_memory().next

大きな配列を割り当てる前に:

print(change_in_memory())
# 0

a = np.zeros(500000)
a[10:20:2] = 1
b = c = a[10:40:4]

大きな配列を割り当てた後:

print(change_in_memory())
# 3844 # KiB

a[:len(b)] = b
b = a[:len(b)]
a.resize(len(b), refcheck=0)
time.sleep(1)

サイズ変更後に空きメモリが増加します。

print(change_in_memory())
# -3708 # KiB
于 2013-03-15T00:59:29.647 に答える
3

あなたはcythonでこれを行うことができます:

In [1]:
%load_ext cythonmagic

In [2]:
%%cython
cimport numpy as np

np.import_array()

def to_c_contiguous(np.ndarray a):
    cdef np.ndarray new
    cdef int dim, i
    new = a.copy()
    dim = np.PyArray_NDIM(new)
    for i in range(dim):
        np.PyArray_STRIDES(a)[i] = np.PyArray_STRIDES(new)[i]
    a.data = new.data
    np.PyArray_UpdateFlags(a, np.NPY_C_CONTIGUOUS)
    np.set_array_base(a, new)

In [8]:
import sys
import numpy as np
a = np.random.rand(10, 10, 10)
b = c = a[::2, 1::3, 2::4]
d = a[::2, 1::3, 2::4]
print sys.getrefcount(a)
to_c_contiguous(b)
print sys.getrefcount(a)
print np.all(b==d)

出力は次のとおりです。

4
3
True

to_c_contiguous(a)の c_contiguous コピーを作成し、aそれを のベースにしaます。

の呼び出し後、to_c_contiguous(b)a の refcount が減少し、a の refcount が 0 になると解放されます。

于 2013-03-15T02:41:10.540 に答える
1

リストした 2 つのことを達成する正しい方法は、np.copy作成したスライスを使用することです。

もちろん、それが正しく機能するためには、適切な を定義する必要があります__array_finalize__。そもそもなぜそれを避けることにしたのかについてはあまり明確ではありませんでしたが、私はそれを定義する必要があると感じています. (を使用せずにどのようにbx**2問題を解決しました__array_finalize__か?)

于 2013-03-15T09:10:47.430 に答える