Cython:函数调用抛出错误“function needs keyword-only argument”

时间:2017-10-23 11:08:30

标签: python cython

我正在尝试将我的函数从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),对不起)。

enter image description here

创建变量“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中使用Python 3.6.2和IPython 6.1.0(通过Anaconda安装)。我正在使用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"),
)

编辑II

在介绍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)

编辑III

最终对我有用的是将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文件进行cython化时,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

1 个答案:

答案 0 :(得分:1)

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

其他评论:

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

    cdef int numSamples = Iext.shape[0]
    
  4. 编辑:要使第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)
      
    3. 因此它们由Cython“编译”,但内存由NumPy分配。