使用 OpenCV 时,Cython 比 Python 慢
Cython slower compared to Python when using OpenCV
我正在试验 Cython 和 OpenCV,并尝试对图像处理的性能进行基准测试。我已尝试尽可能多地优化我的 Cython 代码,但我的性能仍然较慢。我知道由于 OpenCV,大部分代码都是在 C 中执行的,但我希望使用 Cython 的 python 循环有更好的性能。谁能告诉我是否可以做些什么来改进它?以下是我的代码:
# load_images.py
import cv2
from random import randint
import numpy as np
def fetch_images(n):
def get_img():
x = randint(640, 6144)
y = randint(640, 6144)
return np.random.rand(x,y, 3).astype(np.uint8)
return [get_img() for _ in range(n)]
def resize_img(img):
img = cv2.resize(img, (640, 640))
return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
def preprocess(images):
return [resize_img(img) for img in images]
# load_images_cy.pyx
import cv2
from random import randint
import numpy as np
cimport numpy as np
cimport cython
ctypedef np.uint8_t DTYPE_t
@cython.boundscheck(False)
@cython.wraparound(False)
cdef np.ndarray[DTYPE_t, ndim=3] get_img():
cdef int x = randint(640, 6144)
cdef int y = randint(640, 6144)
return np.random.rand(x,y, 3).astype(np.uint8)
cpdef list fetch_images(int n):
cdef int _;
return [get_img() for _ in range(n)]
cdef np.ndarray[DTYPE_t, ndim=2] resize_img(np.ndarray[DTYPE_t, ndim=3] img):
cdef np.ndarray[DTYPE_t, ndim=3] im;
im = cv2.resize(img, (640, 640))
return cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cpdef np.ndarray[DTYPE_t, ndim=3] preprocess(list images):
cdef np.ndarray[DTYPE_t, ndim=3] img;
cdef np.ndarray[DTYPE_t, ndim=3] collection = np.empty((len(images), 640, 640), dtype=np.uint8);
cdef int i;
for i, img in enumerate(images):
collection[i] = resize_img(img)
return collection
# main.py
import load_images_cy
import load_images
import timeit
images = load_images.fetch_images(20)
result_cy = timeit.timeit(lambda: load_images_cy.preprocess(images), number=20)
result_py = timeit.timeit(lambda: load_images.preprocess(images), number=20)
print(f'{result_py/result_cy} times faster')
输出:
0.9192241989059127 times faster
Cython 主要用于与 C 代码交互,并且更容易编写 Python extension modules。虽然可以通过 Cython 获得性能改进,但它并不打算成为 Python 代码的直接加速。
然而,PyPy 旨在为 Python 代码提供或多或少的直接加速。它提供了一个替代解释器,通常比 CPython、reference/default Python 实现更快。
此外,您的装饰师在这里:
@cython.boundscheck(False)
@cython.wraparound(False)
cdef np.ndarray[DTYPE_t, ndim=3] get_img():
...
仅适用于 get_img
- 不适用于以下任何其他功能。不确定那是不是故意的。这些之间不能有空行。
如果您想坚持使用 Cython,并通过它获得性能改进,请考虑更改 the compilation options,例如提供 -O2
或 -O3
。
我正在试验 Cython 和 OpenCV,并尝试对图像处理的性能进行基准测试。我已尝试尽可能多地优化我的 Cython 代码,但我的性能仍然较慢。我知道由于 OpenCV,大部分代码都是在 C 中执行的,但我希望使用 Cython 的 python 循环有更好的性能。谁能告诉我是否可以做些什么来改进它?以下是我的代码:
# load_images.py
import cv2
from random import randint
import numpy as np
def fetch_images(n):
def get_img():
x = randint(640, 6144)
y = randint(640, 6144)
return np.random.rand(x,y, 3).astype(np.uint8)
return [get_img() for _ in range(n)]
def resize_img(img):
img = cv2.resize(img, (640, 640))
return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
def preprocess(images):
return [resize_img(img) for img in images]
# load_images_cy.pyx
import cv2
from random import randint
import numpy as np
cimport numpy as np
cimport cython
ctypedef np.uint8_t DTYPE_t
@cython.boundscheck(False)
@cython.wraparound(False)
cdef np.ndarray[DTYPE_t, ndim=3] get_img():
cdef int x = randint(640, 6144)
cdef int y = randint(640, 6144)
return np.random.rand(x,y, 3).astype(np.uint8)
cpdef list fetch_images(int n):
cdef int _;
return [get_img() for _ in range(n)]
cdef np.ndarray[DTYPE_t, ndim=2] resize_img(np.ndarray[DTYPE_t, ndim=3] img):
cdef np.ndarray[DTYPE_t, ndim=3] im;
im = cv2.resize(img, (640, 640))
return cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cpdef np.ndarray[DTYPE_t, ndim=3] preprocess(list images):
cdef np.ndarray[DTYPE_t, ndim=3] img;
cdef np.ndarray[DTYPE_t, ndim=3] collection = np.empty((len(images), 640, 640), dtype=np.uint8);
cdef int i;
for i, img in enumerate(images):
collection[i] = resize_img(img)
return collection
# main.py
import load_images_cy
import load_images
import timeit
images = load_images.fetch_images(20)
result_cy = timeit.timeit(lambda: load_images_cy.preprocess(images), number=20)
result_py = timeit.timeit(lambda: load_images.preprocess(images), number=20)
print(f'{result_py/result_cy} times faster')
输出:
0.9192241989059127 times faster
Cython 主要用于与 C 代码交互,并且更容易编写 Python extension modules。虽然可以通过 Cython 获得性能改进,但它并不打算成为 Python 代码的直接加速。
然而,PyPy 旨在为 Python 代码提供或多或少的直接加速。它提供了一个替代解释器,通常比 CPython、reference/default Python 实现更快。
此外,您的装饰师在这里:
@cython.boundscheck(False)
@cython.wraparound(False)
cdef np.ndarray[DTYPE_t, ndim=3] get_img():
...
仅适用于 get_img
- 不适用于以下任何其他功能。不确定那是不是故意的。这些之间不能有空行。
如果您想坚持使用 Cython,并通过它获得性能改进,请考虑更改 the compilation options,例如提供 -O2
或 -O3
。