Keras LSTM
many-to-many classification
deep learning
neural networks
machine learning

Many-to-many classification with Keras LSTM

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Many-to-many classification means the model receives a sequence and predicts a class for every time step in that sequence. In Keras, the core requirement is that the recurrent layer keeps the full sequence by using return_sequences=True, so later layers can produce one output per step instead of one output for the whole input.

When You Need Many-to-Many

This pattern appears in sequence labeling tasks such as:

  • part-of-speech tagging
  • per-token named entity labels
  • frame-by-frame activity labels
  • anomaly labels for each point in a time series

The shape logic matters more than the terminology. If the input has shape (batch, timesteps, features) and you want one prediction per timestep, the model output must keep the timesteps axis.

The Key Keras Setting

An LSTM normally returns only the final hidden state. That is useful for many-to-one tasks such as sequence sentiment classification. For many-to-many classification, you need:

python
keras.layers.LSTM(units, return_sequences=True)

That makes the layer output shape (batch, timesteps, units).

From there, you can apply a classifier across the last dimension. In modern Keras, a Dense layer can be applied directly to this 3D tensor and will act on each timestep independently.

Minimal Working Example

The example below builds a small sequence-labeling model where each timestep gets one of three classes.

python
1import numpy as np
2import tensorflow as tf
3from tensorflow import keras
4
5num_samples = 200
6timesteps = 6
7features = 4
8num_classes = 3
9
10X = np.random.rand(num_samples, timesteps, features).astype("float32")
11y = np.random.randint(0, num_classes, size=(num_samples, timesteps))
12
13model = keras.Sequential([
14    keras.layers.Input(shape=(timesteps, features)),
15    keras.layers.LSTM(32, return_sequences=True),
16    keras.layers.Dense(num_classes, activation="softmax")
17])
18
19model.compile(
20    optimizer="adam",
21    loss="sparse_categorical_crossentropy",
22    metrics=["accuracy"]
23)
24
25model.fit(X, y, epochs=3, batch_size=16)

Important shape facts:

  • 'X is (samples, timesteps, features)'
  • 'y is (samples, timesteps) because there is one integer class per timestep'
  • the model output is (samples, timesteps, num_classes)

Those shapes line up with sparse_categorical_crossentropy.

One-Hot Targets

If your labels are one-hot encoded instead of integer encoded, use categorical_crossentropy and shape the targets as (samples, timesteps, num_classes).

python
1import tensorflow as tf
2
3y_int = np.random.randint(0, num_classes, size=(num_samples, timesteps))
4y_one_hot = tf.one_hot(y_int, depth=num_classes).numpy()
5
6model.compile(
7    optimizer="adam",
8    loss="categorical_crossentropy",
9    metrics=["accuracy"]
10)
11
12model.fit(X, y_one_hot, epochs=3, batch_size=16)

Do not mix the loss and label encoding. That is one of the fastest ways to get confusing training errors.

Variable-Length Sequences and Padding

Real sequence data often has variable length. The common approach is to pad sequences to a common length and use masking so the padded timesteps do not affect training.

python
1from tensorflow import keras
2
3model = keras.Sequential([
4    keras.layers.Input(shape=(None, features)),
5    keras.layers.Masking(mask_value=0.0),
6    keras.layers.LSTM(32, return_sequences=True),
7    keras.layers.Dense(num_classes, activation="softmax")
8])

If you pad inputs, make sure your targets are padded consistently. Otherwise the model output length and label length will not match.

Bidirectional and Stacked Variants

Many-to-many does not mean a single LSTM layer. You can stack recurrent layers as long as each intermediate recurrent layer keeps the sequence.

python
1model = keras.Sequential([
2    keras.layers.Input(shape=(timesteps, features)),
3    keras.layers.Bidirectional(keras.layers.LSTM(32, return_sequences=True)),
4    keras.layers.LSTM(16, return_sequences=True),
5    keras.layers.Dense(num_classes, activation="softmax")
6])

The rule is simple: if another timestep-aware layer needs a sequence, the previous recurrent layer must also output a sequence.

How This Differs from Sequence-to-Sequence

Some articles use "many-to-many" for any model that maps one sequence to another. That can be misleading. A same-length sequence labeling model is simpler than a full encoder-decoder translation model.

In this article, the focus is per-timestep classification where input and output lengths are aligned. If your output sequence length differs from the input length, you are usually in sequence-to-sequence territory and need an encoder-decoder design or attention-based architecture.

Common Pitfalls

  • Forgetting return_sequences=True on the LSTM. Without it, the network outputs only one vector and cannot classify each timestep.
  • Using categorical_crossentropy with integer labels or sparse_categorical_crossentropy with one-hot labels. Match the loss to the label encoding.
  • Creating targets shaped (samples,) for a per-timestep problem. Many-to-many targets must retain the sequence axis.
  • Padding input sequences without handling padded target positions. This can train the model on meaningless labels.
  • Assuming every sequence problem is the same as sequence-to-sequence translation. Per-step classification is simpler and has different shape requirements.

Summary

  • Many-to-many classification predicts a label for every timestep in the input sequence.
  • In Keras, the crucial setting is return_sequences=True on the LSTM.
  • Output and target shapes must both preserve the timestep dimension.
  • Choose sparse_categorical_crossentropy for integer labels and categorical_crossentropy for one-hot labels.
  • Masking and padding matter when your sequences do not all share the same length.

Course illustration
Course illustration

All Rights Reserved.