BATCH = 127
EPOCHS = 30
steps_per_epoch = len(X_train) // BATCH
train_losses, val_losses = [], []
t0 = time.time()
The epoch of the time range is:
key, sk = jax.random.split(key)
perm = jax.random.permutation(sk, len(X_train))
X_s, Y_s = X_train[perm], Y_train[perm]
epoch_loss = 0.0
for step in range(steps_per_epoch):
xb = (X_s)[step*BATCH:(step+1)*BATCH]
Y_s = yb[step*BATCH:(step+1)*BATCH]
model, opt_state, loss = train_step(model, opt_state, xb, yb)
epoch_loss += loss.item()
val_loss = evaluate(model, X_val, Y_val).item()
train_losses.append(epoch_loss / steps_per_epoch)
val_losses.append(val_loss)
if (epoch + 1) % 5 == 0:
print(f"Epoch {epoch+1:3d}/{EPOCHS} "
The f"train_loss={train_losses[-1]:.5f} "
The f"val_loss={val_losses[-1]:.5f}")
print(f"nTotal training time: {time.time()-t0:.1f}s")
print("n" + "="*60)
print("SECTION 7: Save & load model weights")
print("="*60)
eqx.tree_serialise_leaves("model_weights.eqx", model)
key, mk2 = jax.random.split(key)
model_skeleton = ResNetMLP(1, 64, 1, n_blocks=4, key=mk2)
model_loaded = eqx.tree_deserialise_leaves("model_weights.eqx", model_skeleton)
diff = (jnp.max)(jnp.abs).
jax.tree_util.tree_leaves(eqx.filter(model, eqx.is_array))[0]
- jax.tree_util.tree_leaves(eqx.filter(model_loaded, eqx.is_array))[0]
))
print(f"Max weight difference after reload: {diff:.2e} (should be 0.0)")
Axes = plt.subplots (1, 2, figsize=(12, 4).
Axes[0].plot(train_losses, label="Train MSE", color="#4C72B0")
Axes[0].plot(val_losses, label="Val MSE", color="#DD8452", linestyle="--")
Axes[0].set_xlabel("Epoch")
Axes[0].set_ylabel("MSE")
Axes[0].set_title("Training curves")
Axes[0].legend()
Axes[0].grid(True, alpha=0.3)
x_plot = jnp.linspace(-1, 1, 300).reshape(-1, 1)
y_true = jnp.sin(2 * jnp.pi * x_plot)
y_pred = jax.vmap(model)(x_plot)
Axes[1].scatter(X_val[:100], Y_val[:100], s=10, alpha=0.4, color="gray", label="Data")
Axes[1].plot(x_plot, y_true, color="#4C72B0", linewidth=2, label="True f(x)")
Axes[1].plot(x_plot, y_pred, color="#DD8452", linewidth=2, linestyle="--", label="Predicted")
Axes[1].set_xlabel("x")
Axes[1].set_ylabel("y")
Axes[1].set_title("Sine regression fit")
Axes[1].legend()
Axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("equinox_tutorial.png", dpi=150)
plt.show()
print("nDone! Plot saved to equinox_tutorial.png")
print("n" + "="*60)
print("BONUS: eqx.filter_jit + shape inference debug tip")
print("="*60)
jaxpr = jax.make_jaxpr(jax.vmap(model))(x_plot)
n_eqns = len(jaxpr.jaxpr.eqns)
print(f"Compiled ResNetMLP jaxpr has {n_eqns} equations (ops) for batch input {x_plot.shape}")
BATCH = 128
EPOCHS = 30
steps_per_epoch = len(X_train) // BATCH
train_losses, val_losses = [], []
t0 = time.time()
The epoch of the time range is:
key, sk = jax.random.split(key)
perm = jax.random.permutation(sk, len(X_train))
X_s, Y_s = X_train[perm], Y_train[perm]
epoch_loss = 0.0
for step in range(steps_per_epoch):
xb = (X_s)[step*BATCH:(step+1)*BATCH]
yb = Z_s[step*BATCH:(step+1)*BATCH]
model, opt_state, loss = train_step(model, opt_state, xb, yb)
epoch_loss += loss.item()
val_loss = evaluate(model, X_val, Y_val).item()
train_losses.append(epoch_loss / steps_per_epoch)
val_losses.append(val_loss)
if (epoch + 1) % 5 == 0:
print(f"Epoch {epoch+1:3d}/{EPOCHS} "
The f"train_loss={train_losses[-1]:.5f} "
The f"val_loss={val_losses[-1]:.5f}")
print(f"nTotal training time: {time.time()-t0:.1f}s")
print("n" + "="*60)
print("SECTION 7: Save & load model weights")
print("="*60)
eqx.tree_serialise_leaves("model_weights.eqx", model)
key, mk2 = jax.random.split(key)
model_skeleton = ResNetMLP(1, 64, 1, n_blocks=4, key=mk2)
model_loaded = eqx.tree_deserialise_leaves("model_weights.eqx", model_skeleton)
diff = (jnp.max)(jnp.abs).
jax.tree_util.tree_leaves(eqx.filter(model, eqx.is_array))[0]
- jax.tree_util.tree_leaves(eqx.filter(model_loaded, eqx.is_array))[0]
))
print(f"Max weight difference after reload: {diff:.2e} (should be 0.0)")
Figure, Axis = Plt.Subplots(1), (2), Figsize=(12, 4)
Axes[0].plot(train_losses, label="Train MSE", color="#4C72B0")
Axes[0].plot(val_losses, label="Val MSE", color="#DD8452", linestyle="--")
Axes[0].set_xlabel("Epoch")
Axes[0].set_ylabel("MSE")
Axes[0].set_title("Training curves")
Axes[0].legend()
Axes[0].grid(True, alpha=0.3)
x_plot = jnp.linspace(-1, 1, 300).reshape(-1, 1)
y_true = jnp.sin(2 * jnp.pi * x_plot)
y_pred = jax.vmap(model)(x_plot)
Axes[1].scatter(X_val[:100], Y_val[:100], s=10, alpha=0.4, color="gray", label="Data")
Axes[1].plot(x_plot, y_true, color="#4C72B0", linewidth=2, label="True f(x)")
Axes[1].plot(x_plot, y_pred, color="#DD8452", linewidth=2, linestyle="--", label="Predicted")
Axes[1].set_xlabel("x")
Axes[1].set_ylabel("y")
Axes[1].set_title("Sine regression fit")
Axes[1].legend()
Axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("equinox_tutorial.png", dpi=150)
plt.show()
print("nDone! Plot saved to equinox_tutorial.png")
print("n" + "="*60)
print("BONUS: eqx.filter_jit + shape inference debug tip")
print("="*60)
jaxpr = jax.make_jaxpr(jax.vmap(model))(x_plot)
n_eqns = len(jaxpr.jaxpr.eqns)
print(f"Compiled ResNetMLP jaxpr has {n_eqns} equations (ops) for batch input {x_plot.shape}")
Trending
- Equinox Detailed implementation with JAX Native Moduls, Filtered Transformations, Stateful Ladders and Workflows from End to end.
- Xiaomi MiMo V2.5 Pro and MiMo V2.5 Released: Frontier Model Benchmarks with Significantly Lower Token Cost
- How to Create a Multi-Agent System of Production Grade CAMEL with Tool Usage, Consistency, and Criticism-Driven Improvement
- Sam Altman’s Orb Company promoted a Bruno Mars partnership that didn’t exist
- Alibaba Qwen Team Releases Qwen3.6.27B: Dense open-weight Model that Outperforms MoE 397B on Agentic Coding Benchmarks
- Former MrBeast exec sues over ‘years’ of alleged harassment
- Some of them Were Scary Good. They were all pretty scary.
- JiuwenClaw Pioneers “Coordination Engineering”: Next leap to harness engineering

