我有以下代码执行规范化的互相关,寻找python中两个信号的相似性:
def normcorr(template,srchspace):
template=(template-np.mean(template))/(np.std(template)*len(template)) # Normalize template
CCnorm=srchspace.copy()
CCnorm=CCnorm[np.shape(template)[0]:] # trim CC matrix
for a in range(len(CCnorm)):
s=srchspace[a:a+np.shape(template)[0]]
sp=(s-np.mean(s))/np.std(s)
CCnorm[a]=numpy.sum(numpy.multiply(template,sp))
return CCnorm
但你可以想象它太慢了。查看cython文档,在原始python中执行循环时,可以承诺大幅提高速度。所以我尝试编写一些cython代码,其中包含如下变量的数据类型:
from __future__ import division
import numpy as np
import math as m
cimport numpy as np
cimport cython
def normcorr(np.ndarray[np.float32_t, ndim=1] template,np.ndarray[np.float32_t, ndim=1] srchspace):
cdef int a
cdef np.ndarray[np.float32_t, ndim=1] s
cdef np.ndarray[np.float32_t, ndim=1] sp
cdef np.ndarray[np.float32_t, ndim=1] CCnorm
template=(template-np.mean(template))/(np.std(template)*len(template))
CCnorm=srchspace.copy()
CCnorm=CCnorm[len(template):]
for a in range(len(CCnorm)):
s=srchspace[a:a+len(template)]
sp=(s-np.mean(s))/np.std(s)
CCnorm[a]=np.sum(np.multiply(template,sp))
return CCnorm
但是一旦我编译它,代码实际上比纯python代码运行得慢。我发现这里(How to call numpy/scipy C functions from Cython directly, without Python call overhead?)从cython调用numpy可能会显着减慢代码速度,这是我的代码的问题,在这种情况下我必须定义内联函数来替换所有对np的调用,或者是否有东西否则我错了,我错过了?
答案 0 :(得分:3)
因为你在cython循环中调用numpy函数,所以不会有速度提升。
如果您使用pandas,可以在numpy中使用roll_mean()
和roll_std()
以及convolve()
来快速进行计算,以下是代码:
import numpy as np
import pandas as pd
np.random.seed()
def normcorr(template,srchspace):
template=(template-np.mean(template))/(np.std(template)*len(template)) # Normalize template
CCnorm=srchspace.copy()
CCnorm=CCnorm[np.shape(template)[0]:] # trim CC matrix
for a in range(len(CCnorm)):
s=srchspace[a:a+np.shape(template)[0]]
sp=(s-np.mean(s))/np.std(s)
CCnorm[a]=np.sum(np.multiply(template,sp))
return CCnorm
def fast_normcorr(t, s):
n = len(t)
nt = (t-np.mean(t))/(np.std(t)*n)
sum_nt = nt.sum()
a = pd.rolling_mean(s, n)[n-1:-1]
b = pd.rolling_std(s, n)[n-1:-1]
b *= np.sqrt((n-1.0) / n)
c = np.convolve(nt[::-1], s, mode="valid")[:-1]
result = (c - sum_nt * a) / b
return result
n = 100
m = 1000
t = np.random.rand(n)
s = np.random.rand(m)
r1 = normcorr(t, s)
r2 = fast_normcorr(t, s)
assert np.allclose(r1, r2)
您可以检查结果r1
和r2
是否相同。这是timeit
测试:
%timeit normcorr(t, s)
%timeit fast_normcorr(t, s)
输出:
10 loops, best of 3: 59 ms per loop
1000 loops, best of 3: 273 µs per loop
它快了200倍。
答案 1 :(得分:1)
如果使用cython -a
编译代码并查看HTML输出,您将看到有很多Python开销。
@cython.boundscheck(False)
@cython.cdivision(True) # Don't check for divisions by 0
def normcorr(np.ndarray[np.float32_t, ndim=1] template,np.ndarray[np.float32_t, ndim=1] srchspace):
cdef int a
cdef int N = template.shape[0]
cdef NCC = srchspace.shape[0] - N
cdef np.ndarray[np.float32_t, ndim=1] s
cdef np.ndarray[np.float32_t, ndim=1] sp
cdef np.ndarray[np.float32_t, ndim=1] CCnorm
template=(template - template.mean()) / (template.std() * N)
CCnorm=srchspace[N:].copy() # You don't need to copy the whole array
for a in xrange(NCC): # Use xrange in Python2
s=srchspace[a:a+N]
sp=(s-np.mean(s)) / np.std(s)
CCnorm[a]= (template * sp).sum()
return CCnorm
为了提高性能,您可以优化最后两行:
@cython.boundscheck(False)
@cython.cdivision(True)
cdef multiply_by_normalised(np.ndarray[np.float32_t, ndim=1] template, np.ndarray[np.float32_t, ndim=1] s):
cdef int i
cdef int N = template.shape[0]
cdef float_32_t mean, std, out = 0
mean = s.mean()
std = s.std()
for i in xrange(N):
out += (s[i] - mean) / std * template[i]
return out
如果您仍需要挤出更多时间,可以使用比Numpy更快的瓶颈mean
和std
函数。