Clip a gradient pytree by its global L2 norm, which is the length of all its leaves taken together as one long vector.
∥g∥=ℓ∑i∑gℓ,i2,s={1c/∥g∥if ∥g∥≤cotherwiseHere gℓ,i is entry i of leaf ℓ of grads, c is max_norm, and every leaf is multiplied by the same scale s. Gradients whose global norm is already at most max_norm come back unchanged, and larger ones shrink until their global norm equals max_norm.
Your function is called inside jax.jit with grads and max_norm as traced arguments.
Return a dict with two keys. The value under clipped is a pytree with the structure of grads whose leaves are JAX arrays with the shape and dtype of the matching gradient leaf, and the value under global_norm is the norm before clipping as a float32 JAX array of shape ().
Input: grads = {"w": [3.0, 0.0], "b": 4.0}, max_norm = 1.0
Output: {"clipped": {"b": 0.8, "w": [0.6, 0.0]}, "global_norm": 5.0}
Explanation: The squares of all entries add up to 9 + 0 + 16 = 25, so the global norm is 5. It is larger than max_norm, so every leaf is multiplied by 1 / 5, which brings the global norm down to exactly 1.
Input: grads = {"dense": {"w": [[0.1, -0.2], [0.2, 0.0]], "b": [0.4, 0.0]}, "head": [-0.4]}, max_norm = 2.0
Output: {"clipped": {"dense": {"b": [0.4, 0.0], "w": [[0.1, -0.2], [0.2, 0.0]]}, "head": [-0.4]}, "global_norm": 0.640312}
Input: grads = {"layers": [{"w": [0.6, 0.6]}, {"w": [0.6, 0.6]}, {"w": [0.6, 0.6]}]}, max_norm = 1.0
Output: {"clipped": {"layers": [{"w": [0.408248, 0.408248]}, {"w": [0.408248, 0.408248]}, {"w": [0.408248, 0.408248]}]}, "global_norm": 1.469694}
jax.tree.leaves(tree) returns every leaf as a flat list.
jnp.sqrt(sum(jnp.sum(l.astype(jnp.float32) ** 2) for l in leaves)) is the global norm.
jnp.minimum(1.0, max_norm / norm) gives the scale without a Python if.
Accepts: object, array, number
Accepts: number
Clip a gradient pytree by its global L2 norm, which is the length of all its leaves taken together as one long vector.
∥g∥=ℓ∑i∑gℓ,i2,s={1c/∥g∥if ∥g∥≤cotherwiseHere gℓ,i is entry i of leaf ℓ of grads, c is max_norm, and every leaf is multiplied by the same scale s. Gradients whose global norm is already at most max_norm come back unchanged, and larger ones shrink until their global norm equals max_norm.
Your function is called inside jax.jit with grads and max_norm as traced arguments.
Return a dict with two keys. The value under clipped is a pytree with the structure of grads whose leaves are JAX arrays with the shape and dtype of the matching gradient leaf, and the value under global_norm is the norm before clipping as a float32 JAX array of shape ().
Input: grads = {"w": [3.0, 0.0], "b": 4.0}, max_norm = 1.0
Output: {"clipped": {"b": 0.8, "w": [0.6, 0.0]}, "global_norm": 5.0}
Explanation: The squares of all entries add up to 9 + 0 + 16 = 25, so the global norm is 5. It is larger than max_norm, so every leaf is multiplied by 1 / 5, which brings the global norm down to exactly 1.
Input: grads = {"dense": {"w": [[0.1, -0.2], [0.2, 0.0]], "b": [0.4, 0.0]}, "head": [-0.4]}, max_norm = 2.0
Output: {"clipped": {"dense": {"b": [0.4, 0.0], "w": [[0.1, -0.2], [0.2, 0.0]]}, "head": [-0.4]}, "global_norm": 0.640312}
Input: grads = {"layers": [{"w": [0.6, 0.6]}, {"w": [0.6, 0.6]}, {"w": [0.6, 0.6]}]}, max_norm = 1.0
Output: {"clipped": {"layers": [{"w": [0.408248, 0.408248]}, {"w": [0.408248, 0.408248]}, {"w": [0.408248, 0.408248]}]}, "global_norm": 1.469694}
jax.tree.leaves(tree) returns every leaf as a flat list.
jnp.sqrt(sum(jnp.sum(l.astype(jnp.float32) ** 2) for l in leaves)) is the global norm.
jnp.minimum(1.0, max_norm / norm) gives the scale without a Python if.
Accepts: object, array, number
Accepts: number