cProfile 对我隐藏了哪些 numpy 函数调用?
Which numpy function calls is cProfile hiding from me?
解决方案
事实证明,np.sum
是一个 python 函数调用 np.add.reduce
。后一个 ufunc
调用 是由 cProfile 报告的 ,我想是因为这仍然是一个 python 对象。 np.maximum
和 np.subtract
是对纯 C 函数的调用,cProfile 认为这些是原子表达式。
问题
我正在尝试优化一小段代码,这比我预期的要花费更多时间。但是,当 运行 cProfile
时,它没有指定哪个 numpy 函数调用消耗的时间最多,只是将我的函数 _H
列为几乎所有时间都在消耗。这是代码:
def _H(X, granularity, knots=None, out=None, buf=None, bias=0):
'''This is the version that I am profiling'''
np.subtract(knots, granularity*X[..., np.newaxis], out=buf)
np.maximum(0, buf, out=buf)
np.sum(buf, axis=1, out=out)
np.subtract(1-bias, out, out=out)
np.maximum(-bias, out, out=out)
我正在使用 ufuncs 来减少临时分配的数量,这节省了很多时间。更 pythonic 的版本只是为了便于阅读:
def _H(X, granularity, knots=None, out=None, buf=None, bias=0):
'''slow but more readable version'''
return np.maximum(
0, 1 - np.maximum(
0, knots - granularity*X[..., np.newaxis]
).sum(1),
) - bias
此函数是从 for 循环调用的(因为 buf
数组不适合大步长的内存):
def H(X, knots, granularity, step=1_000):
t, d = X.shape
_, k = knots.shape
buf = np.empty((step, d, k))
out = np.empty((t, k))
for i in range(0, t, step):
_H(X[i:i + step], granularity, knots=knots,
out=out[i:i + step], buf=buf[:min(step, t-i)], bias=0)
return out
剖析
这是我的分析片段:
t = 1_000_000
d = 3
p = 2
X = np.random.uniform(size=(t, d))
cProfile.run('H(X, p, 10_000)', 'profiler')
pstats.Stats('profiler').strip_dirs().sort_stats('tottime').print_stats()
输出:
1178 function calls in 0.689 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
100 0.371 0.004 0.680 0.007 grid.py:333(_H)
100 0.306 0.003 0.306 0.003 {method 'reduce' of 'numpy.ufunc' objects}
1 0.008 0.008 0.689 0.689 <string>:1(<module>)
1 0.001 0.001 0.681 0.681 grid.py:308(H)
100 0.001 0.000 0.307 0.003 fromnumeric.py:70(_wrapreduction)
100 0.001 0.000 0.308 0.003 fromnumeric.py:2105(sum)
...
据我所知,几乎一半(0.306 秒)的时间花在了 numpy ufunc 上,即 np.subtract
、np.maximum
和 np.sum
。然而,在 _H
中,超过一半的时间(0.371 秒)花在了“其他事情”上。但究竟是什么? cProfile
没有进一步说明哪一段代码,为什么?
From what I can see, almost half (0.306 seconds) of the time is spent in numpy ufuncs, i.e. np.subtract, np.maximum, and np.sum
你读错了。 ufunc.reduce
方法花费了 0.306 秒,该方法用于执行缩减操作,例如 numpy.sum
- numpy.sum
委托给 numpy.add.reduce
.
numpy.maximum(...)
、numpy.subtract(...)
和 granularity*X[..., np.newaxis]
等操作不使用 ufunc.reduce
,因此它们不属于 0.306 秒数字的一部分。
解决方案
事实证明,np.sum
是一个 python 函数调用 np.add.reduce
。后一个 ufunc
调用 是由 cProfile 报告的 ,我想是因为这仍然是一个 python 对象。 np.maximum
和 np.subtract
是对纯 C 函数的调用,cProfile 认为这些是原子表达式。
问题
我正在尝试优化一小段代码,这比我预期的要花费更多时间。但是,当 运行 cProfile
时,它没有指定哪个 numpy 函数调用消耗的时间最多,只是将我的函数 _H
列为几乎所有时间都在消耗。这是代码:
def _H(X, granularity, knots=None, out=None, buf=None, bias=0):
'''This is the version that I am profiling'''
np.subtract(knots, granularity*X[..., np.newaxis], out=buf)
np.maximum(0, buf, out=buf)
np.sum(buf, axis=1, out=out)
np.subtract(1-bias, out, out=out)
np.maximum(-bias, out, out=out)
我正在使用 ufuncs 来减少临时分配的数量,这节省了很多时间。更 pythonic 的版本只是为了便于阅读:
def _H(X, granularity, knots=None, out=None, buf=None, bias=0):
'''slow but more readable version'''
return np.maximum(
0, 1 - np.maximum(
0, knots - granularity*X[..., np.newaxis]
).sum(1),
) - bias
此函数是从 for 循环调用的(因为 buf
数组不适合大步长的内存):
def H(X, knots, granularity, step=1_000):
t, d = X.shape
_, k = knots.shape
buf = np.empty((step, d, k))
out = np.empty((t, k))
for i in range(0, t, step):
_H(X[i:i + step], granularity, knots=knots,
out=out[i:i + step], buf=buf[:min(step, t-i)], bias=0)
return out
剖析
这是我的分析片段:
t = 1_000_000
d = 3
p = 2
X = np.random.uniform(size=(t, d))
cProfile.run('H(X, p, 10_000)', 'profiler')
pstats.Stats('profiler').strip_dirs().sort_stats('tottime').print_stats()
输出:
1178 function calls in 0.689 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
100 0.371 0.004 0.680 0.007 grid.py:333(_H)
100 0.306 0.003 0.306 0.003 {method 'reduce' of 'numpy.ufunc' objects}
1 0.008 0.008 0.689 0.689 <string>:1(<module>)
1 0.001 0.001 0.681 0.681 grid.py:308(H)
100 0.001 0.000 0.307 0.003 fromnumeric.py:70(_wrapreduction)
100 0.001 0.000 0.308 0.003 fromnumeric.py:2105(sum)
...
据我所知,几乎一半(0.306 秒)的时间花在了 numpy ufunc 上,即 np.subtract
、np.maximum
和 np.sum
。然而,在 _H
中,超过一半的时间(0.371 秒)花在了“其他事情”上。但究竟是什么? cProfile
没有进一步说明哪一段代码,为什么?
From what I can see, almost half (0.306 seconds) of the time is spent in numpy ufuncs, i.e. np.subtract, np.maximum, and np.sum
你读错了。 ufunc.reduce
方法花费了 0.306 秒,该方法用于执行缩减操作,例如 numpy.sum
- numpy.sum
委托给 numpy.add.reduce
.
numpy.maximum(...)
、numpy.subtract(...)
和 granularity*X[..., np.newaxis]
等操作不使用 ufunc.reduce
,因此它们不属于 0.306 秒数字的一部分。