Ошибка сегментации при создании многопроцессорного массива - PullRequest
0 голосов
/ 13 декабря 2018

Я пытаюсь заполнить массив с помощью многопроцессорной обработки, следуя этому сообщению .То, что у меня хорошо работает на моем Mac, но когда я портирую его на Ubuntu, я часто получаю ошибки сегментации.

Я сократил код до следующего минимального примера:

import numpy as np
from multiprocessing import sharedctypes

a = np.ctypeslib.as_ctypes(np.zeros((224,224,3)))
print("Made a, now making b")
b = sharedctypes.RawArray(a._type_, a)
print("Finished.")

В Ubuntu 16.04, с Python 3.6.5 и numpy 1.15.4 (те же версии, что и на моем Mac), я получаю вывод

Made a, now making b
Segmentation fault (core dumped)

Теперь я могу несколько изменить размеры массива, а в некоторыхслучаях это будет работать (например, измените первые 224 на 100, и это работает).Но в основном это ошибки.

Может ли кто-нибудь предложить какое-либо понимание?

Я вижу одно сообщение по связанной теме с 2016 года, что никто не ответил на , и другое с указателями который я не использую.

PS- Похоже, не имеет значения, указываю ли я a как многомерный массив или как уплощенный массив (например, np.zeros(224*224*3)).Это также, кажется, не имеет значения, если я изменяю тип данных (например, float на int);это не помогает.

Еще одно обновление: Даже установка "size = 224" в коде из оригинального сообщения вызывает ошибки сегмента на двух разных машинах Ubuntu сразные версии NumPy, но отлично работает на Mac.

Ответы [ 3 ]

0 голосов
/ 14 декабря 2018

Это скорее предположение, чем ответ, но вы можете столкнуться с проблемой из-за сбора мусора в основном буфере данных.Это может объяснить, почему, похоже, существует зависимость от общего размера массива, который вы пытаетесь создать.

Если это так, то исправление будет состоять в том, чтобы назначить массив нулей Numpy, который вы создаете.к своей собственной переменной.Это будет гарантировать, что буфер «живет» через создание RawArray.Тогда код будет:

zs = np.zeros((224,224,3))
a = np.ctypeslib.as_ctypes(zs)
print("Made a, now making b")
b = sharedctypes.RawArray(a._type_, a)
print("Finished.")

У меня сейчас только Mac, поэтому я сам не могу это проверить.

0 голосов
/ 16 декабря 2018

Дополнительный анализ и устранение первопричины.

Как указывалось выше, это результат ошибки сборки мусора, которая подсказала мне, как ее исправить.

Сохраняя ссылку на исходный объект np.zeros, ошибку удалось избежать.Это означало (для меня), что коллекция исходного объекта повредила результирующий массив.

Глядя на реализацию as_ctypes (взято из c52543e4a )

def as_ctypes(obj):
    """Create and return a ctypes object from a numpy array.  Actually
    anything that exposes the __array_interface__ is accepted."""
    ai = obj.__array_interface__
    if ai["strides"]:
        raise TypeError("strided arrays not supported")
    if ai["version"] != 3:
        raise TypeError("only __array_interface__ version 3 supported")
    addr, readonly = ai["data"]
    if readonly:
        raise TypeError("readonly arrays unsupported")
    tp = _ctype_ndarray(_typecodes[ai["typestr"]], ai["shape"])
    result = tp.from_address(addr)
    result.__keep = ai
    return result

очевидно, что об этом думал первоначальный автор (назначив .__keep для сохранения ссылки на исходный объект).Однако, похоже, им нужно сохранить ссылку на оригинальный объект.

Я написал патч , который делает это:

-        result.__keep = ai
+        result.__keep = obj
0 голосов
/ 13 декабря 2018

Последнее замечание

Оставив свои тесты на потомство, но у тел есть ответ.

Примечание

Ниже приведены результаты тестирования Debian.Тестирование на Ubuntu (WSL) действительно намного хуже.В Ubuntu n=193 для любых сбоев фигур (также, если я заменю 3d n на 1) и любые n выше.Выглядит как (см. bla.py ниже):

  1. py bla.py n 1 выделяет 3204 на A, 29323 ob B для всех 0<n<193
  2. Для n>=193 aОшибка сегментации возникает на B, а 3208 выделяется на A.Видимо, где-то в ubuntu.

