DEV Community

Cover image for GPU-Accelerating MSCRED with CUDA, im2col, GEMM, and a Custom PyTorch Extension
ranjithvutnoor
ranjithvutnoor

Posted on

GPU-Accelerating MSCRED with CUDA, im2col, GEMM, and a Custom PyTorch Extension

Introduction

During my M.Tech in Data Science and Artificial Intelligence at IIT Bhilai (2021–2023), I conducted thesis research on multivariate time-series anomaly detection and GPU acceleration using industrial process signals.

My thesis, titled “Anomaly Detection of Multivariate Time Series Data and Acceleration Using GPUs,” explored an MSCRED—Multi-Scale Convolutional Recurrent Encoder-Decoder—and ConvLSTM-based pipeline for modelling relationships between signals and detecting abnormal temporal patterns.

Although the model produced useful anomaly-detection results, its convolution-heavy encoder created a significant CPU bottleneck. I therefore implemented GPU-accelerated operations using CUDA, transformed convolution into an im2col plus GEMM workflow, investigated global-memory and shared-memory implementations, and integrated the accelerated operations with PyTorch.

In the measured workload, encoder runtime decreased from 300 seconds on the CPU to 23.664 seconds on the GPU, representing an approximately 12.68× encoder speed-up.

Research attribution: MSCRED and ConvLSTM are established architectures introduced by the researchers cited in the References section. This article describes how I used, adapted, profiled, and accelerated selected operations as part of my M.Tech thesis.

Data confidentiality: The original research involved industrial process data. This article discusses the architecture, optimisation methodology, and aggregate benchmark results without publishing proprietary signals, internal process details, confidential datasets, or restricted source code.


The Anomaly-Detection Problem

Industrial systems often generate many related sensor and process-control signals at the same time. A single signal may appear normal when viewed independently, while the relationship between several signals may indicate an abnormal operating condition.

This makes multivariate time-series anomaly detection more difficult than analysing one signal at a time.

The model must learn:

  • Relationships between multiple signals
  • Changes across different time windows
  • Temporal dependencies between successive observations
  • Deviations from normal operating patterns
  • Reconstruction differences that may indicate anomalies

The goal of the research was to detect unusual multivariate patterns while preserving the temporal and spatial relationships present in the data.


MSCRED and ConvLSTM Architecture

MSCRED models relationships between multiple time-series signals by constructing signature matrices over different temporal windows.

At a high level, the pipeline contains:

  1. Signature-matrix generation from multivariate signals
  2. A convolutional encoder for spatial feature extraction
  3. ConvLSTM layers for temporal modelling
  4. A decoder that reconstructs expected signal relationships
  5. Reconstruction-error analysis for anomaly scoring

The encoder processes the signature matrices through convolutional operations, while ConvLSTM captures how the encoded representations evolve over time.

Multivariate signals
        ↓
Signature matrices
        ↓
CNN encoder
        ↓
ConvLSTM
        ↓
Decoder
        ↓
Reconstruction error
        ↓
Anomaly score
Enter fullscreen mode Exit fullscreen mode

Why Signature Matrices Are Useful

A signature matrix represents pairwise relationships between signals over a selected time interval.

By generating these matrices at multiple scales, the model can observe both short-term and longer-term relationships. This helps identify anomalies that may not be visible in an individual signal.

Role of the Encoder

The convolutional encoder extracts spatial patterns from the signature matrices. It reduces the raw matrix representation into compact feature maps that capture important relationships between signals.

Role of ConvLSTM

ConvLSTM models how those spatial representations change over time.

Unlike a standard fully connected LSTM, ConvLSTM preserves the spatial structure of feature maps while learning temporal dependencies.

Role of the Decoder

The decoder reconstructs the expected signature matrices.

When the reconstructed output differs significantly from the observed input, the reconstruction error can indicate an anomalous pattern.


Anomaly-Detection Evaluation

The purpose of the MSCRED and ConvLSTM pipeline was to detect abnormal relationships and temporal behaviour across multiple industrial process signals.

The model learned normal multivariate patterns by reconstructing signature matrices. During evaluation, the difference between the observed signature matrices and the reconstructed outputs was used to calculate a reconstruction error.

Observed signature matrix
            ↓
MSCRED reconstruction
            ↓
Reconstruction error
            ↓
Thresholding
            ↓
Normal or anomalous
Enter fullscreen mode Exit fullscreen mode

A larger reconstruction error indicated that the observed relationships differed from patterns learned during normal operation and could therefore represent an anomaly.

The thesis evaluated anomaly-detection quality using the F1 score. Under the reported experimental setup, the best recorded F1 score was 0.941.

