Как лучше определить причину ошибки сегментации в python? - PullRequest
2 голосов
/ 06 января 2020

У меня проблема с ошибкой сегментации в Python. Иногда это происходит, иногда нет, но когда это происходит, я использовал gdb python, как объяснено в в этом ответе , и я получаю такой результат:

[... a lot more lines before this ...]
[New Thread 0x7fff097fa700 (LWP 23244)]

Thread 31 "python" received signal SIGSEGV, Segmentation fault.                                                                                                                                  
[Switching to Thread 0x7fff4affd700 (LWP 23227)]                                                                                                                                                 
__GI___libc_free (mem=0x10035) at malloc.c:3103                                                                                                                                                  
3103    malloc.c: No such file or directory.
(gdb) backtrace
#0  __GI___libc_free (mem=0x10035) at malloc.c:3103
#1  0x00007fff70cc2a39 in ?? () from /<miniconda env path>/lib/python3.6/site-packages/cv2/cv2.cpython-36m-x86_64-linux-gnu.so
#2  0x00007fff70939ef5 in ?? () from /<miniconda env path>/lib/python3.6/site-packages/cv2/cv2.cpython-36m-x86_64-linux-gnu.so
#3  0x00007fff7103a6c5 in ?? () from /<miniconda env path>/lib/python3.6/site-packages/cv2/cv2.cpython-36m-x86_64-linux-gnu.so
#4  0x00007fff70d8263e in ?? () from /<miniconda env path>/lib/python3.6/site-packages/cv2/cv2.cpython-36m-x86_64-linux-gnu.so
#5  0x00007fff70d8304a in ?? () from /<miniconda env path>/lib/python3.6/site-packages/cv2/cv2.cpython-36m-x86_64-linux-gnu.so
#6  0x00007fff70d83d1d in ?? () from /<miniconda env path>/lib/python3.6/site-packages/cv2/cv2.cpython-36m-x86_64-linux-gnu.so
#7  0x00007fff70d83e89 in ?? () from /<miniconda env path>/lib/python3.6/site-packages/cv2/cv2.cpython-36m-x86_64-linux-gnu.so
#8  0x00007ffff7bbd6db in start_thread (arg=0x7fff4affd700) at pthread_create.c:463
#9  0x00007ffff78e688f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Таким образом, проблема, кажется, что-то связанное с cv2, если я правильно понял вывод.

Я не уверен, правильно ли это говорить, но журналы, напечатанные с использованием Python Регистрация прекращается, когда я вызываю функцию из модуля Albumentations , что имеет смысл, так как они используют OpenCV.

Код, который я использую из Albumentations, таков (не уверен, поможет ли это):

import cv2
from albumentations import ElasticTransform, GridDistortion, OneOf, Compose
import logging


class DataAug:
    def __init__(self):
        self.logger = logging.getLogger(__name__)

    @staticmethod
    def get_augs():
        grid = GridDistortion(
            distort_limit=0.2,
            interpolation=cv2.INTER_NEAREST,
            border_mode=cv2.BORDER_CONSTANT,
            value=0,
            always_apply=True
        )
        elast = ElasticTransform(
            alpha_affine=20,
            interpolation=cv2.INTER_NEAREST,
            border_mode=cv2.BORDER_CONSTANT,
            value=0,
            always_apply=True
        )
        return OneOf([
            OneOf([grid, elast], p=1),
            Compose([grid, elast], p=1)
        ], p=1)

    def apply(self, image, mask):
        data = {
            'image': image.astype('uint8'),
            'mask': mask.astype('uint8')
        }
        aug = self.get_augs()
        self.logger.debug('Apply augmentations')
        res = aug(**data)
        return res['image'], res['mask']

Последняя строка, напечатанная для файл журнала - это Apply augmentations.

. Есть ли какой-либо другой способ, чтобы лучше определить, в чем может быть проблема, вызывающая ошибку сегментации? Это на самом деле проблема с модулем или я делаю что-то неправильно, что вызывает его?


РЕДАКТИРОВАТЬ: Изменение метода apply на это не решает проблему

def apply(self, image, mask):
    aug = self.get_augs()
    self.logger.debug('Apply augmentations')
    res = aug(image=image.astype('uint8'), mask=mask.astype('uint8'))
    return res['image'], res['mask']

