Deep Siamese Network for Measuring Similarity of ECG Signals

This article presents an automated neural‑network framework based on a deep Siamese architecture to learn similarity representations between ECG recordings, covering ECG fundamentals, exploratory data analysis, signal preprocessing, model construction with Keras, and demonstrates how the trained network yields similarity scores applicable to broader signal‑matching tasks.

Code DAO
Code DAO
Code DAO
Deep Siamese Network for Measuring Similarity of ECG Signals

This article introduces an automated neural‑network framework for the signal‑matching problem, focusing on biomedical ECG data. It first explains what ECG signals are, why they are important in medical diagnostics, and the need for measuring similarity between two recordings.

Siamese Neural Network Overview

The Siamese network, originally developed by Jane Bromley at AT&T Bell Labs, consists of two identical subnetworks that share weights. Each subnetwork processes a different input, and their outputs are compared using an energy function such as Euclidean distance. This architecture maps high‑dimensional inputs into a target space where semantic similarity can be measured.

Exploratory Data Analysis (EDA)

The workflow begins with exploratory data analysis to inspect the ECG dataset, generate hypotheses, and decide subsequent steps. The provided ExploratoryDataAnalysis class includes methods to check missing values, plot raw signals, create rolling‑window sum plots, profile the dataset, filter outliers, and detect R‑peaks using various detectors (e.g., SW‑T, Christov, Two‑Average, Engzee, Hamilton, Pan‑Tompkins, matched filter).

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
sns.set(rc={'figure.figsize':(11, 4)})
import pathlib
from scipy import stats
from ecgdetectors import Detectors
import warnings
warnings.filterwarnings('ignore')

class ExploratoryDataAnalysis():
    def missing(x):
        print('Total Missing Elements')
        return sum(x.isnull())
    def print_missing(df):
        print('Missing information in whole dataset')
        print('Missing by col', df.apply(ExploratoryDataAnalysis.missing, axis=0))
        print('Missing by row', df.apply(ExploratoryDataAnalysis.missing, axis=1))
    def plots(dataframe, cols):
        dataframe[cols].plot()
    def sumplots_rw(dataframe, cols, window:int):
        processed_data[cols].rolling(window=window).mean().plot(subplots=True)
    def profiling(df):
        import pandas_profiling as pp
        html_report = pp.ProfileReport(df, title='Signal Profiling Report')
        html_report.to_file('./profiling_report.html')
    def filter_outliers(dataframe, z_threshold):
        constraints = dataframe.select_dtypes(include=[np.number])\
            .apply(lambda x: np.abs(stats.zscore(x)) < z_threshold)\
            .all(axis=1)
        dataframe.drop(dataframe.index[~constraints], inplace=True)
        dataframe.reset_index(drop=True, inplace=True)
        return dataframe
    def r_peak_plots_arg(dataframe, det_type, col_index, fs:int):
        unfiltered_ecg = dataframe.iloc[:,col_index]
        detectors = Detectors(fs)
        det_type = str(det_type.strip('"'))
        detector_call = getattr(detectors, det_type)
        r_peaks = detector_call(unfiltered_ecg)
        plt.figure()
        plt.plot(unfiltered_ecg)
        plt.plot(r_peaks, unfiltered_ecg[r_peaks], 'ro')
        plt.title('Detected R-peaks')
        plt.show()
        return det_type, col_index

Running the EDA functions produces plots such as the rolling‑window sum of five ECG channels and R‑peak detection visualizations (e.g., using the Christov detector).

Rolling window plot of ECG1‑ECG5
Rolling window plot of ECG1‑ECG5

Siamese Model Construction

The Siamese_Model function builds a Keras model that takes two input vectors of equal length, computes squared differences, element‑wise products, concatenates these metrics, and passes them through three parallel dense pathways before a final dense layer outputs a similarity score.

def Siamese_Model(features):
    """Implementation of the Siamese Network
    Args:
        features (int): number of features
    Returns:
        [keras model]: siamese model
    """
    inp1 = Input(shape=(features,))
    inp2 = Input(shape=(features,))
    diff = Subtract()([inp1, inp2])
    L2 = Multiply()([diff, diff])          # squared difference
    prod = Multiply()([inp1, inp2])          # product proximity
    combine = Concatenate(axis=1)([L2, prod])
    path1 = Dense(64)(L2)
    path1 = BatchNormalization()(path1)
    path1 = Dropout(0.25)(path1)
    path1 = Activation('relu')(path1)
    path2 = Dense(64)(prod)
    path2 = BatchNormalization()(path2)
    path2 = Dropout(0.25)(path2)
    path2 = Activation('relu')(path2)
    path3 = Dense(64)(combine)
    path3 = BatchNormalization()(path3)
    path3 = Dropout(0.25)(path3)
    path3 = Activation('relu')(path3)
    paths = Concatenate(axis=1)([path1, path2, path3])
    top = Dense(256)(paths)
    top = BatchNormalization()(top)
    top = Dropout(0.25)(top)
    top = Activation('relu')(top)
    out = Dense(1)(top)   # output similarity score
    siamese_model = Model(inputs=[inp1, inp2], outputs=[out])
    return siamese_model

The model is compiled with mean‑squared error loss, the Adam optimizer, and metrics including MSE, MAE, MAPE, and cosine similarity.

# create Siamese network architecture
sm = Siamese.Siamese_Model(5)  # 5 input features
sm.compile(loss='mse', optimizer='adam', metrics=['mse', 'mae', 'mape', 'cosine'])
# estimate similarity score for two ECG feature vectors
score = sm(inputs=[np.array(activity_input_sequence_1), np.array(activity_input_sequence_2)])
SigSimNet architecture diagram
SigSimNet architecture diagram

Conclusion

The article demonstrates how a Siamese neural network can be built to solve signal‑matching problems for ECG data, producing a similarity score that quantifies how closely two recordings align. The same architecture can be extended to other contexts such as images, video, text, or point‑cloud data by adapting the input feature extraction.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Deep LearningKerasSiamese NetworkSignal ProcessingECGSignal Similarity
Code DAO
Written by

Code DAO

We deliver AI algorithm tutorials and the latest news, curated by a team of researchers from Peking University, Shanghai Jiao Tong University, Central South University, and leading AI companies such as Huawei, Kuaishou, and SenseTime. Join us in the AI alchemy—making life better!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.