This result represents model-quality evaluation and should be interpreted separately from the CUDA runtime measurements presented later. The GPU memory optimisations were designed to reduce computation time, not to improve predictive accuracy.


Where the Performance Bottleneck Appeared

The encoder repeatedly applied convolutional operations to signature matrices.

On the CPU, these operations involved substantial nested computation across:

  • Input channels
  • Output filters
  • Spatial positions
  • Kernel dimensions
  • Batch elements

This made the encoder a strong candidate for GPU acceleration because many convolution calculations could be performed in parallel.

The objective was not to redesign the anomaly-detection model. Instead, it was to preserve its expected computational behaviour while accelerating selected expensive operations.


Transforming Conv2D into im2col and GEMM

A convolution repeatedly applies a kernel to overlapping regions of an input feature map.

The im2col, or image-to-column, transformation rearranges those local regions into columns of a matrix.

After this transformation, convolution can be expressed as a general matrix multiplication:

Output matrix = Weight matrix × im2col(Input)
Enter fullscreen mode Exit fullscreen mode

This conversion is useful because matrix multiplication is highly parallel and can be executed efficiently on a GPU.

Conceptual Transformation

Input feature map
        ↓
Extract overlapping kernel windows
        ↓
Arrange windows as matrix columns
        ↓
Multiply by reshaped filter matrix
        ↓
Reshape result into output feature map
Enter fullscreen mode Exit fullscreen mode

Why Use GEMM?

GEMM stands for General Matrix-Matrix Multiplication.

Modern GPU architectures are designed to perform large numbers of multiply-and-accumulate operations in parallel. Expressing convolution as GEMM allows the workload to use that parallelism.

Trade-Off

im2col introduces additional memory usage because overlapping input regions are copied into an intermediate matrix.

The method is most effective when the computational benefit of parallel matrix multiplication outweighs the cost of creating and storing the intermediate representation.


CUDA Kernel Design

The CUDA implementation divided the computation across many GPU threads.

Each thread was responsible for part of the output, while thread blocks grouped related work.

Important kernel-design considerations included:

  • Mapping output elements to threads
  • Selecting thread-block dimensions
  • Coalescing memory access where possible
  • Reducing unnecessary global-memory operations
  • Avoiding excessive synchronisation
  • Preserving correct tensor indexing
  • Managing intermediate buffers efficiently

The implementation required careful validation because incorrect indexing in GPU code can produce plausible-looking but incorrect outputs.


Global Memory and Shared Memory

The first GPU implementation relied primarily on global memory.

Global memory provides access to the complete input, but its latency is considerably higher than that of on-chip shared memory.

The optimised implementation staged reusable tiles inside shared memory. Threads within the same block could then reuse nearby values without repeatedly loading them from global memory.

The shared-memory optimisation was intended to:

  • Reduce repeated global-memory reads
  • Improve data locality
  • Increase data reuse within each thread block
  • Reduce memory-related kernel overhead
  • Improve matrix-multiplication efficiency

Conceptual Data Flow

Global memory
      ↓
Load reusable tile
      ↓
Shared memory
      ↓
Threads perform repeated calculations
      ↓
Write result to global memory
Enter fullscreen mode Exit fullscreen mode

Shared memory is limited in capacity, so tile dimensions and thread-block organisation must be selected carefully.

Poorly selected configurations can:

  • Reduce occupancy
  • Increase synchronisation overhead
  • Create bank conflicts
  • Use too much shared memory per block
  • Limit the number of active thread blocks

Integrating the CUDA Implementation with PyTorch

To use the accelerated operations inside the existing model pipeline, I connected the CUDA implementation to PyTorch through a custom extension.

The integration enabled PyTorch tensors to be passed to the CUDA implementation and the computed results to be returned to the model pipeline.

Important integration concerns included:

  • Tensor dimensions
  • Device placement
  • Data types
  • Contiguous-memory assumptions
  • Compilation and linking
  • Error handling
  • CPU-versus-GPU output comparison

Correctness validation was essential. A faster kernel is not useful if it changes tensor shapes, produces incorrect indexing, introduces unacceptable numerical differences, or behaves inconsistently for the tested configurations.

The custom extension made it possible to retain PyTorch for model development while using lower-level CUDA operations for selected performance-critical components.


Experimental Setup

The benchmark used the following environment:

  • GPU: NVIDIA RTX A6000, 48 GB
  • CPU: 16-core Intel Xeon Gold 5218
  • System memory: 64 GB
  • Data points: 36,000
  • Number of features: 30
  • Batch size: 128
  • CPU threads: 32

Timing Methodology

