【问题标题】:Cython: function call throws error " function needs keyword-only argument"Cython:函数调用抛出错误“函数需要仅关键字参数”
【发布时间】:2017-10-24 15:43:02
【问题描述】:

我正在尝试将我的函数从 Python 转换为 Cython,以显着提高其速度。但是,如果我调用它,它会引发此错误:

hhModel([56,-70,-55,120,36,0.3], Iext, 0.01, -30)       # stim is a 1x200.000 nd.array of the form [0, 0, ..., 1, 1, ..., 0, 0]

TypeError: hhModel() needs keyword-only argument Iext

这可能与Iext的变量类型有关。我试图给它一个列表或一个整数,而不是相同的错误消息。我对 python 和 cython 很陌生,我无法有意义地解释错误消息。我将在下面向您展示我的函数调用以及我的 hhModel(在屏幕截图中:type(stim) 必须是 type(iext),抱歉)。

创建变量“Iext”

# create stimulus vector
def create_stimulus_vector(nA, stimulus_length, zero_length, dt, plotflag):
    "create_stimulus_vector(2.5[nA], 1000[ms], 500[ms], 0.01[step/ms])"
    start           = int(zero_length*1/dt)                      #  5.000
    length          = int(stimulus_length*1/dt+2*start)          # 20.000
    stop            = length-start                               # 15.000  
    stimulus_vector = np.zeros(length)                           # array([ 0.,  0.,  0., ...,  0.,  0.,  0.])
    stimulus_vector[start:stop] = nA                             # array([ 0.,  0.,  1., ...,  1.,  0.,  0.])
    if plotflag:
        plt.plot(np.linspace(0, length*dt/1000, length), stimulus_vector)
        plt.title("One Stimulus Vector")
        plt.ylabel("[nA]")
        plt.xlabel("[s]")
    return stimulus_vector

Iext = create_stimulus_vector(2.5, 1000, 500, 0.01, 1);

Cython 函数 .pyx

from math import exp
import numpy as np

