Numba:class 方法中的 UntypedAttributeError

Numba: UntypedAttributeError in class method

我有以下 class 和方法,应该将数组与内核进行卷积。

import numpy as np
from numpy.fft import fft2 as FFT, ifft2 as IFFT
from PIL import Image
from tqdm import trange, tqdm
from numba import jit

from time import sleep

import _kernel

class convolve(object):
    """ contains methods to convolve two images """
    def __init__(self, image_array, kernel):
        self.array = image_array
        self.kernel = kernel

        self.__rangeX_ = self.array.shape[0]
        self.__rangeY_ = self.array.shape[1]

        self.__rangeKX_ = self.kernel.shape[0]
        self.__rangeKY_ = self.kernel.shape[1]

        if (self.__rangeKX_ >= self.__rangeX_ or \
            self.__rangeKY_ >= self.__rangeY_):
            raise ValueError('Must submit suitable sizes for convolution.')

    @jit(nopython=True)
    def spaceConv(self):
        """ normal convolution, O(N^2*n^2). This is usually too slow """

        # pad array for convolution
        offsetX = self.__rangeKX_ // 2
        offsetY = self.__rangeKY_ // 2

        self.array = np.pad(self.array,               \
            [(offsetY, offsetY), (offsetX, offsetX)], \
               mode='constant', constant_values=0)

        # this is the O(N^2) part of this algorithm
        for i in xrange(self.__rangeX_ - 2*offsetX):
            for j in xrange(self.__rangeY_ - 2*offsetY):
                # Now O(n^2) portion
                total = 0.0
                for k in xrange(2*offsetX+1):
                    for t in xrange(2*offsetY+1):
                        total += self.kernel[k][t] * self.array[i+k][j+t]
                self.array[i+offsetX][j+offsetY] = total

        return self.array

作为附加说明(以防万一有人问),_kernel 只生成特定的内核,人们可能希望将其与图像进行卷积(例如高斯、莫法特等),因此它与此无关 class.

当我在图像和内核上调用上述 class 时,出现以下错误:

Traceback (most recent call last):
  File "fftconv.py", line 147, in <module>
    plt.imshow(conv.spaceConv(), interpolation='none', cmap='gray')
  File "/root/anaconda2/lib/python2.7/site-packages/numba/dispatcher.py", line 304, in _compile_for_args
    raise e
numba.errors.UntypedAttributeError: Caused By:
Traceback (most recent call last):
  File "/root/anaconda2/lib/python2.7/site-packages/numba/compiler.py", line 249, in run
    stage()
  File "/root/anaconda2/lib/python2.7/site-packages/numba/compiler.py", line 465, in stage_nopython_frontend
    self.locals)
  File "/root/anaconda2/lib/python2.7/site-packages/numba/compiler.py", line 789, in type_inference_stage
    infer.propagate()
  File "/root/anaconda2/lib/python2.7/site-packages/numba/typeinfer.py", line 717, in propagate
    raise errors[0]
UntypedAttributeError: Unknown attribute "rangeKX" of type pyobject
File "fftconv.py", line 45
[1] During: typing of get attribute at fftconv.py (45)

Failed at nopython (nopython frontend)
Unknown attribute "rangeKX" of type pyobject
File "fftconv.py", line 45
[1] During: typing of get attribute at fftconv.py (45)

This error may have been caused by the following argument(s):
- argument 0: cannot determine Numba type of value <__main__.convolve object at 0xaff5628c>

通常我很擅长通过 Python 错误追查原因,但是因为我不熟悉 Numba 的内部工作,我不确定为什么它不知道offsetX 是什么类型。有什么建议吗?

numba 执行的一个步骤是类型推断。这会将类型分配给函数中存在的不同值,以便它可以编译(以一种快速运行的方式)。

错误意味着 numba 不理解函数的第一个输入参数(在本例中为 self)。 Numba 在参数为标量或数组(均为数字)的普通函数中效果最佳。一种选择是将 O(n^2) 循环移动到它自己的函数中,并让该函数显式接收数组和任何其他值,并用 numba.njit (或 numba.jit 装饰该函数(nopython=True),等价于

同样值得一试的是尝试使用代码 "as is" 删除 "nopython=True"。如果性能足够好,那就别管它了:)。这可能会发生,因为 numba.jit 能够检测到可以在 "no python" 模式下编译的代码中的循环,并自动执行所需的操作,以便循环本身在全速模式下编译。不过,显式 "nopython=True" 关键字会禁用该模式。