Replies: 2 comments
|
Your instinct is right, but the reason is more specific than "profiler overhead", and it changes what a useful benchmark would look like. The short-circuit is real. array_api_dispatch = get_config()["array_api_dispatch"]
if not array_api_dispatch:
if xp is not None:
return xp, False
else:
return np_compat, FalseSo with dispatch off there is no namespace inspection, no # Return a copy of the threadlocal configuration so that users will
# not be able to modify the configuration with the returned dict.
return _get_threadlocal_config().copy()Every call copies the whole config dict β nine keys today β reads one boolean out of it, and throws the copy away. So what you profiled is not Array API dispatch cost at all; it is a dict copy per helper call, wearing an Array API name in the trace. That also explains the shape of what you saw. Counting the helpers reachable from one Which is why I would not write the asv benchmark you were considering. A And if it did turn out worth fixing, I would not do it the way you sketched. Special-casing Whether maintainers want to bypass that deliberate defensive copy on a hot path is their call, and it is worth asking as a question about |
|
This sounds like a good candidate for an asv benchmark rather than an optimization based on the iris profile. Benchmark small, medium, and realistic dimensions, float32 and float64, dispatch enabled and disabled, and a few L-BFGS iterations. Measure full fit as well as isolated loss_gradient calls, because a helper can look large in inclusive time on tiny data while being negligible end to end. If the NumPy and dispatch-off path is consistently measurable, an early return that preserves existing matmul and dtype logic seems safer than duplicating the algorithm. Use benchmark evidence before changing this hot path. |
Uh oh!
There was an error while loading. Please reload this page.
What I observed
Tracing a default
LogisticRegression(solver="lbfgs")fit on iris, most of thetime sat in
LinearModelLoss.loss_gradient, called once per L-BFGS iteration(the calls can't be batched β each uses updated
coef). Within it, a noticeableshare of inclusive time was in the Array API helpers on plain NumPy/CPU inputs:
get_namespace/get_namespace_and_device/move_to.Why I'm not just opening a PR
I think the observation is probably weak, and I'd rather ask than assume:
get_namespacealready short-circuits (returns
np_compatimmediately). So the per-call costshould be small.
not something that survives on realistically sized
X, where theX @ coefand
X.T @ gradBLAS calls dominate and these helpers are sub-1%.So the honest question: on real-sized inputs, is there any measurable time in
those helpers, or is this a non-issue?
If it turned out to matter
A minimal, low-risk option would be an early "plain NumPy + dispatch off"
short-circuit around the specific
move_to/get_namespace_and_devicecalls inloss_gradient- returning the identical objects, without duplicating thematmul/reshape logic into a second code path. I'd want to avoid a parallel
NumPy-vs-Array-API branch, since that reintroduces exactly the divergence the
Array API work removed, and the dtype/F-order handling there is subtle
(float32 casting, multinomial Fortran ravel, the fact that
weight_intercept_rawis shared across
loss/gradient/hessian/Newton paths).Ask
Before I spend time on an
asvbenchmark: is this overhead already known/considered negligible, or would a benchmark on realistic data be worth bringing?
Happy to run
asvand report numbers either way β including "no measurabledifference," which is a real possible outcome.
All reactions