Реализация эффективной функции разреженной свертки с использованием Eigen - PullRequest
0 голосов
/ 27 марта 2020

Я хочу выполнить свертку образа и ядра. Оба являются собственными матрицами динамического размера со значениями 2001x2001. Я знаю, что моя матрица ядра очень разрежена и содержит ~ 350 ненулевых значений.

Итак, я создал эту функцию с помощью sparseView () матрицы ядра и проверил ее правильность. Идея состоит в том, чтобы перебирать только ненулевые значения моего ядра при выполнении шагов умножения свертки.

Тем не менее, в сценарии, указанном выше, время выполнения этой функции составляет в среднем около 16 секунд на моей машине, даже несмотря на то, что нужно выполнить «только» 1 401 400 350 операций. Используя тот же вход, MATLAB может выполнить свертку с conv2 примерно за 2 секунды. Это просто экстремальная оптимизация в MATLABS или я что-то упустил? (Разделение ядра невозможно)

    Matrix<double, Dynamic, Dynamic> halfSparseConvolution(const Matrix<double, Dynamic, Dynamic> &image, const SparseMatrix<double> &kernel) {
        assert(kernel.rows() % 2 == 1 && kernel.cols() % 2 == 1);
        Matrix<double, Dynamic, Dynamic> image_out = Matrix<double, Dynamic, Dynamic>(image.cols(), image.rows());
        int kernelColsHalf = kernel.cols() / 2;
        int kernelRowsHalf = kernel.rows() / 2;

        for (int i = 0; i < image.rows(); ++i) {
            for (int j = 0; j < image.cols(); ++j) {
                double sum = 0;
                for (int k = 0; k < kernel.outerSize(); ++k) {
                    if (j + kernelColsHalf - k < 0 || j + kernelColsHalf - k >= image.cols())//Checking if out of bounds -> zero-padded so ignore
                        continue;
                    for (Eigen::SparseMatrix<double>::InnerIterator it(kernel, k); it; ++it) {
                        //This iterator only iterates over non-zero values so only nonzero values are multitplied -> better performance with sparse matrices
                        if (i + kernelRowsHalf - it.row() < 0 || i + kernelRowsHalf - it.row() >= image.rows())//Checking if out of bounds -> zero-padded so ignore
                            continue;
                        sum += image(i + kernelRowsHalf - it.row(), j + kernelColsHalf - it.col()) * it.value();
                    }
                }
                image_out(i, j) = sum;
            }
        }
        return image_out;
    }
...