EEG-API / prediction.py
MorganBrizon's picture
Update prediction.py
dd5efa8 verified
Raw
History Blame Contribute Delete
6.15 kB
import numpy as np
import torch
import tensorflow as tf
import pandas as pd
import joblib
import mne
from sklearn.metrics import confusion_matrix, f1_score, accuracy_score
from preprocessing import preprocess_eeg_file
from preprocessing_2dcnn import convert_epoch_to_spectrogram
from preprocessing_epilepsynet import *
from EpilepsyNet_model import TimeSeriesAttentionClassifier
from eegnet_model import EEGNet
def aggregate_predictions(spectrogram_list, model, threshold=0.5):
X = np.array([np.transpose(s, (1, 2, 0)) for s in spectrogram_list])
print(f'---Aggregating predictions from {len(spectrogram_list)} segments---')
preds = model.predict(X)
mean_prob = np.mean(preds[:, 1])
segment_probs = preds[:, 1].tolist()
final_label = 1 if mean_prob >= threshold else 0
return final_label, mean_prob, segment_probs
def predict_eeg_recording(edf_path, model_name='2DCNN', threshold=0.5):
if model_name == '2DCNN':
model = tf.keras.models.load_model('model1_2dcnn.h5')
channels = ["EEG FP1-REF", "EEG FP2-REF", "EEG F3-REF", "EEG F4-REF", "EEG C3-REF"]
preprocessed_df = preprocess_eeg_file(edf_path, fmin=1.0, fmax=45.0, segment_lenght=5, overlap=2, desired=channels)
if preprocessed_df is None or preprocessed_df.empty:
raise ValueError("EEG file could not be preprocessed or no valid segments found.")
spectrogram_list = preprocessed_df.apply(
lambda row: convert_epoch_to_spectrogram(row, channels, fs=250, nperseg=128, noverlap=64), axis=1
).tolist()
return aggregate_predictions(spectrogram_list, model, threshold)
elif model_name == 'EEGNet':
loaded = joblib.load("eegnet_model.joblib")
state_dict = loaded["model_state_dict"]
model = EEGNet(n_channels=21, n_samples=1250, num_classes=2)
model.load_state_dict(state_dict)
channels = [
'EEG FP1-REF', 'EEG FP2-REF', 'EEG F3-REF', 'EEG F4-REF', 'EEG C3-REF', 'EEG C4-REF',
'EEG P3-REF', 'EEG P4-REF', 'EEG O1-REF', 'EEG O2-REF', 'EEG F7-REF', 'EEG F8-REF',
'EEG T3-REF', 'EEG T4-REF', 'EEG T5-REF', 'EEG T6-REF', 'EEG FZ-REF', 'EEG CZ-REF',
'EEG PZ-REF', 'EEG ROC-REF', 'EEG LOC-REF'
]
preprocessed_df = preprocess_eeg_file(
edf_path, fmin=1.0, fmax=45.0, segment_lenght=5, overlap=0, desired=channels
)
if preprocessed_df is None or preprocessed_df.empty:
raise ValueError("EEG file could not be preprocessed or no valid segments found.")
timeseries_list = preprocessed_df.apply(
lambda row: convert_epoch_to_timeseries(row, channels), axis=1
).tolist()
return aggregate_predictions_EEGNET(timeseries_list, model, threshold)
elif model_name == 'EpilepsyNet':
raw = mne.io.read_raw_edf(edf_path, preload=True, verbose='ERROR')
eeg_cols = ['EEG FP1', 'EEG FP2', 'EEG F3', 'EEG F4', 'EEG C3', 'EEG C4', 'EEG P3', 'EEG P4',
'EEG O1', 'EEG O2', 'EEG F7', 'EEG F8', 'EEG T3', 'EEG T4', 'EEG T5', 'EEG T6',
'EEG T1', 'EEG T2', 'EEG FZ', 'EEG CZ', 'EEG PZ']
parameters = {
'eeg_cols': eeg_cols,
'segment_duration': 60.0,
'n_segments_per_file': 12,
'samples_per_segment': 1250,
'random_state': 42
}
X = process_raw_files(
raw_file=raw,
eeg_cols=eeg_cols,
segment_duration=parameters['segment_duration'],
n_segments_per_file=parameters['n_segments_per_file'],
random_state=parameters['random_state']
)
X_std = standardize_data(X)
corr_matrix = compute_correlation_matrix(X_std)
upper_triangle_matrix = extract_upper_triangle(corr_matrix)
X_tensor = torch.tensor(upper_triangle_matrix, dtype=torch.float32)
X_tensor = X_tensor.unsqueeze(0)
input_dim = 210
embed_dim = 256
num_heads = 16
model = TimeSeriesAttentionClassifier(input_dim, embed_dim, num_heads)
model.load_state_dict(torch.load('EpilepsyNet.pth'))
model.eval()
outputs, _ = model(X_tensor)
predicted = (outputs >= 0.5).float()
prob = outputs.float().squeeze().item()
return int(predicted), prob, [prob]
def convert_epoch_to_timeseries(epoch_row, channels):
ts_list = []
for ch in channels:
if ch in epoch_row:
ts = epoch_row[ch]
ts_list.append(ts)
return np.stack(ts_list, axis=0)
def aggregate_predictions_EEGNET(segment_list, model, threshold):
model.eval()
preds = []
with torch.no_grad():
for seg in segment_list:
seg_tensor = torch.tensor(seg, dtype=torch.float32)
seg_tensor = seg_tensor.unsqueeze(0).unsqueeze(0)
output = model(seg_tensor)
prob = torch.softmax(output, dim=1)[0].cpu().numpy()
preds.append(prob)
avg_pred = np.mean(preds, axis=0)
segment_probs = [float(p[1]) for p in preds]
final_class = int(avg_pred[1] >= threshold)
return final_class, float(avg_pred[1]), segment_probs
def predict_ensemble_eeg_recording(edf_path, ensemble_method, threshold=0.5):
pred_prob_list = []
votes = []
for model_name in ["2DCNN", "EEGNet", "EpilepsyNet"]:
pred_label, prob, _ = predict_eeg_recording(edf_path, model_name=model_name, threshold=threshold)
pred_prob_list.append(prob)
votes.append(int(prob >= threshold))
print(f"Prediction from {model_name}: label={pred_label}, probability={prob}")
if ensemble_method.lower() == "average":
avg_prob = np.mean(pred_prob_list)
final_class = int(avg_prob >= threshold)
print("Averaged probability:", avg_prob)
return final_class, avg_prob, []
elif ensemble_method.lower() == "voting":
final_class = int(round(np.mean(votes)))
print("Votes from each model:", votes)
return final_class, votes, []
else:
raise ValueError("Ensemble method must be either 'average' or 'voting'.")