Функция, выполняющая итерации по большому массиву Numpy с помощью nd.iter, потребляет гораздо больше памяти, чем ожидалось.
У меня есть большое (~ 120 МБ) изображение, содержащее значения классов (каждое из значений uint8 между 0 и 9). Для каждого класса я хотел бы создать список признаков, которые можно использовать для дальнейших операций, например:
class_dict = {
1:[(2,3),(2,4),(2,5).....], # Pixels containing class 1
2:[(30000,2333),(54444,23232) .....], # Pixels containing class 2
....
}
В настоящее время это производится с помощью следующего кода:
class = gdal.Open("path/to/class/geotiff")
class_array = gdal.GetVirtualMemArray() # shape=(11027,10954)
def build_class_dict(class_array, no_data=None):
"""Returns a dict of coordinates of the following shape:
[class, coord_list]"""
out_dict = {}
it = np.nditer(class_array, flags=['multi_index'])
while not it.finished:
this_class = int(it.value)
if this_class == no_data:
it.iternext()
continue
if this_class in out_dict.keys():
out_dict[this_class].append(it.multi_index)
else:
out_dict.update({this_class: [it.multi_index]})
it.iternext()
return out_dict
Учитывая, что я, по сути, дважды сохраняю все изображение, я ожидаю, что объем памяти этой функции вырастет совсем немного - скажем, до ~ 3 ГБ, учитывая обычные издержки Python, что не проблема.
Что происходит, так это то, что площадь программы растет очень быстро, заполняя все доступное пространство. Это завершается примерно за минуту для изображений с большим количеством (~ 80%) значений ноданных, но для чего-то еще это истощает машину ресурсов и блокирует.
Есть ли проблема с памятью в этой реализации, или мне придется переосмыслить? Окружение: Python 3.6.7, numpy 1.15.4 (но пробовал на 1.16.4), gdal 2.4.1, работает на ubuntu 18.02.
EDIT
Дальнейшее развитие; при профилировании функции с помощью декоратора @ memory_profiler.profile память скачет, а затем останется неизменной - что я и ожидал. Это не то, как он вел себя, когда его не контролировали, но он также работает намного медленнее.