есть некоторый жесткий предел памяти. Старые тесты на Debian

После некоторого тестирования это выглядит какпроблема памяти со странным масштабированием выделения памяти с измерением.

Редактирование только с двумя измерениями не дает мне сбоя, а 3 делает - я отвечу, предполагая это.

Для меня:

b = sharedctypes.RawArray(a._type_, a)

не завершится сбоем, если:

a = np.ctypeslib.as_ctypes(np.zeros((224**3))) #Though generating b takes a while
a = np.ctypeslib.as_ctypes(np.zeros((100,100,100)))

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

Конечно, вы используете указатели.Давайте попробуем кое-что (bla.py):

import tracemalloc
import numpy as np
from sys import argv
from multiprocessing import sharedctypes

n,shape = (int (x) for x in argv[1:])
if shape == 1: shape = n
if shape == 2: shape = (n**2,n)
if shape == 3: shape = (n,n,n)

tracemalloc.start()
a = np.ctypeslib.as_ctypes(np.zeros(shape))
x=tracemalloc.take_snapshot().statistics('lineno')
print(len(x),sum((a.size for a in x)))
b = sharedctypes.RawArray(a._type_, a)
x=tracemalloc.take_snapshot().statistics('lineno')
print(len(x),sum((a.size for a in x)))

В результате:

           n   shape    (a mallocs sum) (b mallocs sum)
>py bla.py 100 1     => 5 3478 76 30147
>py bla.py 100 2     => 5 5916 76 948313
>py bla.py 100 3     => 5 8200 76 43033
>py bla.py 150 1     => 5 3478 76 30195
>py bla.py 150 2     => 5 5916 76 2790461
>py bla.py 150 3     => 5 8200 76 45583
>py bla.py 159 1     => 5 3478 76 30195
>py bla.py 159 2     => 5 5916 76 2937854
>py bla.py 159 3     => 5 8200 76 46042
>py bla.py 160 1     => 5 3478 76 30195
>py bla.py 160 2     => 5 5916 72 2953989
>py bla.py 160 3     => 5 8200 Segmentation fault
>py bla.py 161 1     => 5 3478 76 30195
>py bla.py 161 2     => 5 5916 75 2971746
>py bla.py 161 3     => 5 8200 75 46116

>py bla.py 221 1     => 5 3478 76 30195
>py bla.py 221 2     => 5 5916 76 5759398
>py bla.py 221 3     => 5 8200 76 55348
>py bla.py 222 1     => 5 3478 76 30195
>py bla.py 222 2     => 5 5916 76 5782877
>py bla.py 222 3     => 5 8200 76 55399
>py bla.py 223 1     => 5 3478 76 30195
>py bla.py 223 2     => 5 5916 76 5806462
>py bla.py 223 3     => 5 8200 76 55450
>py bla.py 224 1     => 5 3478 76 30195
>py bla.py 224 2     => 5 5916 72 5829381
>py bla.py 224 3     => 5 8200 Segmentation fault
>py bla.py 225 1     => 5 3478 76 30195
>py bla.py 225 2     => 5 5916 76 5853950
>py bla.py 225 3     => 5 8200 76 55552

У странных вещей (n**2,n) выделено огромное количество памяти для общего типа,пока нет n**3 или (n,n,n).Но это не имеет значения.

  1. a mallocs согласованы и лишь незначительно зависят от размера, а вовсе не от n (для проверенных чисел).
  2. b mallocs, помимо того, что имеют высокую форму 2, также немного увеличиваются с n, но с формой они сильно различаются.
  3. Ошибки сегментации происходят циклично!Выделение памяти для фигуры (n,n,n) на моей машине приближается к некоторому n зависимому числу до sefault - но для n+1 мы снова в порядке.Кажется, что ~ 46k около 160 и ~ 56k около 224.

Нет хорошего объяснения от меня, но зависимость от n заставляет меня думать, что распределения должны хорошо вписываться в какую-то битовую структуру, ииногда это ломается.

Я предполагаю, что использование 225 для ваших измерений будет работать - как обходной путь.

...