背景
在本文中,我们将探讨如何使用1维卷积神经网络(Conv1D)对EEG信号进行分析。1维卷积是一种沿着时间序列执行的卷积操作,非常适合处理EEG这样的时序数据。我们将继续使用P300数据集,并展示如何将其转换为适合PyTorch的输入格式,然后使用Conv1D模型进行分类。
代码实现
导入基本库
import mne
from mne import create_info
from mne.io import RawArray
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
from torch.utils.data import TensorDataset, WeightedRandomSampler
加载数据
df = pd.read_csv("../data/p300-6trials-12rep-chaky.csv")
df = df.drop(["timestamps"], axis=1)
df.columns = ['P4', 'Pz', 'P3', 'PO4', 'POz', 'PO3', 'O2', 'O1', 'Marker']
在数据集中,Marker
列标识事件的发生,如目标闪烁等。
转换数据为MNE对象
def df_to_raw(df):
sfreq = 125 # 采样频率
ch_names = list(df.columns)
ch_types = ['eeg'] * (len(df.columns) - 1) + ['stim']
ten_twenty_montage = mne.channels.make_standard_montage('standard_1020')
df = df.T
df[:-1] *= 1e-6 # 转换为伏特
info = create_info(ch_names=ch_names, ch_types=ch_types, sfreq=sfreq)
raw = mne.io.RawArray(df, info)
raw.set_montage(ten_twenty_montage)
raw.compute_psd().plot()
return raw
raw = df_to_raw(df)
去除伪影
伪影是信号中的噪声,需要在分析前去除。例如,电源线噪声和低频漂移可以通过滤波器来去除。
raw.notch_filter(50) # 去除50Hz电源线噪声
raw.filter(1, 40) # 滤除低于1Hz和高于40Hz的信号
raw.compute_psd().plot()
分割数据(Epoching)
将数据按事件进行分段,这个过程称为epoching。我们提取事件发生前0.1秒到事件后0.6秒的EEG数据。
from mne import Epochs, find_events
def getEpochs(raw, event_id, tmin, tmax, picks):
events = find_events(raw)
epochs = Epochs(raw, events=events, event_id=event_id,
tmin=tmin, tmax=tmax, baseline=None, preload=True, verbose=False, picks=picks)
print('sample drop %: ', (1 - len(epochs.events) / len(events)) * 100)
return epochs
event_id = {'Non-Target': 1, 'Target' : 2}
tmin = -0.1
tmax = 0.6
eeg_channels = mne.pick_types(raw.info, eeg=True)
picks = eeg_channels
epochs = getEpochs(raw, event_id, tmin, tmax, picks)
特征提取
将数据转换为PyTorch模型输入的格式,并进行归一化处理。
X = epochs.get_data()
y = epochs.events[:, -1]
scalers = {i: MinMaxScaler(feature_range=(-1, 1)) for i in range(X.shape[2])}
for i in range(X.shape[2]):
X[:, :, i] = scalers[i].fit_transform(X[:, :, i])
X_train, X_val, X_test = X[:504], X[504:648], X[648:]
y_train, y_val, y_test = y[:504], y[504:648], y[648:]
X_train, X_val, X_test = torch.FloatTensor(X_train), torch.FloatTensor(X_val), torch.FloatTensor(X_test)
y_train, y_val, y_test = torch.LongTensor(y_train) - 1, torch.LongTensor(y_val) - 1, torch.LongTensor(y_test) - 1
构建模型
class eegConv1d(nn.Module):
def __init__(self, input_size=8, hidden_size=50, out_size=2):
super().__init__()
self.conv1d = nn.Conv1d(input_size, hidden_size, kernel_size=3)
self.linear = nn.Linear(4300, out_size)
def forward(self, seq):
out = self.conv1d(seq)
out = out.reshape(seq.size(0), -1)
out = self.linear(out)
return out
model = eegConv1d().to(device)
训练模型
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
epochs = 20
for epoch in range(epochs):
model.train()
for X_batch, y_batch in train_loader:
X_batch, y_batch = X_batch.to(device), y_batch.to(device)
optimizer.zero_grad()
y_pred = model(X_batch)
loss = criterion(y_pred, y_batch)
loss.backward()
optimizer.step()
print(f"Epoch {epoch+1}, Loss: {loss.item()}")
测试模型
model.eval()
with torch.no_grad():
correct, total = 0, 0
for X_batch, y_batch in test_loader:
X_batch, y_batch = X_batch.to(device), y_batch.to(device)
y_pred = model(X_batch)
_, predicted = torch.max(y_pred.data, 1)
total += y_batch.size(0)
correct += (predicted == y_batch).sum().item()
print(f"Accuracy: {100 * correct / total:.2f}%")
结语
在上一篇文章中,我们介绍了如何使用LSTM模型对P300数据集进行分析。本篇文章进一步探讨了1维卷积神经网络(Conv1D)在EEG信号处理中的应用。通过对相同的数据集进行不同的模型实验,我们能够更加深入地理解不同模型在处理EEG信号时的表现和特点。
与LSTM模型相比,Conv1D模型能够更好地捕捉到时序数据中的局部特征,这使得它在处理EEG这样的高维度时间序列数据时具有独特的优势。我们的实验结果表明,Conv1D模型在分类任务中的表现是可行的,并为未来的研究和应用提供了有价值的参考。
接下来,我们将继续探索其他深度学习模型在EEG信号处理中的应用,尤其是如何利用更复杂的网络结构和数据增强技术进一步提升模型的性能。我们相信,通过不断的探索和创新,能够在脑科学和神经技术领域取得更大的突破。
如果你觉得这篇博文对你有帮助,请点赞、收藏、关注我,并且可以打赏支持我!
欢迎关注我的后续博文,我将分享更多关于人工智能、自然语言处理和计算机视觉的精彩内容。
谢谢大家的支持!