Tensorflow
Hierarchical Softmax
Machine Learning
Deep Learning
Neural Networks

Tensorflow Hierarchical Softmax Implementation

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

Hierarchical softmax is useful when the number of classes is so large that a normal softmax layer becomes expensive. Instead of scoring every class directly, the model predicts a path through a tree of binary decisions. In TensorFlow, this usually means building the hierarchy yourself and training against internal tree nodes with a custom loss.

Why Hierarchical Softmax Helps

A standard softmax over N classes computes logits for all classes and normalizes them together. That is fine for a small label set, but it gets expensive for large vocabularies such as language models. Hierarchical softmax reduces the work by replacing one large classification step with several smaller binary decisions along a path from the root of a tree to a leaf.

For a balanced tree, the number of decisions grows roughly with log N instead of N.

A Small TensorFlow Example

The easiest way to understand the implementation is to start with a fixed tree for four classes. That tree has three internal decision nodes. In real language-modeling systems, the tree is often built from label frequency, sometimes with a Huffman-style layout so common classes get shorter paths.

python
1import tensorflow as tf
2
3PATH_NODES = tf.constant([
4    [0, 1],
5    [0, 1],
6    [0, 2],
7    [0, 2],
8], dtype=tf.int32)
9
10PATH_BITS = tf.constant([
11    [0.0, 0.0],
12    [0.0, 1.0],
13    [1.0, 0.0],
14    [1.0, 1.0],
15], dtype=tf.float32)

Each class maps to a sequence of internal node IDs and expected left-or-right decisions. For example, class 0 means "go left at node 0, then left at node 1".

Build a Model That Predicts Node Logits

Instead of producing one logit per class, the model produces one logit per internal node.

python
1inputs = tf.keras.Input(shape=(16,))
2x = tf.keras.layers.Dense(32, activation="relu")(inputs)
3node_logits = tf.keras.layers.Dense(3)(x)
4
5model = tf.keras.Model(inputs, node_logits)

Now the output is not a class distribution yet. It is a set of binary decisions for the internal nodes in the tree.

Implement the Hierarchical Loss

The loss gathers only the logits needed for the target class path and applies binary cross-entropy to those decisions.

python
1def hierarchical_loss(labels, logits):
2    labels = tf.cast(tf.reshape(labels, [-1]), tf.int32)
3    node_ids = tf.gather(PATH_NODES, labels)
4    targets = tf.gather(PATH_BITS, labels)
5
6    selected_logits = tf.gather(logits, node_ids, batch_dims=1)
7    losses = tf.nn.sigmoid_cross_entropy_with_logits(
8        labels=targets,
9        logits=selected_logits
10    )
11    return tf.reduce_mean(tf.reduce_sum(losses, axis=1))
12
13model.compile(optimizer="adam", loss=hierarchical_loss)

This is the core implementation idea. The model predicts internal decisions, and the loss evaluates only the path that belongs to the target label.

Convert Node Decisions Back to Class Probabilities

During inference, you recover class probabilities by multiplying the probabilities along each leaf path.

python
1def class_probabilities(node_logits):
2    probs = tf.math.sigmoid(node_logits)
3
4    p0 = (1.0 - probs[:, 0]) * (1.0 - probs[:, 1])
5    p1 = (1.0 - probs[:, 0]) * probs[:, 1]
6    p2 = probs[:, 0] * (1.0 - probs[:, 2])
7    p3 = probs[:, 0] * probs[:, 2]
8
9    return tf.stack([p0, p1, p2, p3], axis=1)

For a real system with many classes, you would usually store the tree structure and path tables programmatically instead of hardcoding them.

Know When a Simpler Alternative Is Better

Hierarchical softmax is not the only option for large output spaces. TensorFlow users often choose sampled softmax or noise-contrastive estimation because those methods can be easier to integrate into existing models. Hierarchical softmax becomes attractive when you want deterministic path-based scoring and you are willing to manage the tree structure yourself.

Common Pitfalls

  • Assuming TensorFlow has a drop-in Keras layer that solves the full hierarchy for you.
  • Forgetting that the model output now represents internal nodes, not classes directly.
  • Building path tables incorrectly so labels point to the wrong decision sequence.
  • Using an unbalanced or poorly designed tree that hurts both speed and model quality.

Summary

  • Hierarchical softmax replaces one large softmax with binary decisions along a tree path.
  • In TensorFlow, the usual approach is a custom model output plus a custom loss.
  • The model predicts logits for internal tree nodes, and the loss gathers only the path for the target label.
  • Inference reconstructs class probabilities by multiplying probabilities along each path.
  • For very large vocabularies, compare this approach with sampled softmax before committing to the extra implementation complexity.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.