def hhModel(params, Iext, float dt, int Vref):

    ## Unwrap params argument: these variables are going to be optimized
    cdef float ENa = params[0]
    cdef float EK  = params[1]
    cdef float EL  = params[2]
    cdef float GNa = params[3]
    cdef float GK  = params[4]
    cdef float GL  = params[5]

    ## Input paramters
    # I    : a list containing external current steps, your stimulus vector [nA]
    # dt   : a crazy time parameter [ms]
    # Vref : reference potential [mV]

    def alphaM(float v, float vr):       return 0.1 * (v-vr-25) / ( 1 - exp(-(v-vr-25)/10) )
    def betaM(float v, float vr):        return 4 * exp(-(v-vr)/18)
    def alphaH(float v, float vr):       return 0.07 * exp(-(v-vr)/20)
    def betaH(float v, float vr):        return 1 / ( 1 + exp( -(v-vr-30)/10 ) )
    def alphaN(float v, float vr):       return 0.01 * (v-vr-10) / ( 1 - exp(-(v-vr-10)/10) )
    def betaN(float v, float vr):        return 0.125 * exp(-(v-vr)/80)

    ## steady-state values and time constants of m,h,n

    def m_infty(float v, float vr):      return alphaM(v,vr) / ( alphaM(v,vr) + betaM(v,vr) )
    def h_infty(float v, float vr):      return alphaH(v,vr) / ( alphaH(v,vr) + betaH(v,vr) )
    def n_infty(float v, float vr):      return alphaN(v,vr) / ( alphaN(v,vr) + betaN(v,vr) )

    ## parameters
    cdef float Cm, gK, gL, INa, IK, IL, dv_dt, dm_dt, dh_dt, dn_dt, aM, bM, aH, bH, aN, bN
    cdef float Smemb = 4000    # [um^2] surface area of the membrane
    cdef float Cmemb = 1       # [uF/cm^2] membrane capacitance density
    Cm = Cmemb * Smemb * 1e-8  # [uF] membrane capacitance

    gNa = GNa * Smemb * 1e-8   # Na conductance [mS]
    gK  = GK  * Smemb * 1e-8   # K conductance [mS]
    gL  = GL  * Smemb * 1e-8   # leak conductance [mS]

    # numSamples = int(T/dt);
    # DEF numSamples = len(Iext);
    DEF numSamples = 200000

    # initial values
    cdef float v[numSamples]
    cdef float m[numSamples]
    cdef float h[numSamples]
    cdef float n[numSamples]

    v[0]  = Vref                    # initial membrane potential
    m[0]  = m_infty(v[0], Vref)     # initial m
    h[0]  = h_infty(v[0], Vref)     # initial h
    n[0]  = n_infty(v[0], Vref)     # initial n

    ## calculate membrane response step-by-step
    for j in range(0, numSamples-1):

        DEF stim = Iext[j]

        # ionic currents: g[mS] * V[mV] = I[uA]
        INa = gNa * m[j]*m[j]*m[j] * h[j] * (ENa-v[j])
        IK = gK * n[j]*n[j]*n[j]*n[j] * (EK-v[j])
        IL = gL * (EL-v[j])

        # derivatives
        # I[uA] / C[uF] * dt[ms] = dv[mV]
        dv_dt = ( INa + IK + IL + stim*1e-3) / Cm;

        aM = 0.1 * (v[j]-Vref-25) / ( 1 - exp(-(v[j]-Vref-25)/10))
        bM = 4 * exp(-(v[j]-Vref)/18)
        aH = 0.07 * exp(-(v[j]-Vref)/20)
        bH = 1 / ( 1 + exp( -(v[j]-Vref-30)/10 ) )
        aN = 0.01 * (v[j]-Vref-10) / ( 1 - exp(-(v[j]-Vref-10)/10) )
        bN = 0.125 * exp(-(v[j]-Vref)/80)

        dm_dt = (1-m[j])* aM - m[j]*bM
        dh_dt = (1-h[j])* aH - h[j]*bH
        dn_dt = (1-n[j])* aN - n[j]*bN

        # calculate next step
        v[j+1] = (v[j] + dv_dt * dt)
        m[j+1] = (m[j] + dm_dt * dt)
        h[j+1] = (h[j] + dh_dt * dt)
        n[j+1] = (n[j] + dn_dt * dt)

    return v

编辑:

重启内核后错误仍然存​​在。我在 Jupyter Notebook(通过 Anaconda 安装)中使用 Python 3.6.2 和 IPython 6.1.0。我正在使用 Windows 10。

创建 .pyx 文件

%run -i setup.py build_ext --inplace

# import cyton function to python
import pyximport; pyximport.install();
from hh_vers_vector import hhModel

设置 .py 文件

from distutils.core import setup
from Cython.Build import cythonize

setup(
    ext_modules=cythonize("hh_vers_vector.pyx"),
)

编辑二

引入int[:] Iextcdef float[:] v = np.zeros(numSamples)后又遇到一个新的错误,即:

Iext = create_stimulus_vector(2.5, 1000, 500, 0.01, 1);
hhModel([56,-70,-55,120,36,0], Iext, 0.01, -30)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
C:\ownCloud\Masterarbeit\python\setup.py in <module>()
----> 1 hhModel([56,-70,-55,120,36,0], Iext, 0.01, -30)

C:\ownCloud\Masterarbeit\python\hh_vers02.pyx in hh_vers02.hhModel()
      8 
      9 
---> 10 def hhModel(params, int[:] Iext, float dt, int Vref):
     11 
     12     ## Unwrap params argument: these variables are going to be optimized

ValueError: Buffer dtype mismatch, expected 'int' but got 'double'

现在是我代码的重要部分

from math import exp
import numpy as np

def hhModel(params, int[:] Iext, float dt, int Vref):
    cdef int numSamples = Iext.shape[0]
    cdef float[:] v = np.zeros(numSamples)
    cdef float[:] m = np.zeros(numSamples)
    cdef float[:] h = np.zeros(numSamples)
    cdef float[:] n = np.zeros(numSamples)