РЕДАКТИРОВАТЬ: Еще одна вещь, которую я заметил, заключается в том, что ошибка сегмента происходит, только когда я загружаю файлы рассылки вместо создания объектов в коде. Я делаю это, чтобы избежать применения этого процесса каждый раз, чтобы сэкономить время при следующем выполнении.


РЕДАКТИРОВАТЬ: Пример минимальной воспроизводимости (ошибка сегмента может не возникать при каждом выполнении, из 21 выполнения 8 были ошибками сегмента)

import pickle
import cv2
import numpy as np
from albumentations import ElasticTransform, GridDistortion, OneOf, Compose


class DataAug:
    @staticmethod
    def get_augs():
        grid = GridDistortion(
            distort_limit=0.2,
            interpolation=cv2.INTER_NEAREST,
            border_mode=cv2.BORDER_CONSTANT,
            value=0,
            always_apply=True
        )
        elast = ElasticTransform(
            alpha_affine=20,
            interpolation=cv2.INTER_NEAREST,
            border_mode=cv2.BORDER_CONSTANT,
            value=0,
            always_apply=True
        )
        return OneOf([
            OneOf([grid, elast], p=1),
            Compose([grid, elast], p=1)
        ], p=1)

    def apply(self, image, mask):
        data = {
            'image': image.astype('uint8'),
            'mask': mask.astype('uint8')
        }
        aug = self.get_augs()
        res = aug(**data)
        return res['image'], res['mask']


if __name__ == '__main__':
    prc_path = {
        "a": "test-seg-fault/a",
        "b": "test-seg-fault/b"
    }

    sid = 'test1'

    with open(f'{prc_path["a"]}/{sid}', 'wb') as f:
        pickle.dump(np.zeros((1, 512, 512, 3)), f)
    with open(f'{prc_path["b"]}/{sid}', 'wb') as f:
        pickle.dump(np.zeros((1, 512, 512, 1)), f)

    with open(f'{prc_path["a"]}/{sid}', 'rb') as f:
        input_a = pickle.load(f)
    with open(f'{prc_path["b"]}/{sid}', 'rb') as f:
        input_b = pickle.load(f)

    image, mask = DataAug().apply(image=input_a[0, :, :, :], mask=input_b[0, :, :, 0])

    print(image.shape, mask.shape)

Возвращение минимального воспроизводимого примера:

Thread 31 "python" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffa8dd3700 (LWP 28584)]
__GI___libc_free (mem=0x10035) at malloc.c:3103
3103    malloc.c: No such file or directory.
(gdb) backtrace
#0  __GI___libc_free (mem=0x10035) at malloc.c:3103
#1  0x00007ffff5214a39 in ?? () from /<miniconda env path>/lib/python3.6/site-packages/cv2/cv2.cpython-36m-x86_64-linux-gnu.so
#2  0x00007ffff4e8bef5 in ?? () from /<miniconda env path>/lib/python3.6/site-packages/cv2/cv2.cpython-36m-x86_64-linux-gnu.so
#3  0x00007ffff558c6c5 in ?? () from /<miniconda env path>/lib/python3.6/site-packages/cv2/cv2.cpython-36m-x86_64-linux-gnu.so
#4  0x00007ffff52d463e in ?? () from /<miniconda env path>/lib/python3.6/site-packages/cv2/cv2.cpython-36m-x86_64-linux-gnu.so
#5  0x00007ffff52d504a in ?? () from /<miniconda env path>/lib/python3.6/site-packages/cv2/cv2.cpython-36m-x86_64-linux-gnu.so
#6  0x00007ffff52d5d1d in ?? () from /<miniconda env path>/lib/python3.6/site-packages/cv2/cv2.cpython-36m-x86_64-linux-gnu.so
#7  0x00007ffff52d5e89 in ?? () from /<miniconda env path>/lib/python3.6/site-packages/cv2/cv2.cpython-36m-x86_64-linux-gnu.so
#8  0x00007ffff7bbd6db in start_thread (arg=0x7fffa8dd3700) at pthread_create.c:463
#9  0x00007ffff78e688f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95


РЕДАКТИРОВАТЬ: удаление чтения дампа и выборки и объявление переменных input_a = np.zeros((1, 512, 512, 3)), input_b = np.zeros((1, 512, 512, 1)) ошибка сегментации все еще происходит.

...