ResNet
time series
deep learning
neural networks
model adaptation

How to adapt ResNet to time series data

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

ResNet is an image architecture, but the core idea is broader than computer vision. A residual block lets a model learn a refinement to its input instead of relearning the entire transformation, and that idea works well for temporal signals too. For time series, the main adaptation is replacing image-style spatial operations with sequence-aware ones.

Translate image blocks into sequence blocks

In an image ResNet, a convolution slides across height and width. In a time-series ResNet, a Conv1D slides across the time axis instead. In Keras, the usual input shape is (timesteps, channels), where channels means features per time step.

That mapping is straightforward:

  • univariate series: one channel
  • multivariate series: one channel per measured feature
  • image Conv2D: replaced by Conv1D
  • image global average pooling: replaced by temporal global average pooling

Residual connections still matter for the same reason they matter in vision: deeper stacks are easier to optimize when each block can preserve the input path.

Build a 1D residual block

The usual pattern is two or three Conv1D layers, normalization, a nonlinearity, and a skip path. If the number of filters changes, project the skip path with a 1x1 convolution so the shapes match.

python
1import tensorflow as tf
2
3
4def residual_block(x, filters, kernel_size=3, stride=1):
5    shortcut = x
6
7    y = tf.keras.layers.Conv1D(
8        filters, kernel_size, strides=stride, padding="same", use_bias=False
9    )(x)
10    y = tf.keras.layers.BatchNormalization()(y)
11    y = tf.keras.layers.ReLU()(y)
12
13    y = tf.keras.layers.Conv1D(
14        filters, kernel_size, padding="same", use_bias=False
15    )(y)
16    y = tf.keras.layers.BatchNormalization()(y)
17
18    if shortcut.shape[-1] != filters or stride != 1:
19        shortcut = tf.keras.layers.Conv1D(
20            filters, 1, strides=stride, padding="same", use_bias=False
21        )(shortcut)
22        shortcut = tf.keras.layers.BatchNormalization()(shortcut)
23
24    out = tf.keras.layers.Add()([shortcut, y])
25    return tf.keras.layers.ReLU()(out)
26
27
28inputs = tf.keras.Input(shape=(256, 4))
29x = residual_block(inputs, 32)
30x = residual_block(x, 32)
31x = residual_block(x, 64, stride=2)
32x = tf.keras.layers.GlobalAveragePooling1D()(x)
33outputs = tf.keras.layers.Dense(3, activation="softmax")(x)
34
35model = tf.keras.Model(inputs, outputs)
36model.compile(optimizer="adam", loss="sparse_categorical_crossentropy")
37model.summary()

This model is suitable for sequence classification. The first dimension is time, and the second is the number of input variables.

Match the head to the problem

The residual trunk is only part of the design. The output head should reflect the task:

  • classification: global pooling followed by a dense classifier
  • regression: global pooling followed by one or more linear outputs
  • forecasting: a dense layer that predicts the next value, or a sequence head that predicts multiple future steps

For many forecasting problems, you train on sliding windows. Each training example is a recent chunk of history, and the label is the next point or next horizon.

python
1import numpy as np
2
3
4series = np.sin(np.linspace(0, 50, 400)).astype("float32")
5window = 32
6
7X = []
8y = []
9for i in range(len(series) - window):
10    X.append(series[i:i + window])
11    y.append(series[i + window])
12
13X = np.array(X)[..., np.newaxis]
14y = np.array(y)
15
16inputs = tf.keras.Input(shape=(window, 1))
17x = residual_block(inputs, 16)
18x = residual_block(x, 16)
19x = tf.keras.layers.GlobalAveragePooling1D()(x)
20outputs = tf.keras.layers.Dense(1)(x)
21
22forecast_model = tf.keras.Model(inputs, outputs)
23forecast_model.compile(optimizer="adam", loss="mse")
24forecast_model.fit(X, y, epochs=3, batch_size=32, verbose=0)

That example shows the mechanical change from image classification to next-step forecasting. The residual idea stays the same, but the input windowing and output layer change.

Decide how much temporal context to capture

Time series often need longer context than small image patches. You can increase receptive field by stacking more blocks, using larger kernels, or using dilated convolutions. Residual connections help here because deeper temporal models are otherwise harder to train.

You should also think about whether your problem is local or global:

  • local patterns: short kernels often work well
  • seasonal or long-range patterns: deeper stacks or dilation help
  • irregular timestamps: resampling or feature engineering may matter more than architecture choice

In practice, a 1D ResNet is often a strong baseline before trying transformers or more elaborate hybrids.

Common Pitfalls

One common mistake is getting the input shape backwards. In Keras, the typical order is (timesteps, channels), not (channels, timesteps).

Another mistake is copying an image ResNet too literally. Aggressive downsampling can destroy short-lived spikes or boundary events that matter in time series.

Teams also over-focus on architecture and under-focus on data preparation. Normalization, window construction, label alignment, and handling missing timestamps usually affect results more than adding extra residual blocks.

Finally, do not assume classification tricks transfer directly to forecasting. A classifier head and a forecast head answer different questions even if the trunk looks similar.

Summary

  • ResNet adapts to time series by replacing Conv2D blocks with Conv1D residual blocks.
  • The usual input layout is (timesteps, channels).
  • Use projection shortcuts when filter counts or stride change.
  • Choose the output head based on classification, regression, or forecasting.
  • Good windowing, normalization, and label alignment are as important as model depth.

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.