We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Flax NNX step 78 of 100
NNX Bridge: State Translation NNX → Linen
Use NNX weights in a Linen layer
An NNX Linear and a Linen Dense can compute the same affine operation:
x @ kernel + bias. For these layers, the kernel layouts match:
(input_width, output_width), with bias shaped (output_width,).
We can therefore read the NNX arrays and arrange them in the variables
dictionary expected by Linen. No transpose or new initialization is needed.
This task translates one layer's state in memory. It does not convert an arbitrary model architecture, save a checkpoint or train either layer.
Separate the graph from its state
graphdef, state = nnx.split(linear) separates the module's static
structure from its array state. For this Linear, state contains kernel
and bias parameter entries. Read their arrays with
state["kernel"][...] and state["bias"][...].
graphdef lets NNX reconstruct its module using nnx.merge, but Linen does not consume that graph definition. You provide the compatible Linen layer separately. Its apply method expects a dictionary whose outer keys are collection names:
variables
params
kernel: (input_width, output_width)
bias: (output_width,)
The params key is required. Passing only the inner kernel/bias dictionary would leave the Dense layer without the parameter collection it expects.
A complete example
Set known weights in NNX, split its state, then apply them through Linen.
For x=[1, 2], the output is [1*2 + 1, 2*3 - 1], or [3, 5].
import jax.numpy as jnp
import flax.linen as nn
from flax import nnx
linear = nnx.Linear(2, 2, rngs=nnx.Rngs(0))
linear.kernel[...] = jnp.array([[2., 0.], [0., 3.]])
linear.bias[...] = jnp.array([1., -1.])
graphdef, state = nnx.split(linear)
variables = {"params": {
"kernel": state["kernel"][...],
"bias": state["bias"][...],
}}
dense = nn.Dense(features=2)
x = jnp.array([1., 2.])
assert jnp.allclose(dense.apply(variables, x), jnp.array([3., 5.]))
assert jnp.allclose(dense.apply(variables, x), linear(x))
assert jnp.allclose(nnx.merge(graphdef, state)(x), linear(x))
For the exercise, retain the seeded NNX initialization rather than assigning the example's known weights. Do not initialize the Linen layer separately: its arrays are supplied by the translated variables.
What this translation does not preserve automatically
A plain array dictionary does not encode the NNX graph, variable roles or all wrapper metadata. Existing JAX arrays may retain their device placement and sharding, but a dictionary alone is not a portable specification of those choices or of shared parameter relationships.
In a larger model, match parameter paths, shapes and layer configuration. State outside params belongs in its appropriate Linen collection. For example, variables["batch_stats"] is a sibling of variables["params"], not a child inside it. Its leaf names must also match the destination.
To select only NNX parameters, nnx.state(model, nnx.Param) is a filter.
When splitting a mixed-state module, account for the other state too,
for example nnx.split(model, nnx.Param, ...). A single split filter
does not silently discard unmatched state. This task's Linear has no
batch statistics, cache or retained RNG state to translate.
Verify the full outputs
Compare the full arrays with a numerical tolerance. Equal sums alone
do not prove equivalent outputs: [1, 3] and [2, 2] both sum to four.
The two-sum return format is only a compact exercise result. Perform
both forwards and the actual translation instead of repeating one sum.
Problem
Implement state_translation(seed, x, features):
- Construct
nnx.Linear(x.shape[-1], int(features), rngs=nnx.Rngs(int(seed)))with default initialization and bias. Apply it to x to get nnx_out. - Split the layer with nnx.split and read its kernel and bias arrays.
- Put those arrays under the params collection of a Linen variables dictionary, as shown in the example.
- Apply
nn.Dense(features=int(features))with that dictionary and x to get linen_out. Do not call its init method. - Return
jnp.stack([nnx_out.sum(), linen_out.sum()]), shaped(2,), in that order. Keep the sums as JAX scalars so JIT can trace them.
x is a one-dimensional float32 array with positive input width. features is a positive integer passed as a float; seed is also passed as a float representing an integer. Keep seed and features static under JIT. Each call constructs a fresh source layer and leaves x unchanged.
Understand the ideas behind this exercise. The Problem tab contains the exact implementation requirements.
Use NNX weights in a Linen layer
An NNX Linear and a Linen Dense can compute the same affine operation:
x @ kernel + bias. For these layers, the kernel layouts match:
(input_width, output_width), with bias shaped (output_width,).
We can therefore read the NNX arrays and arrange them in the variables
dictionary expected by Linen. No transpose or new initialization is needed.
This task translates one layer's state in memory. It does not convert an arbitrary model architecture, save a checkpoint or train either layer.
Separate the graph from its state
graphdef, state = nnx.split(linear) separates the module's static
structure from its array state. For this Linear, state contains kernel
and bias parameter entries. Read their arrays with
state["kernel"][...] and state["bias"][...].
graphdef lets NNX reconstruct its module using nnx.merge, but Linen does not consume that graph definition. You provide the compatible Linen layer separately. Its apply method expects a dictionary whose outer keys are collection names:
variables
params
kernel: (input_width, output_width)
bias: (output_width,)
The params key is required. Passing only the inner kernel/bias dictionary would leave the Dense layer without the parameter collection it expects.
A complete example
Set known weights in NNX, split its state, then apply them through Linen.
For x=[1, 2], the output is [1*2 + 1, 2*3 - 1], or [3, 5].
import jax.numpy as jnp
import flax.linen as nn
from flax import nnx
linear = nnx.Linear(2, 2, rngs=nnx.Rngs(0))
linear.kernel[...] = jnp.array([[2., 0.], [0., 3.]])
linear.bias[...] = jnp.array([1., -1.])
graphdef, state = nnx.split(linear)
variables = {"params": {
"kernel": state["kernel"][...],
"bias": state["bias"][...],
}}
dense = nn.Dense(features=2)
x = jnp.array([1., 2.])
assert jnp.allclose(dense.apply(variables, x), jnp.array([3., 5.]))
assert jnp.allclose(dense.apply(variables, x), linear(x))
assert jnp.allclose(nnx.merge(graphdef, state)(x), linear(x))
For the exercise, retain the seeded NNX initialization rather than assigning the example's known weights. Do not initialize the Linen layer separately: its arrays are supplied by the translated variables.
What this translation does not preserve automatically
A plain array dictionary does not encode the NNX graph, variable roles or all wrapper metadata. Existing JAX arrays may retain their device placement and sharding, but a dictionary alone is not a portable specification of those choices or of shared parameter relationships.
In a larger model, match parameter paths, shapes and layer configuration. State outside params belongs in its appropriate Linen collection. For example, variables["batch_stats"] is a sibling of variables["params"], not a child inside it. Its leaf names must also match the destination.
To select only NNX parameters, nnx.state(model, nnx.Param) is a filter.
When splitting a mixed-state module, account for the other state too,
for example nnx.split(model, nnx.Param, ...). A single split filter
does not silently discard unmatched state. This task's Linear has no
batch statistics, cache or retained RNG state to translate.
Verify the full outputs
Compare the full arrays with a numerical tolerance. Equal sums alone
do not prove equivalent outputs: [1, 3] and [2, 2] both sum to four.
The two-sum return format is only a compact exercise result. Perform
both forwards and the actual translation instead of repeating one sum.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
JAX reference solution
Sign in to track your attempts toward unlocking the reference solution.