3

私は機械学習のために非常に高次元のベクトルを扱っており、numpy を使用してメモリの使用量を削減することを考えていました。numpy (1)(3) を使用してどれだけのメモリを節約できるかを確認するための簡単なテストを実行します。

規格一覧

import random
random.seed(0)
vector = [random.random() for i in xrange(2**27)]

numpy 配列

import numpy
import random
random.seed(0)
vector = numpy.fromiter((random.random() for i in xrange(2**27)), dtype=float)

メモリ使用量 (2)

Numpy array: 1054 MB
Standard list: 2594 MB

私が期待したように。

ネイティブ フロートを使用してメモリのブロックを継続的に割り当てることにより、numpy は標準リストが使用しているメモリの約半分しか消費しません。

私のデータはかなり予備的であることがわかっているので、スパース データを使用して同じテストを行いました。

規格一覧

import random
random.seed(0)
vector = [random.random() if random.random() < 0.00001 else 0.0 for i in xrange(2 ** 27)]

numpy 配列

from numpy import fromiter
from random import random
random.seed(0)
vector = numpy.fromiter((random.random() if random.random() < 0.00001 else 0.0 for i in xrange(2 ** 27)), dtype=float)

メモリ使用量 (2)

Numpy array: 1054 MB
Standard list: 529 MB

突然、Python リストは numpy 配列が使用するメモリの半分の量を使用します! なんで?

私が考えることができることの1つは、Pythonが非常にまばらなデータが含まれていることを検出すると、辞書表現に動的に切り替えることです。これをチェックすると、実行時のオーバーヘッドが大幅に増える可能性があるため、これが起こっているとは思えません。

ノート

  1. テストごとに、新しい python シェルを開始しました。
  2. htopで測定したメモリ。
  3. 32 ビット Debian で実行します。
4

1 に答える 1

2

Python リストは、Python オブジェクトへの参照 (ポインター) の単なる配列です。CPython (通常の Python 実装) では、展開をより効率的にするためにリストがわずかに過剰に割り当てられますが、dict に変換されることはありません。詳細については、ソース コードを参照してください:リスト オブジェクトの実装

リストのスパース バージョンでは、単一のint0 オブジェクトへのポインターが多数あります。これらのポインターは 32 ビット = 4 バイトを占めますが、numpy float は確かに大きく、おそらく 64 ビットです。

FWIW、スパース リスト/配列テストをより正確にするにはrandom.seed(some_const)、両方のバージョンで同じシードを使用して呼び出し、Python リストと numpy 配列の両方で同じ数のゼロを取得する必要があります。

于 2015-04-14T13:23:48.213 に答える