Python 2.7 Cython中的二项式迭代期望
我是Cython的新手。如何将下面名为Values的Python函数转换为Cython?在因子=2和i=60的情况下,在我的大Linux机器上需要2.8秒。目标是1秒以下,系数=2,i=360 这是密码。谢谢Python 2.7 Cython中的二项式迭代期望,python-2.7,numpy,cython,Python 2.7,Numpy,Cython,我是Cython的新手。如何将下面名为Values的Python函数转换为Cython?在因子=2和i=60的情况下,在我的大Linux机器上需要2.8秒。目标是1秒以下,系数=2,i=360 这是密码。谢谢 import numpy as np import itertools class Numeraire: def __init__(self, rate): self.rate = rate def __call__(self, timenext, tim
import numpy as np
import itertools
class Numeraire:
def __init__(self, rate):
self.rate = rate
def __call__(self, timenext, time, state):
return np.exp(-self.rate*(timenext - time))
def Values(values, i1, i0=0, numeraire=Numeraire(0.)):
factors=len(values.shape)
norm=0.5**factors
for i in np.arange(i1-1, i0-1, -1):
for j in itertools.product(np.arange(i+1), repeat=factors):
value = 0.
for k in itertools.product(np.arange(2), repeat=factors):
value += values[tuple(np.array(j) + np.array(k))]
values[j] = value*norm*numeraire(i+1, i, j)
return values
factors = 2
i = 60
values = np.ones([i+1]*factors)
Values(values, i, numeraire=Numeraire(0.05/12))
print values[(0,)*factors], np.exp(-0.05/12*i)
在使用Cython之前,应该使用Numpy优化代码。在这里,为循环对第三个和第二个内部
进行矢量化,可产生x40加速
In [1]: import numpy as np
...: import itertools
...:
...: # define Numaire and Values functions from the question above
...:
...: def Values2(values, i1, i0=0, numeraire=Numeraire(0.)):
...: factors=len(values.shape)
...: norm=0.5**factors
...: k = np.array(list(itertools.product(np.arange(2), repeat=factors)))
...: for i in np.arange(i1-1, i0-1, -1):
...: j = np.array(list(itertools.product(np.arange(i+1), repeat=factors)))
...: mask_all = j[:,:,np.newaxis] + k.T[np.newaxis, :, :]
...: mask_x, mask_y = np.swapaxes(mask_all, 2, 1).reshape(-1, 2).T
...:
...: values_tmp = values[mask_x, mask_y].reshape((j.shape[0], k.shape[0]))
...: values_tmp = values_tmp.sum(axis=1)
...: values[j[:,0], j[:,1]] = values_tmp*norm*numeraire(i+1, i, j)
...: return values
...:
...: factors = 2
...: i = 60
...: values = lambda : np.ones([i+1]*factors)
...: print values()[(0,)*factors], np.exp(-0.05/12*i)
...:
...: res = Values(values(), i, numeraire=Numeraire(0.05/12))
...: res2 = Values2(values(), i, numeraire=Numeraire(0.05/12))
...: np.testing.assert_allclose(res, res2)
...:
...: %timeit Values(values(), i, numeraire=Numeraire(0.05/12))
...: %timeit Values2(values(), i, numeraire=Numeraire(0.05/12))
...:
1.0 0.778800783071
1 loops, best of 3: 1.26 s per loop
10 loops, best of 3: 31.8 ms per loop
下一步是更换生产线
j = np.array(list(itertools.product(np.arange(i+1), repeat=factors)
与之相当的是Numpy,取自此(不太漂亮)
这导致x160的整体速度提高,代码在我的笔记本电脑上以1.2秒的时间运行i=360
和factors=2
在最后一个版本中,我认为如果你把它移植到Cython上,速度不会有多大提高,因为只剩下一个循环,而且只有360次迭代。相反,应该执行一些微调的Python/Numpy优化,以进一步提高速度
或者,您可以尝试将Cython应用于原始实现。但是,由于它基于itertools.product
,在循环中重复调用时速度很慢,Cython对此没有帮助。在使用Cython之前,您应该使用Numpy优化代码。在这里,为
循环对第三个和第二个内部进行矢量化,可产生x40加速
In [1]: import numpy as np
...: import itertools
...:
...: # define Numaire and Values functions from the question above
...:
...: def Values2(values, i1, i0=0, numeraire=Numeraire(0.)):
...: factors=len(values.shape)
...: norm=0.5**factors
...: k = np.array(list(itertools.product(np.arange(2), repeat=factors)))
...: for i in np.arange(i1-1, i0-1, -1):
...: j = np.array(list(itertools.product(np.arange(i+1), repeat=factors)))
...: mask_all = j[:,:,np.newaxis] + k.T[np.newaxis, :, :]
...: mask_x, mask_y = np.swapaxes(mask_all, 2, 1).reshape(-1, 2).T
...:
...: values_tmp = values[mask_x, mask_y].reshape((j.shape[0], k.shape[0]))
...: values_tmp = values_tmp.sum(axis=1)
...: values[j[:,0], j[:,1]] = values_tmp*norm*numeraire(i+1, i, j)
...: return values
...:
...: factors = 2
...: i = 60
...: values = lambda : np.ones([i+1]*factors)
...: print values()[(0,)*factors], np.exp(-0.05/12*i)
...:
...: res = Values(values(), i, numeraire=Numeraire(0.05/12))
...: res2 = Values2(values(), i, numeraire=Numeraire(0.05/12))
...: np.testing.assert_allclose(res, res2)
...:
...: %timeit Values(values(), i, numeraire=Numeraire(0.05/12))
...: %timeit Values2(values(), i, numeraire=Numeraire(0.05/12))
...:
1.0 0.778800783071
1 loops, best of 3: 1.26 s per loop
10 loops, best of 3: 31.8 ms per loop
下一步是更换生产线
j = np.array(list(itertools.product(np.arange(i+1), repeat=factors)
与之相当的是Numpy,取自此(不太漂亮)
这导致x160的整体速度提高,代码在我的笔记本电脑上以1.2秒的时间运行i=360
和factors=2
在最后一个版本中,我认为如果你把它移植到Cython上,速度不会有多大提高,因为只剩下一个循环,而且只有360次迭代。相反,应该执行一些微调的Python/Numpy优化,以进一步提高速度
或者,您可以尝试将Cython应用于原始实现。但是,因为它基于itertools.product
,在循环中重复调用时速度很慢,Cython对此没有帮助。下面是我的最新答案(没有Cython!),对于因子=2
,i=360
的情况,它在125毫秒内运行
import numpy as np
import itertools
slices = (slice(None, -1, None), slice(1, None, None))
def Expectation(values, numeraire, i, i0=0):
def Values(values, i):
factors = values.ndim
expect = np.zeros((i,)*factors)
for j in itertools.product(slices, repeat=factors):
expect += values[j]
return expect*0.5**factors*numeraire(i, i-1)
return reduce(Values, range(i, i0, -1), values)
class Numeraire:
def __init__(self, factors, rate=0):
self.factors = factors
self.rate = rate
def __call__(self, timenext, time):
return np.full((time+1,)*factors, np.exp(-self.rate*(timenext - time)))
factors = 2
i = 360
values, numeraire = np.ones((i+1,)*factors), Numeraire(factors, 0.05/12)
%timeit Expectation(values, numeraire, i)
Expectation(values, numeraire, i)[(0,)*factors], np.exp(-0.05/12*i)
这是我的最新答案(不是Cython!),对于factor=2
,i=360
的情况,它在125毫秒内运行
import numpy as np
import itertools
slices = (slice(None, -1, None), slice(1, None, None))
def Expectation(values, numeraire, i, i0=0):
def Values(values, i):
factors = values.ndim
expect = np.zeros((i,)*factors)
for j in itertools.product(slices, repeat=factors):
expect += values[j]
return expect*0.5**factors*numeraire(i, i-1)
return reduce(Values, range(i, i0, -1), values)
class Numeraire:
def __init__(self, factors, rate=0):
self.factors = factors
self.rate = rate
def __call__(self, timenext, time):
return np.full((time+1,)*factors, np.exp(-self.rate*(timenext - time)))
factors = 2
i = 360
values, numeraire = np.ones((i+1,)*factors), Numeraire(factors, 0.05/12)
%timeit Expectation(values, numeraire, i)
Expectation(values, numeraire, i)[(0,)*factors], np.exp(-0.05/12*i)
在引入Cython之前,您可能应该尝试使用标准的NumPy矢量化操作。特别是,除非你开始以矢量化的方式计算,或者将其移动到Cython中,否则你很快就会被numeraire
束缚。我认为如果你解释一下这段代码的作用,包括对小数组的影响,你会得到更多的帮助。对于您的示例,值
在左上角最小,在“圆圈”中在右侧和底部增加到1。为什么?因为它试图实现一个二项式晶格,用于期权定价。这里有一个参考:在引入Cython之前,您可能应该尝试使用标准的NumPy矢量化操作。特别是,除非你开始以矢量化的方式计算,或者将其移动到Cython中,否则你很快就会被numeraire
束缚。我认为如果你解释一下这段代码的作用,包括对小数组的影响,你会得到更多的帮助。对于您的示例,值
在左上角最小,在“圆圈”中在右侧和底部增加到1。为什么?因为它试图实现一个二项式晶格,用于期权定价。这里有一个参考:哇,谢谢你的精彩回答!在我的机器上,您的解决方案只需1.4秒!抱歉贪心,但是,您的函数是否可以修改为允许因子=1的情况,例如?@SteveSchulist Aww,是的,对不起,我没有意识到值
有因子
列,这确实是针对因子=2
的情况(即2D数组)而做的,并且需要推广到ND数组(或至少1D). 不幸的是,我不认为我可以在这周看…哇,谢谢你的精彩回答!在我的机器上,您的解决方案只需1.4秒!抱歉贪心,但是,您的函数是否可以修改为允许因子=1的情况,例如?@SteveSchulist Aww,是的,对不起,我没有意识到值
有因子
列,这确实是针对因子=2
的情况(即2D数组)而做的,并且需要推广到ND数组(或至少1D). 不幸的是,我不认为这周我可以调查。。。