我正在尝试将我的函数从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中使用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[:] Iext
和cdef 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
最终对我有用的是将float
和int[:]
更改为double
和double[:]
(感谢@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
答案 0 :(得分:1)
没有Iext
的编译时定义,我可以正确地构建和运行代码。编译时定义将取决于在笔记本中调用cython cell magic时Iext的值,并且在笔记本之外根本不起作用。
其他评论:
import pyximport; pyximport.install();
的使用是多余的,实际上是有害的,因为它是另一个构建系统,而您有基于setup.py
的构建。为了灵活性和易于调试,我还建议删除DEF
numSamples
。您可以从Iext.shape[0]
和“cdef”获取阵列的形状:
cdef int numSamples = Iext.shape[0]
编辑:要使第3点起作用,您必须:
在
中声明参数Iext
def hhModel(params, int[:] Iext, float dt, int Vref):
将本地数组声明为
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分配。