尝试定义cython方法会导致"此处不允许cdef语句"错误



我正在尝试使用EasyCython模块将纯Python模块转换为与Cython兼容的模块。
但是,问题是,在尝试执行EasyCython时,它失败并显示错误:

G:ProcpythonFV>easycython F_V.pyx
Compiling F_V.pyx because it changed.
[1/1] Cythonizing F_V.pyx
C:UsersRikaAnaconda3Libsite-packagesCythonCompilerMain.py:369: FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! File: G:ProcpythonFVF_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:UsersRikaAnaconda3Librunpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "C:UsersRikaAnaconda3Librunpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:UsersRikaAnaconda3Scriptseasycython.exe__main__.py", line 7, in <module>
File "C:UsersRikaAnaconda3Libsite-packagesbeginmain.py", line 54, in start
collector=self._collector)
File "C:UsersRikaAnaconda3Libsite-packagesbegincmdline.py", line 253, in apply_options
return_value = call_function(func, signature(ext), opts)
File "C:UsersRikaAnaconda3Libsite-packagesbegincmdline.py", line 236, in call_function
return func(*pargs, **kwargs)
File "C:UsersRikaAnaconda3Libsite-packageseasycythoneasycython.py", line 77, in main
ext_modules = cythonize(ext_modules),
File "C:UsersRikaAnaconda3Libsite-packagesCythonBuildDependencies.py", line 1102, in cythonize
cythonize_one(*args)
File "C:UsersRikaAnaconda3Libsite-packagesCythonBuildDependencies.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

我在这里错过了什么?

问题恰好是当使用 pythonclass时,也应该使用cdef。这种类称为Extension Type
来自 Cython 文档:

。Cython扩展类型定义看起来很像Python类 定义。在其中,您可以使用 def 语句来定义方法 可以从 Python 代码中调用。您甚至可以定义许多 特殊方法,如init((,就像在 Python 中一样。

注意:

这样做之后,为了能够在Python中使用我的类,我必须从它继承,而是使用继承的类。那是我必须做的:

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)
...

最新更新