We recently ran into a situation quite similar to the following (simplified) code:
import jax
def positive_branch(x):
# this function does not terminate for negative values
def body(x):
return x * 0.1
return jax.lax.while_loop(lambda y: (y <= 0) | (y > 1e-6), body, x)
def negative_branch(x):
# this function always terminates
def body(x):
return x * 0.1
return jax.lax.while_loop(lambda y: y < -1e-6, body, x)
def branching_fn(x):
return jax.lax.cond(x >= 0, x, positive_branch, x, negative_branch)
x = jax.random.normal(jax.random.PRNGKey(0), shape=(10,))
branching_fns = jax.vmap(branching_fn)
y = branching_fns(x)
print(y)
So in essence, we have a a while loop that only terminates if the condition that leads the branch it resides in to be executed is true. In classical sequential code this is not a problem, however, in this particular example, it results in non-termination.
What seems to be happening is that despite conditional branching using jax.lax.cond, both branches are executed (we suspect that jax.lax.cond in this case performs some kind of result multiplexing/selection instead of actual conditional executing).
What's a bit puzzling about this is that this does not occur when not using jax.vmap:
- execution on a single data point does not exhibit the problem
jax.lax.map does not exhibit the problem
A fix in this example is to include the branching condition in the loops conditions to ensure they always terminate - but it might be worthwhile to think about how to fix this in the underlying implementation.. so can you maybe shed some light on what is causing this and whether it could be addressed? At least I think this should be documented somewhere (maybe on the sharp bits page). Also, what exactly is the difference between map and vmap in terms of performance/parallelization?
We recently ran into a situation quite similar to the following (simplified) code:
So in essence, we have a a while loop that only terminates if the condition that leads the branch it resides in to be executed is true. In classical sequential code this is not a problem, however, in this particular example, it results in non-termination.
What seems to be happening is that despite conditional branching using
jax.lax.cond, both branches are executed (we suspect thatjax.lax.condin this case performs some kind of result multiplexing/selection instead of actual conditional executing).What's a bit puzzling about this is that this does not occur when not using
jax.vmap:jax.lax.mapdoes not exhibit the problemA fix in this example is to include the branching condition in the loops conditions to ensure they always terminate - but it might be worthwhile to think about how to fix this in the underlying implementation.. so can you maybe shed some light on what is causing this and whether it could be addressed? At least I think this should be documented somewhere (maybe on the sharp bits page). Also, what exactly is the difference between
mapandvmapin terms of performance/parallelization?