Keras
embedding layers
neural networks
deep learning
machine learning

Multiple embedding layers in keras

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

Using multiple embedding layers in Keras is normal whenever different categorical inputs have different vocabularies or different semantic roles. The usual pattern is one input and one embedding layer per categorical feature, followed by concatenation or another merge step.

When Multiple Embeddings Make Sense

Separate embeddings are useful when the model receives distinct categories such as:

  • user id and item id in a recommender
  • country code and device type in a ranking model
  • word tokens and position ids in an NLP model

Each of those feature spaces has its own vocabulary size and its own meaning. Forcing them into a single embedding table often makes the model harder to reason about unless the categories truly share the same index space.

A Simple Keras Example

Here is a recommendation-style model with separate user and item embeddings:

python
1import tensorflow as tf
2from tensorflow import keras
3
4user_input = keras.Input(shape=(1,), name="user_id")
5item_input = keras.Input(shape=(1,), name="item_id")
6
7user_embedding = keras.layers.Embedding(input_dim=10000, output_dim=32)(user_input)
8item_embedding = keras.layers.Embedding(input_dim=5000, output_dim=32)(item_input)
9
10user_vector = keras.layers.Flatten()(user_embedding)
11item_vector = keras.layers.Flatten()(item_embedding)
12
13features = keras.layers.Concatenate()([user_vector, item_vector])
14hidden = keras.layers.Dense(64, activation="relu")(features)
15output = keras.layers.Dense(1, activation="sigmoid")(hidden)
16
17model = keras.Model(inputs=[user_input, item_input], outputs=output)
18model.compile(optimizer="adam", loss="binary_crossentropy")
19
20model.summary()

This model learns one embedding table for users and another for items. That separation is exactly what you want because user ids and item ids are not interchangeable categories.

Sequence Inputs Need Pooling or Sequence Modeling

If an embedding produces a sequence instead of a single id, you usually need another layer before a dense head. For example:

python
1tokens = keras.Input(shape=(20,), name="tokens")
2positions = keras.Input(shape=(20,), name="positions")
3
4token_embedding = keras.layers.Embedding(input_dim=20000, output_dim=64)(tokens)
5position_embedding = keras.layers.Embedding(input_dim=20, output_dim=64)(positions)
6
7combined = keras.layers.Add()([token_embedding, position_embedding])
8pooled = keras.layers.GlobalAveragePooling1D()(combined)
9output = keras.layers.Dense(3, activation="softmax")(pooled)
10
11model = keras.Model(inputs=[tokens, positions], outputs=output)

This is still “multiple embedding layers,” but now they operate over aligned sequences and are combined elementwise instead of flattened and concatenated.

Share Embeddings Only When It Makes Semantic Sense

Sometimes developers ask whether multiple inputs can reuse the same embedding layer. The answer is yes, but only when the inputs represent the same vocabulary and should share representation learning.

For example, two text fields that both use the same token index mapping may share one embedding layer:

python
1shared_embedding = keras.layers.Embedding(input_dim=20000, output_dim=64)
2
3title_input = keras.Input(shape=(30,), name="title")
4body_input = keras.Input(shape=(200,), name="body")
5
6title_emb = shared_embedding(title_input)
7body_emb = shared_embedding(body_input)

That is different from user ids versus item ids, where separate embeddings are the right default.

Watch the Vocabulary Sizes

Each embedding layer needs its own correct input_dim. A common bug is copying one embedding definition and forgetting that another categorical feature has a very different vocabulary size.

For example:

  • user ids might need input_dim=100000
  • device type might need input_dim=6

Those should not share the same table shape just because both are categorical.

Common Pitfalls

The most common mistake is mixing multiple categorical features into one embedding table without a good reason. That usually hides feature meaning and complicates debugging.

Another pitfall is forgetting to reduce or reshape the embedding output before feeding it to dense layers. A sequence embedding often needs pooling, flattening, or recurrent processing first.

It is also easy to set the wrong input_dim, especially when ids are one-based, sparse, or preprocessed differently across features. Embedding lookups fail or waste memory quickly when the dimension is wrong.

Finally, avoid making embedding dimensions arbitrarily huge. Larger embeddings increase memory usage and training cost, and they are not automatically better than smaller, well-chosen representations.

Summary

  • Use separate embedding layers when categorical inputs have different vocabularies or roles.
  • Merge multiple embeddings with concatenation, addition, or another structure that matches the model design.
  • Share one embedding layer only when the inputs truly belong to the same token space.
  • Set input_dim correctly for each feature.
  • Pool, flatten, or otherwise process sequence embeddings before passing them into dense layers.

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.