numpy array - загрузка с диска строка за строкой - эффективность памяти, но быстрая - PullRequest
0 голосов
/ 16 февраля 2019

Есть ли способ конвейерного массива массива с диска, который сохраняется таким образом

np.save('data.npy',np.zeros(shape=[500,300,3])) # RGB image

и читается строка за строкой (или столбец за столбцом) аналогично тому, как работают генераторы, но беззадержка загрузки?


Подробное описание

Моему приложению нужна задержка, близкая к нулю, но загрузка больших массивов с диска может занять некоторое время (~ 0,02-0,1с).Даже эта небольшая задержка приводит к неприятным результатам.

У меня есть решение для этого, которое удовлетворяет скорости:

dictionary = {'array1': array1, ....}

с этим я могу сразу получить доступ к массивам, но так как я использую RasPberry Pi ZeroМоя программа на Python ограничена ЦП и ОЗУ, поэтому, если у меня много массивов, я буду иметь дело с

MemoryError

Мое приложение читает ряд за строкой с частотой 50 Гц, как это

for row in array:
    [operation with row]
    time.sleep(0.02) # in reality, whole cycle is 0.02s ( including operation time) 

Я ищу тип генератора:

def generate_rows(path):
    array = np.load(path)
    for row in array:
        yield row

Это решает проблему с памятью, но я думаю Я потеряю почти нулевую задержку (загрузкамассив).

Поэтому мой вопрос: Есть ли способ генерировать строки, как с помощью генератора, но первые строки готовы, так сказать, «немедленно», с почти нулевой задержкой?


РЕДАКТИРОВАТЬ: Основываясь на комментариях @Lukas Koestler и @hpaulj, я попробовал memmap, но результат на удивление не очень хороший, потому что memmap вылетает в Memory раньше, чем простая загрузка полных массивов.

WINDOWS 10

Я сохранил 1000 дисковых массивов (shape = [500,30,3]) на диске и попытался их кэшировать с помощьюnp.load и np.load с чтением memmap

import numpy as np
import os

mats = os.listdir('matrixes')
cache = []
for i in range(10):
    for n in mats:
        cache.append(np.load('matrixes\\{}'.format(n),mmap_mode='r')) # Load with memmap
        #cache.append(np.load('matrixes\\{}'.format(n))) #load without memmap

    print('{} objects stored in cache '.format((i+1)*1000))

После запуска обоих вариантов (с memmap и без него) произошли эти две ошибки

Memmap после сохранения 4000 объектов memmaps:

...
  File "C:\Python27\lib\site-packages\numpy\core\memmap.py", line 264, in __new__
    mm = mmap.mmap(fid.fileno(), bytes, access=acc, offset=start)
WindowsError: [Error 8] Not enough memory resources are available to process this command

Простой np.load без memmap после кэширования 5000 np.arrays

....
File "C:\Python27\lib\site-packages\numpy\lib\format.py", line 661, in read_array
    array = numpy.fromfile(fp, dtype=dtype, count=count)
MemoryError 

Raspberry pi Zero

Как было указано@Alex Yu, я тестировал на Windows 10, переключаясь на Raspberry Pi Zero,

Я получил более 1000 numpy массивов (заняло довольно много времени), а затем я получил

1000 objects stored in cache
Killed

С Memmaps я довольно быстро получил более 1000 memmaps, но я получил разные ошибки

File "/usr/lib/python2.7/dist-packages/numpy/lib/npyio.py", line 416, in load
    return format.open_memmap(file, mode=mmap_mode)
  File "/usr/lib/python2.7/dist-packages/numpy/lib/format.py", line 792, in open_memmap
    mode=mode, offset=offset)
  File "/usr/lib/python2.7/dist-packages/numpy/core/memmap.py", line 264, in __new__
    mm = mmap.mmap(fid.fileno(), bytes, access=acc, offset=start)
mmap.error: [Errno 24] Too many open files

Если я не ошибаюсь, эта ошибка возникает при открытии большого количества файлов, но не при их закрытии.

1 Ответ

0 голосов
/ 17 февраля 2019

Спасибо @Lukas Koestler и @hpaulj за то, что они указали мне на использование memmap