The timings reported here are measurements from my thesis experiments using the specified hardware and workload. The CPU and GPU implementations used the same input dimensions and batch configuration.

The results should be treated as comparative experimental measurements rather than universal library benchmarks. Performance may vary with implementation details, CUDA configuration, tensor dimensions, data-transfer costs, compiler settings, and hardware.


Performance Benchmark Results

Component CPU GPU: global memory GPU: shared memory
Encoder 300 s 27.492 s 23.664 s
ConvLSTM 1,200 s 909.208 s 847.260 s
Total runtime 2,700 s 1,594 s 1,481 s

Results at a Glance

  • Anomaly-detection quality: best recorded F1 score of 0.941
  • Encoder acceleration: approximately 12.68×
  • End-to-end acceleration: approximately 1.82×
  • Total runtime reduction: approximately 45.1%

The shared-memory implementation reduced encoder runtime from 300 seconds to 23.664 seconds, producing an approximately 12.68× encoder speed-up.

For the complete measured pipeline, runtime decreased from 2,700 seconds to 1,481 seconds. The total-runtime measurement represents the complete measured pipeline rather than only the encoder and ConvLSTM components shown separately.


Why the Encoder Improved More Than ConvLSTM

The convolutional encoder benefited strongly from GPU execution because its operations provided substantial data parallelism.

ConvLSTM achieved a smaller improvement because of:

  • Recurrent dependencies
  • Sequential temporal processing
  • Memory movement
  • Repeated state updates
  • More limited parallelism across time steps

Consequently, the 12.68× encoder acceleration did not translate into a 12.68× end-to-end speed-up.

After the encoder was accelerated, ConvLSTM became the dominant runtime bottleneck.

This is an important performance-engineering lesson: accelerating one component can move the bottleneck to another part of the system.


Correctness Validation

The CUDA implementation was compared with the reference implementation for the tested tensor shapes and configurations.

The optimisation work focused on reducing execution time while preserving the expected computational behaviour. Model-quality evaluation and runtime evaluation were treated as separate concerns.


Engineering Challenges

Several engineering challenges appeared during the implementation.

1. Correct Tensor Indexing

The CUDA kernel had to reproduce the same logical output as the reference convolution operation.

A small indexing error could generate incorrect feature maps without necessarily causing a runtime failure.

2. Memory Management

The im2col transformation created additional intermediate data.

This required careful allocation, reuse, and release of GPU memory.

3. Synchronisation

Threads sharing data through shared memory had to synchronise at appropriate points.

Missing or unnecessary synchronisation could cause incorrect results or reduced performance.

4. Kernel Configuration

Thread-block dimensions and tile sizes affected:

  • Occupancy
  • Shared-memory usage
  • Memory access
  • Work distribution
  • Overall kernel performance

5. PyTorch Integration

The extension had to account for tensor shapes, data types, device placement, memory layout, compilation, linking, and output comparison.

6. Measuring the Correct Bottleneck

Improving one component changed the relative cost of other components.

Profiling therefore had to be repeated after major optimisations.


Engineering Lessons

1. Optimising One Component Does Not Guarantee an Equivalent End-to-End Improvement

Once the encoder was accelerated, ConvLSTM represented a larger proportion of the remaining runtime.

2. im2col Makes Convolution GPU-Friendly but Introduces Memory Overhead

The transformation enables GEMM-based execution while creating a larger intermediate representation.

3. Shared Memory Is Valuable When Threads Repeatedly Reuse Nearby Data

Its benefit depends on access patterns, tile sizes, synchronisation, and thread-block configuration.

4. Profiling Must Guide Optimisation

Performance work should focus on measured bottlenecks rather than assumptions about which component is slow.

5. Correctness Is as Important as Speed

GPU output should be compared against a trusted reference implementation before performance improvements are accepted.

6. Custom PyTorch Extensions Offer Flexibility at the Cost of Additional Complexity

Device handling, tensor shapes, data types, compilation, numerical validation, and fallback behaviour all require careful attention.


Frequently Asked Questions

What is MSCRED?

MSCRED stands for Multi-Scale Convolutional Recurrent Encoder-Decoder.

It is an architecture designed to model relationships between multiple time-series signals and detect abnormal behaviour through reconstruction error.

What does im2col do?

im2col rearranges overlapping convolution windows into matrix columns, allowing convolution to be expressed as matrix multiplication.

Why did shared memory help?

Shared memory allowed threads in the same block to reuse data without repeatedly loading it from slower global memory. This reduced memory-access overhead for reusable tiles.

Did GPU memory optimisation improve the F1 score?

That was not the purpose of the optimisation, and this article does not claim that it did.

