正如this answer所述,我尝试使用joblib并行训练多个scikit-learn模型。
import joblib
import numpy
from sklearn import tree, linear_model
classifierParams = {
"Decision Tree": (tree.DecisionTreeClassifier, {}),''
"Logistic Regression" : (linear_model.LogisticRegression, {})
}
XTrain = numpy.array([[1,2,3],[4,5,6]])
yTrain = numpy.array([0, 1])
def trainModel(name, clazz, params, XTrain, yTrain):
print("training ", name)
model = clazz(**params)
model.fit(XTrain, yTrain)
return model
joblib.Parallel(n_jobs=4)(joblib.delayed(trainModel)(name, clazz, params, XTrain, yTrain) for (name, (clazz, params)) in classifierParams.items())
然而,对最后一行的调用需要很长时间而不使用CPU,实际上它似乎只是阻塞而且永远不会返回任何东西。我的错是什么?
XTrain
中包含非常少量数据的测试表明,在多个进程中复制numpy数组不是延迟的原因。
答案 0 :(得分:-5)
检查CPU%
以及其他资源'这个节点的状态数字。
看完你的个人资料是一个了不起的时刻,先生:
问题 IS 深受尊重对基本计算机科学+算法规则的影响。
问题不要求强大的科学背景,但常识。
问题不任何特别是大数据但需要闻到事情的实际效果。
第1步:
永远不要雇佣或解雇每一位顾问,不尊重事实(上面提到的答案没有提出任何建议,任何承诺的授予越少)。忽视事实可能是一个" 成功的罪"在PR / MARCOM /广告/媒体业务(如果客户容忍这种不诚实和/或操纵习惯),但不是在科学公平的量化领域。 这是不可原谅的。
第2步:
永远不要雇佣或解雇每位顾问,他们声称拥有软件架构方面的经验, 尤其是关于......大数据的解决方案 ,但不关注积累的块状结构一旦处理开始分布在某些硬件和软件资源池中,系统架构的每个相应元素将引入的所有附加开销成本。这是不可原谅的。
第3步:
永远不要雇佣或解雇每一位顾问,一旦事实不符合她/他的意愿,他们就会变得被动,并开始指责已经伸出援助之手的其他知识渊博的人,而不是"改善(他们)沟通技巧" 而不是从错误中学习。当然,技能可能有助于以其他方式表达明显的错误,然而,巨大的错误将仍然是巨大的错误,每个科学家,对她/他的科学头衔公平,应该从不诉诸于攻击一个帮助的同事,而是一个接一个地开始寻找错误的根本原因。这--- ---
@sascha ... May I suggest you take little a break from stackoverflow to cool off, work a little on your interpersonal communication skills
---对于@sascha而言,只不过是一种直接的,在理智上令人无法接受的令人讨厌的犯规。
语法构造函数的命令式形式点燃了大量的活动:
joblib.Parallel( n_jobs = <N> )( joblib.delayed( <aFunction> )
( <anOrderedSetOfFunParameters> )
for ( <anOrderedSetOfIteratorParams> )
in <anIterator>
)
至少猜测会发生什么,科学公平的方法是测试几个代表性案例,对其实际执行进行基准测试,收集定量支持的事实,并对行为模型及其对CPU_core-count的主要依赖性进行假设, RAM大小,<aFunction>
- 复杂性和资源分配信封等。
def a_NOP_FUN( aNeverConsumedPAR ):
""" __doc__
The intent of this FUN() is indeed to do nothing at all,
so as to be able to benchmark
all the process-instantiation
add-on overhead costs.
"""
pass
##############################################################
### A NAIVE TEST BENCH
##############################################################
from zmq import Stopwatch; aClk = Stopwatch()
JOBS_TO_SPAWN = 4 # TUNE: 1, 2, 4, 5, 10, ..
RUNS_TO_RUN = 10 # TUNE: 10, 20, 50, 100, 200, 500, 1000, ..
try:
aClk.start()
joblib.Parallel( n_jobs = JOBS_TO_SPAWN
)( joblib.delayed( a_NOP_FUN )
( aSoFunPAR )
for ( aSoFunPAR )
in range( RUNS_TO_RUN )
)
except:
pass
finally:
try:
_ = aClk.stop()
except:
_ = -1
pass
print( "CLK:: {0:_>24d} [us] @{1: >3d} run{2: >5d} RUNS".format( _,
JOBS_TO_SPAWN,
RUNS_TO_RUN
)
)
通过[ RUNS_TO_RUN, JOBS_TO_SPAWN]
- 笛卡尔空间DataPoints的合理缩放2D景观收集了关于此NOP案例的足够代表性数据,以便至少生成实际系统启动成本的第一手经验实际上本质上是空的过程&#39;与强制性指示 joblib.Parallel(...)( joblib.delayed(...) )
-syntax构造函数相关的开销工作负载,仅产生一些joblib
- 管理 a_NOP_FUN()
{ strong>实例。
让我们同意所有现实问题,包括机器学习模型,都是更复杂的工具,刚刚测试过的 a_NOP_FUN()
,而在这两种情况下,你必须支付已经基准的开销成本(即使是为了获得真正的零产品而付出的代价)。
因此,从这个最简单的案例中可以得出一个科学公平,严谨的工作,已经显示了所有相关设置开销的基准成本最小joblib.Parallel()
惩罚正弦 - 非 - 转发到真实世界算法所在的方向 - 最佳,然后向测试循环中添加一些越来越大的&#34; - 大小:< / p>
def a_NOP_FUN_WITH_JUST_A_MEM_ALLOCATOR( aNeverConsumedPAR ):
""" __doc__
The intent of this FUN() is to do nothing but
a MEM-allocation
so as to be able to benchmark
all the process-instantiation
add-on overhead costs.
"""
import numpy as np # yes, deferred import, libs do defer imports
SIZE1D = 1000 # here, feel free to be as keen as needed
aMemALLOC = np.zeros( ( SIZE1D, # so as to set
SIZE1D, # realistic ceilings
SIZE1D, # as how big the "Big Data"
SIZE1D # may indeed grow into
),
dtype = np.float64,
order = 'F'
) # .ALLOC + .SET
aMemALLOC[2,3,4,5] = 8.7654321 # .SET
aMemALLOC[3,3,4,5] = 1.2345678 # .SET
return aMemALLOC[2:3,3,4,5]
再次
通过在 a_NOP_FUN_WITH_JUST_A_MEM_ALLOCATOR()
-scaling, SIZE1D
-scaling的合理广泛范围内运行[ RUNS_TO_RUN, JOBS_TO_SPAWN]
来收集有关实际远程处理MEM分配成本的足够代表性的定量数据>
再次
在joblib.Parallel()
- 笛卡尔空间DataPoints的合理缩放的2D景观上,以便在def a_NOP_FUN_WITH_SOME_MEM_DATAFLOW( aNeverConsumedPAR ):
""" __doc__
The intent of this FUN() is to do nothing but
a MEM-allocation plus some Data MOVs
so as to be able to benchmark
all the process-instantiation + MEM OPs
add-on overhead costs.
"""
import numpy as np # yes, deferred import, libs do defer imports
SIZE1D = 1000 # here, feel free to be as keen as needed
aMemALLOC = np.ones( ( SIZE1D, # so as to set
SIZE1D, # realistic ceilings
SIZE1D, # as how big the "Big Data"
SIZE1D # may indeed grow into
),
dtype = np.float64,
order = 'F'
) # .ALLOC + .SET
aMemALLOC[2,3,4,5] = 8.7654321 # .SET
aMemALLOC[3,3,4,5] = 1.2345678 # .SET
aMemALLOC[:,:,:,:]*= 0.1234567
aMemALLOC[:,3,4,:]+= aMemALLOC[4,5,:,:]
aMemALLOC[2,:,4,:]+= aMemALLOC[:,5,6,:]
aMemALLOC[3,3,:,:]+= aMemALLOC[:,:,6,7]
aMemALLOC[:,3,:,5]+= aMemALLOC[4,:,:,7]
return aMemALLOC[2:3,3,4,5]
工具内的扩展黑盒PROCESS_under_TEST实验中触及性能缩放中的新维度,留下其魔法尚未开放。
~ 100 .. 300 [ns]
人们可能很快就会注意到,不仅静态大小很重要,而且MEM-transport BANDWIDTH (硬件硬连线)也会引发问题,因为将数据从/向CPU移动到/来自MEM的成本比def a_CPU_1_CORE_BURNER_FUN( aNeverConsumedPAR ):
""" __doc__
The intent of this FUN() is to do nothing but
add some CPU-load
to a MEM-allocation plus some Data MOVs
so as to be able to benchmark
all the process-instantiation + MEM OPs
add-on overhead costs.
"""
import numpy as np # yes, deferred import, libs do defer imports
SIZE1D = 1000 # here, feel free to be as keen as needed
aMemALLOC = np.ones( ( SIZE1D, # so as to set
SIZE1D, # realistic ceilings
SIZE1D, # as how big the "Big Data"
SIZE1D # may indeed grow into
),
dtype = np.float64,
order = 'F'
) # .ALLOC + .SET
aMemALLOC[2,3,4,5] = 8.7654321 # .SET
aMemALLOC[3,3,4,5] = 1.2345678 # .SET
aMemALLOC[:,:,:,:]*= 0.1234567
aMemALLOC[:,3,4,:]+= aMemALLOC[4,5,:,:]
aMemALLOC[2,:,4,:]+= aMemALLOC[:,5,6,:]
aMemALLOC[3,3,:,:]+= aMemALLOC[:,:,6,7]
aMemALLOC[:,3,:,5]+= aMemALLOC[4,:,:,7]
aMemALLOC[:,:,:,:]+= int( [ np.math.factorial( x + aMemALLOC[-1,-1,-1] )
for x in range( 1005 )
][-1]
/ [ np.math.factorial( y + aMemALLOC[ 1, 1, 1] )
for y in range( 1000 )
][-1]
)
return aMemALLOC[2:3,3,4,5]
好,比任何智能改组的几个字节都要好......#34;内部&#34; CPU_core,{CPU_core_private | CPU_core_shared | CPU_die_shared} -cache层次结构 - 单独(和任何非本地NUMA转移表现出相同数量级的附加痛苦)。
所以让我们开始燃烧油!
如果以上所有内容都能很好地开始闻到引擎盖下的东西是如何工作的,那么这将变得丑陋和肮脏。
{ aMlModelSPACE, aSetOfHyperParameterSPACE, aDataSET }
与机器学习多D空间领域中常见的有效载荷级别相比, O( N )
- 状态空间的所有维度都会影响到所需处理的范围(一些具有O( N.logN )
,一些其他~ 15+ [ms]
复杂度),其中几乎立即,精心设计,不仅仅是一个CPU_core很快就会被利用一个单一的工作&#34; -being run。
一旦天真(读取资源 - 使用不协调)CPU负载混合物开始行动,并且当任务相关的CPU负载的混合开始变得混乱时,一个确实令人讨厌的气味开始了(读取资源 - 使用O / S调度程序进程碰巧争用通用(仅仅采用一种天真的共享使用策略)资源 - 即MEM(将SWAP引入HELL),CPU(引入缓存未命中和MEM重新获取(是) ,添加了SWAPs处罚),如果忘记并让流程触及 fileIO
,则不会支付任何超过 [SERIAL]
延迟费用的费用 - ( 5(!) - 数量级更慢 +共享+纯粹 - [CONCURRENTLY]
,性质) - 设备。这里没有祈祷帮助(包括SSD) ,只需几个数量级,但仍然是一个地狱分享和运行设备非常快速的磨损+撕裂坟墓。)
虚拟内存分页和交换开始严重恶化到目前为止的其余部分&#34;只是巧合 - (读:弱协调) - aResRECORDER.show_usage_since0() method returns:
ResCONSUMED[T0+ 166036.311 ( 0.000000)]
user= 2475.15
nice= 0.36
iowait= 0.29
irq= 0.00
softirq= 8.32
stolen_from_VM= 26.95
guest_VM_served= 0.00
- 计划处理(读取:进一步降低单个PROCESS-under-TEST性能)。
再次 - 事实很重要:轻量级资源监控类可能会有所帮助:
>>> psutil.Process( os.getpid()
).memory_full_info()
( rss = 9428992,
vms = 158584832,
shared = 3297280,
text = 2322432,
lib = 0,
data = 5877760,
dirty = 0
)
.virtual_memory()
( total = 25111490560,
available = 24661327872,
percent = 1.8,
used = 1569603584,
free = 23541886976,
active = 579739648,
inactive = 588615680,
buffers = 0,
cached = 1119440896
)
.swap_memory()
( total = 8455712768,
used = 967577600,
free = 7488135168,
percent = 11.4,
sin = 500625227776,
sout = 370585448448
)
Wed Oct 19 03:26:06 2017
166.445 ___VMS______________Virtual Memory Size MB
10.406 ___RES____Resident Set Size non-swapped MB
2.215 ___TRS________Code in Text Resident Set MB
14.738 ___DRS________________Data Resident Set MB
3.305 ___SHR_______________Potentially Shared MB
0.000 ___LIB_______________Shared Memory Size MB
__________________Number of dirty pages 0x
类似地,更富有构造的资源监视器可以报告更广泛的操作系统上下文,以查看额外的资源窃取/争用/竞争条件恶化实际实现的流程的位置:
>= 1.00
除了逐步建立的证据记录之外,真实世界的系统部署附加开销如何累积成本,recently re-formulated Amdahl's Law, extended so as to cover both the add-on overhead-costs plus the "process-atomicity" of the further indivisible parts' sizing, defines最大附加成本阈值,如果是分布式的话可能是合理的处理是为了提供任何以上 [SERIAL]
计算过程加速。
不遵守重新制定的Amdahl法律的明确逻辑导致流程比在纯粹的 joblib.Parallel()( joblib.delayed(...) )
流程调度中处理更糟糕(有时,当 {{1}} 方法 &#34;阻止流程&#34;时,设计和/或操作不当的结果可能看起来好像就是这种情况#34; )。