MemoryError в numpy.append, несмотря на достаточно оперативной памяти - PullRequest
2 голосов
/ 19 июня 2019

Я пытался добавить список точек считываемого облака точек с помощью 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 массив значений типа numpy, как описано выше. После однократной установки точек вы не сможете установить их снова, это означает, что при установке точек необходимо знать окончательный счетчик строк.
  • Вы можете изменить значения строки с помощью 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()

Почти во всех случаях использования, которые у меня есть, это прекрасно работает. Он объединяет все предоставленные облака точек с новым облаком точек в новом файле. Однако, когда результирующее облако точек становится слишком большим, несмотря на то, что у меня гораздо больше памяти, чем нужно, я получаю 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 Ответ

0 голосов
/ 19 июня 2019

На случай, если операция фактически не помещается в памяти, вы можете выделить часть своего жесткого диска для работы в качестве памяти.

Для Windows

Или вы можете использовать Swap-Space на Ubuntu .

Возможно, начните с этого, пока не поймете, как уменьшить потребление памяти. Или, по крайней мере, это может помочь вам устранить неполадки, гарантируя, что у вас действительно достаточно памяти.

...