The best recorded F1 score describes anomaly-detection quality in the thesis experiments. The CPU and GPU timing results describe computational performance. They should be interpreted separately.

Why was the encoder speed-up much larger than the total speed-up?

After the encoder became faster, ConvLSTM represented a larger share of total runtime. The overall system was therefore limited by the remaining bottleneck.

Is a Custom CUDA Kernel Always Faster Than PyTorch Operations?

No.

Optimised PyTorch and CUDA libraries are already highly efficient for many operations. A custom kernel is most useful when:

  • The workload has a specialised access pattern
  • Existing operations create unnecessary overhead
  • Profiling identifies a clear bottleneck
  • Correctness and maintenance costs are justified

Can the Original Industrial Dataset Be Shared?

No.

The original dataset contains industrial process information. A public reproduction would require synthetic or appropriately anonymised multivariate time-series data.

Are These Benchmark Results Universal?

No.

Performance depends on GPU architecture, CPU configuration, tensor dimensions, batch size, kernel implementation, memory layout, CUDA and PyTorch versions, compiler settings, and workload characteristics.

The reported numbers apply to the specific experimental setup described in this article.


Limitations and Data-Privacy Considerations

The reported results were obtained on a specific hardware configuration and workload.

Different GPUs, tensor dimensions, batch sizes, memory layouts, CUDA versions, and kernel configurations may produce different results.

The original dataset cannot be published because it contains industrial process information. A public reproduction would therefore require synthetic or appropriately anonymised multivariate time-series data.

This article presents aggregate benchmark measurements and technical methodology rather than the complete industrial dataset or restricted implementation.


Future Work

Future work could focus on:

  • Profiling and optimising the ConvLSTM component
  • Reducing intermediate memory allocation
  • Reducing host-to-device and device-to-device memory movement
  • Comparing the custom implementation with optimised CUDA libraries
  • Evaluating additional tile and thread-block configurations
  • Testing across different GPU architectures
  • Reproducing the workflow using synthetic public data
  • Adding automated correctness and regression tests
  • Measuring kernel-level execution using GPU profiling tools

Conclusion

This work was completed as part of my M.Tech thesis research at the Indian Institute of Technology Bhilai.

It demonstrated how low-level GPU optimisation can be integrated into a deep-learning anomaly-detection pipeline.

The convolutional encoder benefited substantially from:

  • CUDA parallelisation
  • im2col-based lowering
  • GEMM
  • Shared-memory data reuse
  • Custom PyTorch integration

Encoder runtime decreased from 300 seconds to 23.664 seconds in the measured workload.

The broader result also illustrated an important systems principle: once one stage is accelerated, another stage may become the new performance bottleneck.

In this case, ConvLSTM limited the end-to-end improvement even after the encoder achieved a substantial speed-up.

The work reinforced that successful performance engineering requires both low-level optimisation and system-level measurement.


References

  1. Zhang, C., Song, D., Chen, Y., Feng, X., Lumezanu, C., Cheng, W., Ni, J., Zong, B., Chen, H., and Chawla, N. V. (2019). A Deep Neural Network for Unsupervised Anomaly Detection and Diagnosis in Multivariate Time Series Data. Proceedings of the AAAI Conference on Artificial Intelligence, 33(01), 1409–1416. https://doi.org/10.1609/aaai.v33i01.33011409

  2. Shi, X., Chen, Z., Wang, H., Yeung, D.-Y., Wong, W.-K., and Woo, W.-C. (2015). Convolutional LSTM Network: A Machine Learning Approach for Precipitation Nowcasting. Advances in Neural Information Processing Systems 28, 802–810. https://proceedings.neurips.cc/paper_files/paper/2015/hash/07563a3fe3bbe7e3ba84431ad9d055af-Abstract.html

  3. NVIDIA. CUDA C++ Programming Guide. https://docs.nvidia.com/cuda/cuda-c-programming-guide/

  4. PyTorch. Custom C++ and CUDA Operators. https://docs.pytorch.org/tutorials/advanced/cpp_custom_ops.html


Citation and Feedback

If this article informs academic or technical work, please cite the original MSCRED and ConvLSTM papers above.

To refer specifically to my thesis implementation, optimisation process, or reported benchmarks, you may cite this article as:

Vutnoor, R. (2026). “GPU-Accelerating MSCRED with CUDA, im2col, GEMM, and a Custom PyTorch Extension.” DEV Community.

If you found the article useful, a reaction, comment, or constructive technical question on DEV would be appreciated.


I am Ranjith Vutnoor, an AI/ML Software Engineer and IIT Bhilai alumnus working on production RAG systems, LLM evaluation, model fine-tuning, PyTorch, and GPU-accelerated machine learning.

Top comments (0)