Andrew NG 很有启发性,这是毫无疑问的
但是可以通过几个步骤来获得更好的代码设计:
提示 1:
如果认真维护更大的代码库,请开始使用更好的 IDE,其中两个
(a) 括号匹配支持 GUI 突出显示和
(b) 跳转到匹配括号 KBD 快捷方式
cost = - ( 1 / m ) * ( np.sum( np.multiply( Y, np.log( A ) )
+ np.multiply( ( 1 - Y ), np.log( 1 - A ) ),
axis = 1
)
) # missing-parenthesis
提示 2:
在所有教学大纲任务都自动评分之后,尝试提高您的代码性能 - 并非所有步骤都经过性能优化,这对于小规模的学习任务是宽容的,而一旦扩展到更大的学习任务,这可能会扼杀您的方法 @987654323 @ 在 O( N^k ) 在两个 [PTIME,PSPACE] 维度中。
对于 1E+3 来说似乎可以正常工作,但无法为 1E+6 或 1E+9 示例提供训练,如果某些 ML 管道在 ML 模型的 HyperPARAMETERs 上迭代,则更少[EXPTIME,EXPSPACE] -搜索域。那很痛。然后,一旦[PSPACE]-问题的大小不适合计算基础架构的内存处理,就会开始更仔细地编写代码以进行权衡,付出过多的[PTIME] 和[EXPTIME]-成本。
在哪里?
--避免重复计算同一事物,如果考虑到数组则越多
(在所有迭代方法中,ML-pipelines + ML-model-HyperPARAMETERs 的巨大,确实 VAST SPACE 搜索
每个浪费的 [ns] 很快就会变成累积的 [us],如果不是 [ms],
每个浪费的 [ms] 很快就会变成累积的 [s],如果不是几十 [min],
每个 浪费的 [min] 很快就会变成累积的 [hrs],如果不是 [days] .. . 是的, 糟糕的代码设计可能会让日子不好过)
示例:
# here, A[] is .ALLOC'd + .SET -----------------------------[PTIME]
A = sigmoid( np.dot( w.T, X )
+ b
) # compute activations, .SET in A[]
# ----------------------------------------------------------[PTIME]-cost was paid
cost = -( 1 / m ) * ( np.sum( np.multiply( Y, np.log( A ) )
+ np.multiply( (1 - Y ), np.log( 1 - A ) ),
axis = 1
)
)
# ----------------------------------------------------------[PTIME]-cost again?
dw = ( 1 / m ) * np.dot( X, ( A - Y ).T ) # consumes ( A - Y )
db = ( 1 / m ) * ( np.sum( A - Y ) ) # consumes ( A - Y ) again
# ----------------------------------------------# last but not least,
# # A[] is not consumed
# # till EoFun/return
# a better approach is to use powerful + faster [PTIME] numpy in-place operations
# that also avoid additional dynamic allocation [PSPACE] -> saving more [PTIME]
DIV_byM = 1 / m # re-use O(N^2) times
A -= Y # way faster in-place + re-used
# ----------------------------------------------# [PTIME]-cost avoided 2x
dw = np.dot( X, A.T ) # +1st re-use
dw *= DIV_byM # way faster in-place
assert( dw.shape == w.shape and "INF: a schoolbook assert()-ion test, "
and "of not much value in PRODUCTION-code"
)
return { 'dw': dw,
'db': DIV_byM * np.sum( A ) # +2nd re-use
} # MUCH better to design
# # the whole as in-place mods
# # of static .ALLOC'd np.view-s,
# # instead of new dict()-s
[TEST-ME] 是一个很好的设计实践,但是
[PERF-ME] 扩展对于成熟代码更重要 - 一个评估的好实践:
一个好的工程实践是将自己的代码与一些实际的操作状态/条件进行基准测试。
鉴于使用了deep-learning,可以假设一组缩放范围——大约 20 M 神经元,大约 30 M 神经元——来对代码执行时间进行基准测试和自我记录:
""" __doc__
USAGE: ...
PARAMETERS: ...
...
EXAMPLE: nnFeedFORWARD( X_example, nnMAP, thetaVEC, stateOfZ, stateOfA )
[TEST-ME] ...
[PERF-ME] *DO NOT* numba.jit( nnFeedFORWARD, nogil = True ) as it performs worse than with plain numpy-OPs
~ 500 .. 1200 [us / 1E6 theta-s .dot() ] on pre-prepared np.view()-s
~ 500 .. 1200 [us / 1E6 theta-s *= 0. ] on pre-prepared np.view()-s
############################################################
#
# as-is: ~ 9 [ms / 21M Theta-s .dot() ] on pre-prepared np.view()-s for MAT + INCL. np.random/rand( 1000 ) ~~ 40 [us]
[ / 10k NEURONs tanh() ] in 5 LAYERs
~ 14 [ms / 30M Theta-s .dot() ]
[ / 17k NEURONs tanh() ] in 10 LAYERs
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> * ~ 1E6 iterations in { .minimize() | .fmin_l_bfgs_b() }
~ 4 [hrs / 1E6 iterations ] w/o backprop