我正在研究一个优化问题,有 scipy.optimize
它的目的是计算一些3D地图。给定3个真实数据量 (vol0, vol1, vol2)
我的目标是估计3个参数的地图 (map_0, map_1, map_2)
通过体素强度的一些函数对其模型进行体素拟合。
到目前为止,这是我开始的想法。
import scipy
import numpy as np
from scipy.optimize import minimize
def objective (x,arg0,arg1):
vol_model0 = someFun( arg0[0], arg1, ... ) # *model value for arg0 which needs arg0[0] and arg1*
vol_model1 = someFun( arg0[1], arg1, ... ) # *model value for arg0 which needs arg0[1] and arg1*
vol_model2 = someFun( arg0[2], arg1, ... ) # *model value for arg0 which needs arg0[2] and arg1*
RSS = np.sum( [ np.power( ( arg0[0] - vol_model0 ), 2 )
+ np.power( ( arg0[1] - vol_model1 ), 2 )
+ np.power( ( arg0[2] - vol_model2 ), 2 ) ]
)
return RSS
arg1 = [1, 2, 3, 4]
vol0 = 5* np.zeros([100,100,100])
vol1 = 3* np.zeros([100,100,100])
vol2 = 4* np.zeros([100,100,100])
map_0 = np.zeros([100,100,100])
map_1 = np.zeros([100,100,100])
map_2 = np.zeros([100,100,100])
x0 = [5, 5, 5]
bnds = ( (1,10), (1, 10), (1, 10) )
for i0 in range(0,100):
for i1 in range(0,100):
for i2 in range(0,100):
arg0 = [ vol0[i0,i1,i2], \
vol1[i0,i1,i2], \
vol2[i0,i1,i2] \
]
res = minimize(objective, x0, args = (arg0,arg1), bounds = bnds)
map_0[i0,i1,i2], \
map_1[i0,i1,i2], \
map_2[i0,i1,i2] = res.x
我的问题是: 给定这个约束性优化问题,有没有办法让整个过程更快?嵌套的for循环需要很长的时间来完成.我想知道是否有办法将这个问题并行化或使其更快。
这个问题更多的是与 效率 的处理,比使用任何并发处理要好。
在进入任何进一步的步骤之前,让我提出几个要做的步骤。
1 ) 鉴于 1E6
调用将完成,优化所有的函数开销--因为每个 [us]
拯救的将会拯救另一个整体 [s]
在终点线上
2 ) 避免任何不相关的开销 (如果一个变量永远不会被重复使用,为什么要让python创建一个变量,维护一个变量名呢?你只是付出了成本,却没有得到任何回报)。)
3 ) 如果可能的话,numba-compile的代码,以提高性能&。objective()
函数,这里的每一个 [us]
削去 someFun( aFloat64, anInt64[], ... )
运行时将进一步节省您的 ~ 3 [s]
-的倍数。minimize()
-在终点线上再重复一遍... ... 值得这样做,不是吗?
>>> aClk.start(); _ = np.sum( # _______________________________ AVOID I/O on printing here by assignment into _ var
[ np.power( ( arg0[0] - v0 ), 2 ),
np.power( ( arg0[1] - v1 ), 2 ),
np.power( ( arg0[2] - v2 ), 2 )
] #___________________________ LIST-constructor overheads
); aClk.stop() # _______________.stop() the [us]-clock
225 [us]
164 [us]
188
157
175
199
201
201
171 [us]
>>> RSS = _
>>> RSS
0.16506628505715615
交叉验证方法的正确性。
>>> arg0_dif = arg0.copy()
>>> vV = np.ones( 3 ) * 1.23456789
>>> arg0_dif[:] -= vV[:]
>>> np.dot( arg0_dif, arg0_dif.T )
0.16506628505715615
+5x ~ +7x
FASTER CODE 。>>> aClk.start(); _ = np.dot( arg0_dif, arg0_dif.T ); aClk.stop()
39
38
28
28
27 [us] ~ +5x ~ +7x FASTER just by using more efficient way to produce the RSS calculations
"""
@numba.jit( signature = 'f8[:], f8[:], i8[:]', nogil = True, ... ) """
def aMoreEfficientObjectiveFUN( x, arg0, arg1 ):
###############################################################################################
# BEST 2 VECTORISE THE someFun() into someFunVECTORISED(),
# so as to work straight with arg0-vector and return vector of differences
#rg0[:] -= someFunVECTORISED( arg0, arg1, ... ) ##########################################
arg0[0] -= someFun( arg0[0], arg1, ... ) # *model value for arg0 which needs arg0[0] and arg1*
arg0[1] -= someFun( arg0[1], arg1, ... ) # *model value for arg0 which needs arg0[0] and arg1*
arg0[2] -= someFun( arg0[2], arg1, ... ) # *model value for arg0 which needs arg0[0] and arg1*
return np.dot( arg0, arg0.T ) # just this change gets ~ 5x ~ 7x FASTER processing ............
做好了这些,剩下的事情就简单了。
在一个案例中,所有修改后的附加间接费用。阿姆达赫定律 仍然可以证明支付所有的附加费用是合理的,即.XFER-process2main。 + SERDES (在发送参数前进行酸洗) + XFER-main2process + SERDES (在发送结果前进行酸洗) + XFER-process2main,即 multiprocessing
可以帮你分担 1E6
呼叫,完全独立的呼叫,并将结果回溯到了 "我"。map_tensor[:,i0,i1,i2]
~ ( map_0[i0,i1,i2], map_1[i0,i1,i2], map_2[i0,i1,i2] )
在所有附加的开销成本都没有得到证明的情况下,保持工作流不在几个进程之间分配,如果确实好奇和热衷于实验,可以尝试在一个基于线程的并发处理内运行这个,作为GIL-free处理(逃避,在 numpy
-的部件,不需要持有GIL锁,GIL驱动的成本重新。[SERIAL]
-化)可能会在叠加的并发处理上表现出一些延迟屏蔽。体内测试将证明这一点或表明,在python原生态系统中这样做没有额外的优势。
尾声 。
Would be nice & fair to give us your feedback on runtime improvements, partly from cod-efficiency ( 从最初的 ~ 27 minutes
(原状) -- -- 智能化之后 np.dot()
技巧 -- +在完全矢量化后的 objective( x, arg0, arg1 )
,其中 someFun()
可以处理向量,并智能地返回了 np.dot()
单独 -- +在一个 @numba.jit( ... )
装饰处理,如果这样的结果表明自己的效率进一步提高了