编辑三

最终对我有用的是将floatint[:] 更改为doubledouble[:](感谢@Pierre de Buyl)

import numpy as np

def hhModel(params, double[:] Iext, float dt, int Vref):
    cdef int numSamples = Iext.shape[0]
    cdef double[:] v = np.zeros(numSamples)
    cdef double[:] m = np.zeros(numSamples)
    cdef double[:] h = np.zeros(numSamples)
    cdef double[:] n = np.zeros(numSamples)

然而,当对我的 .pyx 文件进行 cythonizing 时,Python 仍然会引发警告。由于该功能仍然有效,因此我认为理解它的含义是一种奖励(尽管会很有用)。

%run -i setup.py build_ext --inplace

[1/1] Cythonizing hh_vers02.pyx
warning: hh_vers02.pyx:71:23: Index should be typed for more efficient access

【问题讨论】:

  • 请用复制粘贴的文字替换图片。另外,为了在您使用笔记本时更好地诊断,请检查重新启动内核后错误是否仍然存在。另外,能否给出Python和Cython的版本?
  • 谢谢!我编辑了帖子,希望您拥有所需的所有信息。否则我很乐意再次编辑我的帖子。
  • 您不需要在安装文件中使用“pyximport”。您已经可以删除此部分(等待进一步信息时)。
  • DEF stim = Iext[j] 将硬编码 Iext 的值,而不是将其用作变量。编译时定义在这里用处不大。
  • 所以,如果没有Iext 的编译时定义,我可以让它工作。如果这对你有用,我会写这个作为答案。

标签: python cython


【解决方案1】:

没有Iext 的编译时定义,我可以正确构建和运行代码。编译时定义将取决于在笔记本内调用 cython 单元魔术时 Iext 的值,并且在笔记本外根本不起作用。

其他说明:

  1. 使用import pyximport; pyximport.install(); 是多余的,实际上是有害的,因为它是另一个构建系统,而您有一个基于setup.py 的构建。
  2. 我建议查看 Cython 的 documentation for working with NumPy 以及 typed memoryviews 上的更多最新页面。
  3. 为了灵活性和调试方便,我还建议删除DEFnumSamples。您可以从Iext.shape[0] 和“cdef”获取数组的形状:

    cdef int numSamples = Iext.shape[0]
    

编辑:要使第 3 点起作用,您必须:

  1. 将参数Iext 声明为

    def hhModel(params, int[:] Iext, float dt, int Vref):
    
  2. 将本地数组声明为

    cdef float[:] v = np.zeros(numSamples)
    cdef float[:] m = np.zeros(numSamples)
    cdef float[:] h = np.zeros(numSamples)
    cdef float[:] n = np.zeros(numSamples)
    

因此它们由 Cython “编译”,但内存由 NumPy 分配。

【讨论】:

  • 您的回答很有帮助,谢谢!我对第 3 点还有一个问题),我很高兴你也强调了这一点。如果我从DEF numSamples 更改为cdef int numSamplescdef float v[numSamples] 将抛出Not allowed in a constant expression。但是即使使用DEF numSampleslen(Iext)Iext.shape[0] 都会抛出TypeError: 'NoneType' object is not subscriptable。你知道如何给Iext 指定合适的类型吗?将其作为函数的输入时,它是一个 nd.array。
  • 看看你的参考,听起来像np.ndarray[DTYPE_t, ndim=1] Iextctypedef np.int_t DTYPE_t 应该做的工作,但它没有。
  • 我添加了缺少的步骤。
  • 酷!难道Iext 不包含int 值?我得到ValueError: Buffer dtype mismatch, expected 'int' but got 'double'。将int[:] Iext 更改为double[:] Iext 也无济于事。
  • 在函数的开头添加cdef int j。当 Cython 知道循环索引是一个 int 时,它可以加快数组访问速度。
猜你喜欢
  • 2019-04-23
  • 1970-01-01
  • 2019-09-23
  • 2022-01-23
  • 2016-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-01
相关资源
最近更新 更多