MemoryError в numpy.append, несмотря на достаточно оперативной памяти
Я пытался добавить список точек считываемого облака точек с помощью laspy к другому списку точек, в основном объединяя два облака точек. При объединении нескольких облаков точек я добавлял все точки к одному и тому же np.ndarray, чтобы сохранить его обратно в файл laspy. Теперь, когда объединенный размер всех облаков точек, которые я хочу объединить, превышает примерно 350 МБ, я получаю MemoryError
,
Я попытался использовать другой метод записи файла pointcloud, так что мне не нужно считывать все точки в памяти одновременно, но это не удалось, поскольку laspy действительно странно, когда речь идет о записи файлов pointcloud, вот несколько вещей, которые я понял:
laspy.File.points
имеет следующий формат:
array([((24315, 12245, 12080, 0, 24, 0, 0, 0, 202, 23205, 24735, 21930),),
...,
((15155, -23292, -6913, 0, 56, 0, 0, 0, 343, 36975, 37230, 37485),)],
dtype=[('point', [('X', '<i4'), ('Y', '<i4'), ('Z', '<i4'), ('intensity', '<u2'), ('flag_byte', 'u1'), ('raw_classification', 'u1'), ('scan_angle_rank', 'i1'), ('user_data', 'u1'), ('pt_src_id', '<u2'), ('red', '<u2'), ('green', '<u2'), ('blue', '<u2')])])
- Тип переменной
laspy.File.points
являетсяnumpy.ndarray
- Форма
laspy.File.points
является(<numberOfRows>,)
=> одномерный массив, хотя он имеет 12 значений в строке (?) - Строки имеют тип
numpy.void
- Для того, чтобы написать
laspy.File
вам нужно создать новый файл в режиме записи, скопировать заголовок из существующего файла и установить для File.points массив пустых данных точно такого же типа, как описано выше. После установки точек один раз, вы не можете установить их снова, это означает, что окончательное количество строк должно быть известно при установке точек. - Вы можете изменить значения строки, используя
laspy.File.set_x(<arrayOfXValues>)
(и аналогично), должна быть той же длины, что иlaspy.File.points
Теперь мой компьютер имеет 16 ГБ оперативной памяти, из которых около 10 ГБ свободно, когда я начинаю объединение. С помощью psutils
Я получаю свою использованную и доступную память и никогда не опускаюсь ниже 9 ГБ свободной памяти. С помощью psutil.Process(os.getpid()).memory_info().rss
Я получаю использованную память для этого процесса, которая никогда не превышает 650 МБ.
При объединении я читаю первый файл, затем перебираю другие файлы, читаю их один за другим и вызываю numpy.append(combinedPoints, otherPointcloudPoints)
сложить все точки вместе. Это, однако, бросает MemoryError
, когда вышеперечисленные условия выполняются.
Вот код для объединения нескольких облаков точек в одно новое облако точек (все это происходит в классе PointCloudFileIO
, self.file
является примером laspy.File
). util.inMB
вычисляет размер от байтов до мегабайт.
def mergePointClouds(self, listPaths, newPath):
realSize = util.inMB(psutil.Process(os.getpid()).memory_info().rss)
print("Process Memory used at start: {:.2f}MB".format(realSize))
print("Available memory at start: {:.2f}MB".format(util.inMB(psutil.virtual_memory().available)))
pointsOwn = self.file.points
firstOtherReader = PointCloudFileIO(listPaths[0])
pointsCombined = np.append(pointsOwn, firstOtherReader.file.points)
realSize = util.inMB(psutil.Process(os.getpid()).memory_info().rss)
print("Process Memory used after first merge: {:.2f}MB".format(realSize))
print("Available memory after first merge: {:.2f}MB".format(util.inMB(psutil.virtual_memory().available)))
for i in range(1, len(listPaths)):
otherReader = PointCloudFileIO(listPaths[i])
otherPoints = otherReader.file.points
pointsCombined = np.append(pointsCombined, otherPoints)
realSize = util.inMB(psutil.Process(os.getpid()).memory_info().rss)
print("Process Memory used in loop: {:.2f}MB".format(realSize))
print("Available memory in loop: {:.2f}MB | Used: {:.2f}MB | Percent: {}%".format(util.inMB(psutil.virtual_memory().available), util.inMB(psutil.virtual_memory().used), psutil.virtual_memory().percent))
outFile = File(newPath, mode='w', header=self.file.header)
outFile.points = pointsCombined
outFile.close()
Почти для всех вариантов использования, которые у меня есть, это работает отлично. Он объединяет все предоставленные облака точек с новым облаком точек в новом файле. Однако, когда результирующее pointcloud становится слишком большим, несмотря на то, что у него больше памяти, чем нужно, я получаю MemoryError
,
Вот журнал, когда я запускаю программу с этими точечными облаками (скачивая файлы.laz), вам нужно будет разархивировать файлы.laz с помощью laszip, прежде чем их можно будет использовать с laspy (по крайней мере, при использовании Windows):
Process Memory used at start: 21.18MB
Available memory at start: 9793.35MB | Used: 6549.50MB | Percent: 40.1%
Process Memory used after first merge: 381.63MB
Available memory after first merge: 9497.64MB | Used: 6845.20MB | Percent: 41.9%
Process Memory used in loop: 559.52MB
Available memory in loop: 9309.36MB | Used: 7033.48MB | Percent: 43.0%
Process Memory used in loop: 637.05MB
Available memory in loop: 9301.00MB | Used: 7041.85MB | Percent: 43.1%
Traceback (most recent call last):
File "optimization_test.py", line 7, in <module>
f1.mergePointClouds(paths, "someShiet.las")
File "C:\Users\viddie\Desktop\git\GeoLeo\geoleo\pointcloud.py", line 175, in mergePointClouds
pointsCombined = np.append(pointsCombined, otherPoints)
File "C:\Users\viddie\AppData\Local\Programs\Python\Python36-32\lib\site-packages\numpy\lib\function_base.py", line 5166, in append
return concatenate((arr, values), axis=axis)
MemoryError
Если кто-то знает причину этого, любая помощь приветствуется.
1 ответ
На случай, если операция фактически не помещается в памяти, вы можете выделить часть своего жесткого диска для работы в качестве памяти.
Или вы можете использовать Swap-Space в Ubuntu.
Возможно, начните с этого, пока не поймете, как уменьшить потребление памяти. Или, по крайней мере, это может помочь вам устранить неполадки, гарантируя, что у вас действительно достаточно памяти.