尝试定义 cython 方法导致“此处不允许使用 cdef 语句”错误
Trying to define a cython method results in `cdef statement not allowed here` error
我正在尝试使用 EasyCython
模块将纯 Python 模块转换为与 Cython 兼容的模块。
然而,问题是,在尝试执行 EasyCython
时,它失败并显示错误:
G:\Proc\python\FV>easycython F_V.pyx
Compiling F_V.pyx because it changed.
[1/1] Cythonizing F_V.pyx
C:\Users\Rika\Anaconda3\Lib\site-packages\Cython\Compiler\Main.py:369: FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! File: G:\Proc\python\FV\F_V.pyx
tree = Parsing.p_module(s, pxd, full_module_name)
Error compiling Cython file:
------------------------------------------------------------
...
# or the network would mistake some one else for someother people! (for example someone has a profile image
# while the other doesnt, when confronted with the profile image, the network most likely find more features
# from the person that has already a profile image of him in the fbank (unless the change is noticeable
# this really can be a major issue)))
# @benchmark
cpdef _identify_id(self, input_img_embedding, list embedding_list, bint short_circut=True, bint accumulate_score=False):
^
------------------------------------------------------------
F_V.pyx:929:10: cdef statement not allowed here
Traceback (most recent call last):
File "C:\Users\Rika\Anaconda3\Lib\runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "C:\Users\Rika\Anaconda3\Lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:\Users\Rika\Anaconda3\Scripts\easycython.exe\__main__.py", line 7, in <module>
File "C:\Users\Rika\Anaconda3\Lib\site-packages\begin\main.py", line 54, in start
collector=self._collector)
File "C:\Users\Rika\Anaconda3\Lib\site-packages\begin\cmdline.py", line 253, in apply_options
return_value = call_function(func, signature(ext), opts)
File "C:\Users\Rika\Anaconda3\Lib\site-packages\begin\cmdline.py", line 236, in call_function
return func(*pargs, **kwargs)
File "C:\Users\Rika\Anaconda3\Lib\site-packages\easycython\easycython.py", line 77, in main
ext_modules = cythonize(ext_modules),
File "C:\Users\Rika\Anaconda3\Lib\site-packages\Cython\Build\Dependencies.py", line 1102, in cythonize
cythonize_one(*args)
File "C:\Users\Rika\Anaconda3\Lib\site-packages\Cython\Build\Dependencies.py", line 1225, in cythonize_one
raise CompileError(None, pyx_file)
Cython.Compiler.Errors.CompileError: F_V.pyx
这是用 cython 类型注释的两个方法。
#@benchmark
cpdef _identify_id(self, input_img_embedding, list embedding_list, bint short_circut=True, bint accumulate_score=False):
# These are the underlying types for the arguments and local variables used here
# input_img_embedding_type: <class 'torch.Tensor'> shape:torch.Size([1, 512])
# feature1 type: <class 'torch.Tensor'> shape: torch.Size([1, 512])
# x1 type: <class 'torch.Tensor'> shape: torch.Size([1, 512])
# cosine type: <class 'numpy.float32'> shape: ()
# np.clip(cosine) type: <class 'numpy.float64'> shape: ()
#
cdef float min_theta = 1000.0
cdef float total_theta = 0.0
cdef char* id_name = 'None' #None
for (name, feature1) in embedding_list:
id_name = name
x1 = feature1 / np.linalg.norm(feature1)
cosine = np.dot(input_img_embedding.squeeze(0), x1.squeeze(0))
cdef float cosine = np.clip(cosine, -1.0, 1.0)
cdef float theta = math.acos(cosine)
cdef float theta = theta * 180 / math.pi
if short_circut:
if theta < self._threshold:
return id_name, theta
if theta < min_theta:
min_theta = theta
total_theta += theta
# the elses from now on are for debugging purposes
if not short_circut and not accumulate_score:
if min_theta < self._threshold:
return id_name, min_theta
else:
return 'unknown', min_theta
if accumulate_score:
final_score = total_theta/len(embedding_list)
if final_score < self._threshold:
return id_name, final_score
else:
return 'unknown', final_score
return 'unknown', theta # min_theta
#@benchmark
cpdef _check_in_fbank(self, img):
"""Checks whether a given image is represented in the face bank.
Arguments:
img {torch.tensor} -- input image to be verified
Returns:
tuple(name, theta)
"""
# These are the underlying python types
# img type: <class 'torch.Tensor'> shape: torch.Size([3, 112, 112])
# feature0 type: <class 'torch.Tensor'> shape: torch.Size([1, 512])
# x0 type: <class 'torch.Tensor'> shape: torch.Size([1, 512])
with Benchmark_Block("model frwd took: "):
feature0 = self.model(img.unsqueeze(0)).cpu().detach()
x0 = feature0 / np.linalg.norm(feature0)
cdef list lst = []
for img_list in self._fbank_embeddings:
cdef tuple f = self._identify_id(x0, img_list, short_circut=self.short_circut, accumulate_score=self.accumulate_score)
lst.append(f)
cdef tuple min_val = min(lst, key=lambda t: t[1])
print(f'lst of returned results : {lst}. The minimum is: {min_val} in {len(self._fbank_embeddings)} enteries')
return min_val
我在这里错过了什么?
问题恰好是当使用 python class
时,也应该使用 cdef
。这种 class 称为 Extension Type
.
来自 Cython 文档:
... a Cython extension type definition looks a lot like a Python class
definition. Within it, you use the def statement to define methods
that can be called from Python code. You can even define many of the
special methods such as init() as you would in Python.
注:
这样做之后,为了能够在 Python 中使用我的 class,我不得不继承它,而不是使用继承的class。那是我必须做的:
cdef class MyClass():
def __init__(self, args)
...
cpdef func1(self,...):
...
cpdef func2(self, ....):
...
...
class MyClass2(MyClass):
def __init__(self, args):
super().__init__(args)
pass
在您的客户端代码中:
# use MyClass2 from now on
obj = MyClass2(args)
...
我正在尝试使用 EasyCython
模块将纯 Python 模块转换为与 Cython 兼容的模块。
然而,问题是,在尝试执行 EasyCython
时,它失败并显示错误:
G:\Proc\python\FV>easycython F_V.pyx
Compiling F_V.pyx because it changed.
[1/1] Cythonizing F_V.pyx
C:\Users\Rika\Anaconda3\Lib\site-packages\Cython\Compiler\Main.py:369: FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! File: G:\Proc\python\FV\F_V.pyx
tree = Parsing.p_module(s, pxd, full_module_name)
Error compiling Cython file:
------------------------------------------------------------
...
# or the network would mistake some one else for someother people! (for example someone has a profile image
# while the other doesnt, when confronted with the profile image, the network most likely find more features
# from the person that has already a profile image of him in the fbank (unless the change is noticeable
# this really can be a major issue)))
# @benchmark
cpdef _identify_id(self, input_img_embedding, list embedding_list, bint short_circut=True, bint accumulate_score=False):
^
------------------------------------------------------------
F_V.pyx:929:10: cdef statement not allowed here
Traceback (most recent call last):
File "C:\Users\Rika\Anaconda3\Lib\runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "C:\Users\Rika\Anaconda3\Lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:\Users\Rika\Anaconda3\Scripts\easycython.exe\__main__.py", line 7, in <module>
File "C:\Users\Rika\Anaconda3\Lib\site-packages\begin\main.py", line 54, in start
collector=self._collector)
File "C:\Users\Rika\Anaconda3\Lib\site-packages\begin\cmdline.py", line 253, in apply_options
return_value = call_function(func, signature(ext), opts)
File "C:\Users\Rika\Anaconda3\Lib\site-packages\begin\cmdline.py", line 236, in call_function
return func(*pargs, **kwargs)
File "C:\Users\Rika\Anaconda3\Lib\site-packages\easycython\easycython.py", line 77, in main
ext_modules = cythonize(ext_modules),
File "C:\Users\Rika\Anaconda3\Lib\site-packages\Cython\Build\Dependencies.py", line 1102, in cythonize
cythonize_one(*args)
File "C:\Users\Rika\Anaconda3\Lib\site-packages\Cython\Build\Dependencies.py", line 1225, in cythonize_one
raise CompileError(None, pyx_file)
Cython.Compiler.Errors.CompileError: F_V.pyx
这是用 cython 类型注释的两个方法。
#@benchmark
cpdef _identify_id(self, input_img_embedding, list embedding_list, bint short_circut=True, bint accumulate_score=False):
# These are the underlying types for the arguments and local variables used here
# input_img_embedding_type: <class 'torch.Tensor'> shape:torch.Size([1, 512])
# feature1 type: <class 'torch.Tensor'> shape: torch.Size([1, 512])
# x1 type: <class 'torch.Tensor'> shape: torch.Size([1, 512])
# cosine type: <class 'numpy.float32'> shape: ()
# np.clip(cosine) type: <class 'numpy.float64'> shape: ()
#
cdef float min_theta = 1000.0
cdef float total_theta = 0.0
cdef char* id_name = 'None' #None
for (name, feature1) in embedding_list:
id_name = name
x1 = feature1 / np.linalg.norm(feature1)
cosine = np.dot(input_img_embedding.squeeze(0), x1.squeeze(0))
cdef float cosine = np.clip(cosine, -1.0, 1.0)
cdef float theta = math.acos(cosine)
cdef float theta = theta * 180 / math.pi
if short_circut:
if theta < self._threshold:
return id_name, theta
if theta < min_theta:
min_theta = theta
total_theta += theta
# the elses from now on are for debugging purposes
if not short_circut and not accumulate_score:
if min_theta < self._threshold:
return id_name, min_theta
else:
return 'unknown', min_theta
if accumulate_score:
final_score = total_theta/len(embedding_list)
if final_score < self._threshold:
return id_name, final_score
else:
return 'unknown', final_score
return 'unknown', theta # min_theta
#@benchmark
cpdef _check_in_fbank(self, img):
"""Checks whether a given image is represented in the face bank.
Arguments:
img {torch.tensor} -- input image to be verified
Returns:
tuple(name, theta)
"""
# These are the underlying python types
# img type: <class 'torch.Tensor'> shape: torch.Size([3, 112, 112])
# feature0 type: <class 'torch.Tensor'> shape: torch.Size([1, 512])
# x0 type: <class 'torch.Tensor'> shape: torch.Size([1, 512])
with Benchmark_Block("model frwd took: "):
feature0 = self.model(img.unsqueeze(0)).cpu().detach()
x0 = feature0 / np.linalg.norm(feature0)
cdef list lst = []
for img_list in self._fbank_embeddings:
cdef tuple f = self._identify_id(x0, img_list, short_circut=self.short_circut, accumulate_score=self.accumulate_score)
lst.append(f)
cdef tuple min_val = min(lst, key=lambda t: t[1])
print(f'lst of returned results : {lst}. The minimum is: {min_val} in {len(self._fbank_embeddings)} enteries')
return min_val
我在这里错过了什么?
问题恰好是当使用 python class
时,也应该使用 cdef
。这种 class 称为 Extension Type
.
来自 Cython 文档:
... a Cython extension type definition looks a lot like a Python class definition. Within it, you use the def statement to define methods that can be called from Python code. You can even define many of the special methods such as init() as you would in Python.
注:
这样做之后,为了能够在 Python 中使用我的 class,我不得不继承它,而不是使用继承的class。那是我必须做的:
cdef class MyClass():
def __init__(self, args)
...
cpdef func1(self,...):
...
cpdef func2(self, ....):
...
...
class MyClass2(MyClass):
def __init__(self, args):
super().__init__(args)
pass
在您的客户端代码中:
# use MyClass2 from now on
obj = MyClass2(args)
...