, и @ Alex Yu * ​​1005 * за то, что решение стало реальностью


Решение моего собственного вопроса

Использование

np.load(path,mmap_mode='r')

работает, но ограничено лимитом открытых файлов.В Windows и Linux выдает разные ошибки:

WIN

WindowsError: [Error 8] Not enough memory resources are available to process this command

LIN

mmap.error: [Errno 24] Too many open files

Эта проблема была решена с помощью ссылки @Alex Yu * ​​1033 * продлить лимит открытых файлов .

Извлечь:

открыто

/etc/security/limits.conf

Вставьте следующее к концу:

*         hard    nofile      500000
*         soft    nofile      500000
root      hard    nofile      500000
root      soft    nofile      500000

Конец извлечения

Существует ограничение, но оно увеличило количество до 8000 объектов в списке

...
8000 objects stored in cache

до

Traceback (most recent call last):
...
mm = mmap.mmap(fid.fileno(), bytes, access=acc, offset=start)
mmap.error: [Errno 12] Cannot allocate memory

Для меня этого вполне достаточно


Общий обзор различных взглядов на мою проблему

проверено на массивах с формой [500,30,3]

1) Простая загрузка: без кэширования

array = np.load(path)
[process rows]

Самый медленный, но самый эффективный в использовании памяти

cache_limit = 0 (массивы в словаре)

2) Жесткий кеш - загрузка массивов в словарь

cache_raw = {i: np.load(i) for i in os.listdir('array_folder')}
...
temporary_array = cache_raw[some_array]
[process rows with temporary_array]

Сверхбыстрая, но очень неэффективная память

cache_limit ~ 1000, (RPI ноль) (массивы в словаре)

3) Кэш Memmap

cache_memmap = {i: np.load(i,mmap_mode='r') for i in os.listdir('array_folder')}
...
memmap_array = cache_memmap[some_array]
[process rows with memmap_array]

разумная скорость, эффективная память

cache_limit ~ 8000 (RPI ноль) (массивы в словаре)


Результаты

Сроки результатов загрузки первая строка для 20 случайных обращений для всех отношений:

Memmap
0.00122714042664
0.00237703323364
0.00152182579041
0.000735998153687
0.000724077224731
0.000736951828003
0.000741004943848
0.000698089599609
0.000723123550415
0.000734090805054
0.000775814056396
0.00343084335327
0.000797033309937
0.000717878341675
0.000727891921997
0.000733852386475
0.000690937042236
0.00178194046021
0.000714063644409
0.000691175460815
Hard cache
0.000302076339722
0.000305891036987
0.000910043716431
0.000320911407471
0.000298976898193
0.000309944152832
0.000294923782349
0.000304937362671
0.000298023223877
0.00031590461731
0.000324010848999
0.000273942947388
0.000274181365967
0.000286817550659
0.000277042388916
0.000297784805298
0.000288009643555
0.000318050384521
0.00031304359436
0.000298023223877
Without cache
0.0350978374481
0.0103611946106
0.0172200202942
0.0349309444427
0.0177171230316
0.00722813606262
0.0286860466003
0.0435371398926
0.0261130332947
0.0302798748016
0.0361919403076
0.0286440849304
0.0175659656525
0.035896062851
0.0307757854462
0.0364079475403
0.0258250236511
0.00768494606018
0.025671005249
0.0261180400848

РЕДАКТИРОВАТЬ: Дополнительные вычисления:

Среднее время 100 уникальных обращений,5 раз за каждое отношение

Memmap
0.000535547733307 # very good speed
0.000488042831421
0.000483453273773
0.000485241413116
0.00049720287323
Hard cache
0.000133073329926 # 4x faster than memmap
0.000132908821106
0.000131068229675
0.000130603313446
0.000126478672028
Without cache
0.0996991252899 # very slow
0.0946901941299
0.0264434242249 # Interesting to note here, something I suspected
0.0239776492119 # np.load has cache in itself
0.0208633708954 # If you load particular numpy array more times in the program,
#it will load faster. Kind of integrated cache
# From my own experience, it is very unreliable and cannot be counted with.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...