-
-
Notifications
You must be signed in to change notification settings - Fork 153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow merging graphs with multiple clients in FusionOptimizer
#1237
Comments
@brandonwillard Do you have any pointers for non-local rewriters that replace multiple nodes? It sounds like the functionality for multiple outputs is already present in the scalar Composite, the only thing we need is to ramp up the FusionOptimizer |
Some of the |
FusionOptimizer
FusionOptimizer
FusionOptimizer
We should probably look into these kinds of fusions that turn scalar constants into inputs. It's not clear to me that this is any better than—say—making In other words, why don't we produce the following instead?
|
Also, can you clarify the kinds of graphs you think we should be producing in these multi-client cases? |
I was thinking the same. I can only think of wanting to reuse the same |
Clarifying what is the idea behind allowing Composites with multiple clients. The following example: import aesara
import aesara.tensor as at
x = at.vector("x")
y = at.exp(x/5)
w = y + 1
z = y * 2
f1 = aesara.function([x], [z, w])
aesara.dprint(f1) Right now produces this graph:
After #1242, it produces this graph:
The expected savings come from having to iterate only once over the data vector Another example is the following graph: x = at.dvector("x")
mu = at.dvector("mu")
logp = (- ((x - mu) **2) / 2)
grad = at.grad(logp.sum(), x)
f2 = aesara.function([mu, x], [logp, grad])
aesara.dprint(f2) Before:
After:
Again we replace 3 loops by 1. Regarding CSE, I don't think anything is changed. The code generated by the scalar Composite seems to be clever enough and reuse repeated computations in intermediate variables. Here is the C code of the Composite scalar in the first function: // function 1
{
npy_float64 V13_tmp1;
// i0 * i1
V13_tmp1 = V11_i * V9_i;
npy_float64 V13_tmp2;
// exp(i0 * i1)
V13_tmp2 = exp((npy_float64)V13_tmp1);
// First output
// i2 * exp(i0 * i1)
V1_i = V7_i * V13_tmp2;
// Second output
// i3 + exp(i0 * i1)
V3_i = V5_i + V13_tmp2;
} // function 2
{
npy_float64 V11_tmp1;
// i0 - i1
V11_tmp1 = V9_i - V7_i;
// First output
// - (i0 - i1)
V1_i = -V11_tmp1;
npy_float64 V11_tmp2;
// sqr(i0 - i1)
V11_tmp2 = V11_tmp1 * V11_tmp1;
// Second output
// i2 * sqr(i0 - i1)
V3_i = V5_i * V11_tmp2;
} You can see that it avoids recomputing the same sub-expressions in both cases. It does store more intermediate variables than needed, but hopefully the compiler will be able to get rid of those. I think the idea of inplacing scalar constants is worth investigating, but deserves a separate issue. It was already relevant for the old Composite graphs. Edit: I see it was already separated into #1270 |
Do you have a comparison like #1242 (comment) for these new CSE-related changes to your approach? |
Right now, Elemwise composite graphs will be split at nodes that have multiple clients. This can be avoided by allowing the fusion rewriter to replace multiple outputs. One example where this is very common is in value_and_grad functions.
Discussed with @aseyboldt and @aesara-devs/aesara
See rationale and proposed changes in #1237 (comment)
The text was updated successfully, but these errors were encountered: