TensorFlow integration¶
uv add esmoe[tensorflow]
esmoe.tensorflow.ESMoE is a tf.Module. It needs TensorFlow and nothing else, Keras included.
Inputs are NHWC.
import tensorflow as tf
from esmoe.tensorflow import ESMoE, Sequential
net = Sequential([ESMoE(kernels=[3, 5, 7], top_k=1)])
out = net(tf.random.normal([2, 16, 16, 8]), training=True)
kernels gives each expert a receptive field, an int or an (h, w) pair, and sets how many
there are; top_k says how many run per sample. Channels come from the first call.
The auxiliary loss¶
The balancing term joins the total loss yourself:
from esmoe.tensorflow import routing
with routing(net) as route:
with tf.GradientTape() as tape:
total = tf.reduce_sum(net(x, training=True)) + 0.01 * route.loss()
grads = tape.gradient(total, net.trainable_variables)
routing clears the registry on the way in, so a block that did not run this step cannot report
the step before. Without the context manager, pair clear_aux_loss with collect_aux_loss.
Into a model that already exists¶
from esmoe.tensorflow import graft
graft(model, at="stem", mode="after", kernels=[3, 5, 7], top_k=1)
at takes an attribute name, several names, or a (name, module) -> bool test; layers inside a
Sequential are addressed by position. mode is after, before or replace, applied in place.
Boundaries¶
Every expert is evaluated. Skipping an unrouted one depends on the batch, which a static graph cannot express.
Batch normalisation keeps its moving statistics in untrained variables, updated when
training=True.