似乎我可以通过创建mmap'ddarray并使用它来初始化Series来为python系列记录底层数据.
def assert_readonly(iloc):
try:
iloc[0] = 999 # Should be non-editable
raise Exception("MUST BE READ ONLY (1)")
except ValueError as e:
assert "read-only" in e.message
# Original ndarray
n = 1000
_arr = np.arange(0,1000, dtype=float)
# Convert it to a memmap
mm = np.memmap(filename, mode='w+', shape=_arr.shape, dtype=_arr.dtype)
mm[:] = _arr[:]
del _arr
mm.flush()
mm.flags['WRITEABLE'] = False # Make immutable!
# Wrap as a series
s = pd.Series(mm, name="a")
assert_readonly(s.iloc)
Run Code Online (Sandbox Code Playgroud)
成功!它似乎s是由只读的mem映射的ndarray支持.我可以为DataFrame执行相同的操作吗?以下失败
df = pd.DataFrame(s, copy=False, columns=['a'])
assert_readonly(df["a"]) # Fails …Run Code Online (Sandbox Code Playgroud) 我有一个时间戳数组,对于矩阵X的第二列中的每一行都会增加.我计算时间戳的平均值,它大于最大值.我正在使用numpy memmap进行存储.为什么会这样?
>>> self.X[:,1]
memmap([ 1.45160858e+09, 1.45160858e+09, 1.45160858e+09, ...,
1.45997146e+09, 1.45997683e+09, 1.45997939e+09], dtype=float32)
>>> np.mean(self.X[:,1])
1.4642646e+09
>>> np.max(self.X[:,1])
memmap(1459979392.0, dtype=float32)
>>> np.average(self.X[:,1])
1.4642646e+09
>>> self.X[:,1].shape
(873608,)
>>> np.sum(self.X[:,1])
memmap(1279193195216896.0, dtype=float32)
>>> np.sum(self.X[:,1]) / self.X[:,1].shape[0]
memmap(1464264515.9120522)
Run Code Online (Sandbox Code Playgroud)
编辑:我在这里上传了memmap文件.http://www.filedropper.com/x_2这是我加载它的方式.
filepath = ...
shape = (875422, 23)
X = np.memmap(filepath, dtype="float32", mode="r", shape=shape)
# I preprocess X by removing rows with all 0s
# note this step doesn't affect the problem
to_remove = np.where(np.all(X == 0, axis=1))[0]
X = np.delete(X, to_remove, axis=0)
Run Code Online (Sandbox Code Playgroud) 到目前为止,我已经尝试过:
xr.open_dataset使用chunksarg,它将数据加载到内存中。NetCDF4DataStore,然后调用ds['field'].values,它将数据加载到内存中。ScipyDataStore与mmap='r'和ds['field'].values数据加载到内存中。从我所看到的情况来看,该设计似乎不围绕在内存映射的数组上实际应用numpy函数,而是将小块加载到内存中(有时使用内存映射来实现)。例如,此注释。而有些相关评论点击这里了解不xarray不能够确定一个numpy的阵列是否mmapped与否。
我希望能够将数据表示和切片为xarray.Dataset,并能够调用.values(或.data)以获取ndarray,但仍将其映射(为共享内存等目的)。
如果分块的dask操作至少可以在内存映射的数组上运行,直到它实际上需要进行某些更改,这也是很好的,因为dask似乎是围绕不可变数组设计的,因此这似乎是可能的。
我确实找到了xarray的窍门,就是这样做的:
data=np.load('file.npy', mmap_mode='r')
ds=xr.Dataset({'foo': (['dim1', 'dim2'], data)})
Run Code Online (Sandbox Code Playgroud)
在这一点上,类似以下内容的工作无需将任何内容加载到内存中:
np.sum(ds['foo'].values)
np.sum(ds['foo'][::2,:].values)
Run Code Online (Sandbox Code Playgroud)
... xarray显然不知道该数组是否被映射,因此无法承受np.copy此类情况。
是否存在“受支持的”方式在xarray或dask中进行只读映射(或对此事进行复制复制)?
假设我在磁盘上保存了一些大矩阵。将它全部存储在内存中并不是真的可行,所以我使用 memmap 来访问它
A = np.memmap(filename, dtype='float32', mode='r', shape=(3000000,162))
Run Code Online (Sandbox Code Playgroud)
现在假设我想遍历这个矩阵(本质上不是以有序的方式),这样每一行都将被访问一次。
p = some_permutation_of_0_to_2999999()
Run Code Online (Sandbox Code Playgroud)
我想做这样的事情:
start = 0
end = 3000000
num_rows_to_load_at_once = some_size_that_will_fit_in_memory()
while start < end:
indices_to_access = p[start:start+num_rows_to_load_at_once]
do_stuff_with(A[indices_to_access, :])
start = min(end, start+num_rows_to_load_at_once)
Run Code Online (Sandbox Code Playgroud)
随着这个过程在我的电脑上进行,我的电脑变得越来越慢,我的 RAM 和虚拟内存使用量呈爆炸式增长。
有没有办法强制 np.memmap 使用一定数量的内存?(我知道我需要的行数不会超过我计划一次读取的行数,而且缓存不会真正帮助我,因为我只访问了每一行一次)
也许有其他方法可以按自定义顺序在 np 数组上迭代(类似于生成器)?我可以使用 file.seek 手动编写它,但它恰好比 np.memmap 实现慢得多
do_stuff_with() 不保留对其接收的数组的任何引用,因此在该方面没有“内存泄漏”
谢谢
Joblib 具有通过自动内存映射数组来跨进程共享 Numpy 数组的功能。然而,这利用了 Numpy 的特定功能。Pandas 确实在底层使用了 Numpy,但除非您的列都具有相同的数据类型,否则您无法真正将 DataFrame 序列化为单个 Numpy 数组。
缓存 DataFrame 以在 Joblib 中重用的“正确”方法是什么?
我最好的猜测是分别对每一列进行内存映射,然后在循环内重建数据帧(并祈祷 Pandas 不会复制数据)。但这似乎是一个相当密集的过程。
我知道独立的 Memory 类,但不清楚这是否有帮助。
我正在处理一个太大而无法放入 RAM 的数据集。我目前正在尝试的解决方案是使用 numpy memmap 使用 Dataloader 一次加载一个样本/行。解决方案看起来像这样:
class MMDataset(torch.utils.data.Dataset):
def __init__(self, path):
self.file_path = path
self.dataset_len = 44000000
self.bytes_per_value = 32/8
self.num_cols = 512
self.num_rows = 1
def __getitem__(self, index):
x = np.memmap(self.file_path, dtype='float32', mode='r', shape=(
self.num_rows, self.num_cols), offset=int(index*self.num_cols*self.bytes_per_value))
return np.array(x)
def __len__(self):
return self.dataset_len
dataset = MMDataset('./data/emb.memmap')
data_loader = DataLoader(
dataset,
batch_size=4096,
shuffle=True,
num_workers=20
)
Run Code Online (Sandbox Code Playgroud)
当可用RAM量大于memmap文件的大小时,数据加载速度很快。我每秒处理大约60 批。但是,当可用 RAM 小于 memmap 文件的大小时,我得到大约 3 个批次/秒。
我在尝试不同大小的 memmap 文件时发现了这一点。
为什么会这样呢?如果当可用 RAM < memmap 文件大小时 Dataloader …
我有一个大数据文件 (N,4),我正在逐行映射。我的文件是 10 GB,下面给出了一个简单的实现。虽然下面的工作,它需要大量的时间。
我想实现这个逻辑,以便直接读取文本文件并且我可以访问元素。此后,我需要根据第 2 列元素对整个(映射)文件进行排序。
我在网上看到的示例假设数据较小 ( d) 并使用,f[:] = d[:]但我不能这样做,因为d在我的情况下是巨大的并且会占用我的 RAM。
PS:我知道如何使用 加载文件np.loadtxt并使用对它们进行排序argsort,但是对于 GB 文件大小,该逻辑失败(内存错误)。将不胜感激任何方向。
nrows, ncols = 20000000, 4 # nrows is really larger than this no. this is just for illustration
f = np.memmap('memmapped.dat', dtype=np.float32,
mode='w+', shape=(nrows, ncols))
filename = "my_file.txt"
with open(filename) as file:
for i, line in enumerate(file):
floats = [float(x) for x in line.split(',')]
f[i, :] = floats
del f
Run Code Online (Sandbox Code Playgroud) 我正在图像数据库上训练神经网络。我的图像具有全高清 (1920 x 1080) 分辨率,但为了训练,我使用大小为 256x256 的随机裁剪。由于读取完整图像然后裁剪效率不高,因此我使用 numpy memmap 仅加载 256x256 裁剪图像。也就是说,我正在做类似下面的事情
image_mmap = numpy.load(npy_image_path.as_posix(), mmap_mode=mmap_mode)
cropped_image = image_mmap[y1:y2, x1:x2]
Run Code Online (Sandbox Code Playgroud)
由于在每个 epoch 中都会加载相同的图像,因此最初在每个 epoch 中加载所有 memmap 是否会更好,只需调用上面的第二行来获取裁剪后的图像?
PS:我已经尝试了这两种方法,但我并没有真正发现它们之间有很大的区别。我的直觉表明在__init__函数中加载所有内存映射应该比在每个时期一次又一次加载内存映射更好,但事实并非如此。如果你能解释为什么会发生这种情况,那也会对我有帮助。
尽管两种方法对我来说效果相似,但我问这个问题的原因是,我想知道未来的最佳实践是什么。
是否可以将 numpy 数组以布尔格式保存在磁盘上,每个元素只需要 1 位?这个答案建议使用packbits和unpackbits,但是从文档来看,这似乎可能不支持内存映射。有没有办法在支持 memmap 的情况下在磁盘上存储 1 位数组?
需要 memmap 的原因:我正在全高清 ( 1920x1080) 图像的数据库上训练我的神经网络,但我会为每次迭代随机裁剪一个256x256补丁。由于读取完整图像非常耗时,因此我使用 memmap 只读取所需的补丁。现在,我想将二进制掩码与我的图像一起使用,因此有此要求。
我正在寻找更紧凑的方式来存储布尔值.numpy内部需要8位来存储一个布尔值,但np.packbits允许打包它们,这很酷.
问题是要在4e6字节数组中包含一个32e6字节的布尔数组,我们需要先花费256e6字节来转换int数组中的布尔数组!
In [1]: db_bool = np.array(np.random.randint(2, size=(int(2e6), 16)), dtype=bool)
In [2]: db_int = np.asarray(db_bool, dtype=int)
In [3]: db_packed = np.packbits(db_int, axis=0)
In [4]: db.nbytes, db_int.nbytes, db_packed.nbytes
Out[5]: (32000000, 256000000, 4000000)
Run Code Online (Sandbox Code Playgroud)
numpy跟踪器中有一个关于该问题的问题已经打开了一年(参见 https://github.com/numpy/numpy/issues/5377)
有人有解决方案/更好的解决方法吗?
当我们尝试以正确的方式执行时的追溯:
In [28]: db_pb = np.packbits(db_bool)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-28-3715e167166b> in <module>()
----> 1 db_pb = np.packbits(db_bool)
TypeError: Expected an input array of integer data type
In [29]:
Run Code Online (Sandbox Code Playgroud)
PS:我会试试bitarray但是会把它变成纯粹的numpy.
numpy-memmap ×10
numpy ×9
python ×8
pandas ×2
pytorch ×2
arrays ×1
boolean ×1
dask ×1
dataloader ×1
h5py ×1
hdf5 ×1
joblib ×1
memory ×1
python-3.x ×1
xarray ×1