Добавил:
kiopkiopkiop18@yandex.ru Вовсе не секретарь, но почту проверяю Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

5 курс / ОЗИЗО Общественное здоровье и здравоохранение / Проектирование_мультимодальных_интерфейсов_мозг_компьютер

.pdf
Скачиваний:
1
Добавлен:
24.03.2024
Размер:
10.34 Mб
Скачать

Нейронные сети

plt.legend()

plt.plot(list(range(0, eeg_sample_length)), sample_ positives[0][0], color = "#bbbbbb", label = "One Sample")

plt.plot(list(range(0, eeg_sample_length)), sample_ positives[0].mean(dim = 0), color = "g", label = "Mean Positive")

plt.plot(list(range(0, eeg_sample_length)), sample_ negatives_high[0], color = "#bbbbbb")

plt.plot(list(range(0, eeg_sample_length)), sample_ negatives_high.mean(dim = 0), color = "r", label = "Mean Negative")

plt.plot(list(range(0, eeg_sample_length)), sample_ negatives_low[0], color = "#bbbbbb")

plt.plot(list(range(0, eeg_sample_length)), sample_ negatives_low.mean(dim = 0), color = "r")

plt.plot(list(range(0, eeg_sample_length)), [0.75] * eeg_sample_length, color = "k")

plt.plot(list(range(0, eeg_sample_length)), [0.25] * eeg_sample_length, color = "k")

plt.show()

Проверка работоспособности модели

Итак, мы обучили сеть на примере полученных данных. Давайте классифицируем оставшиеся образцы тестовых данных, чтобы увидеть, действительно ли обучение сработало.

Ниже мы классифицируем данные, на которых сеть не обучалась, чтобы увидеть, может ли она экстраполировать данные из обучающего набора, на котором она училась.

# Классифицируем положительный тестовый набор данных predicted_positives = tutorial_model(test_positives).

data.tolist()

# Распечатать результаты

for index, value in enumerate(predicted_positives): print("Положительное значение теста {1} Value scored:

{0:.2f}%".format(value[0] * 100, index + 1))

print()

# Классифицируем отрицательный тестовый набор данных predicted_negatives = tutorial_model(test_negatives).

99

Рекомендовано к покупке и изучению сайтом МедУнивер - https://meduniver.com/

Глава 5. Применение методов машинного обучения для ИМК

data.tolist()

# Распечатать результаты

for index, value in enumerate(predicted_negatives): print("Negative Test {1} Value scored: {0:.2f}%".

format(value[0] * 100, index + 1))

print()

print(«Ниже приведена диаграмма рассеяния некоторых об разцов «)

print(«Обратите внимание наотдельные области красных изеленых точек. Если ввод этого \n» +

«сеть представляла собой простые координаты x и y, квадратная полоса вцентре былабы \n» +

«представляют \"пространство решений\" нашей сети. Тем неменее фактический сигнал ЭЭГ\n» +

«выборка представляет собой массив изнескольких точек иможет пересечь границу влюбой момент».)

print("Plotted is one positive sample in green and two negative samples in red")

rcParams['figure.figsize'] = 10, 5 plt.scatter(list(range(0, eeg_sample_length)), test_

positives[3], color = "#00aa00") plt.plot(list(range(0, eeg_sample_length)), test_

positives[3], color = "#bbbbbb") plt.scatter(list(range(0, eeg_sample_length)), test_

negatives[0], color = "#aa0000") plt.plot(list(range(0, eeg_sample_length)), test_

negatives[0], color = "#bbbbbb") plt.scatter(list(range(0, eeg_sample_length)), test_

negatives[9], color = "#aa0000") plt.plot(list(range(0, eeg_sample_length)), test_

negatives[9], color = "#bbbbbb") plt.ylim([0, 1])

plt.show()

Если бы вход этой сети был простыми координатами x и y, квадратная полоса в центре графика представляла бы «пространство решений» нашей сети. Однако реальная выборка сигнала ЭЭГ представляет собой массив из нескольких точек и в любой момент может пересечь границу. На полученном графике показан один положитель-

100

Получение данных из набора данных MNE EEG

ный образец зеленым цветом и два отрицательных образца красным цветом. Полученные результаты показывают, что нейронная сеть правильно классифицирует простой набор тестовых данных ЭЭГ и готова к тестированию с реальными образцами. Читателю остается самостоятельно провести дополнительные эксперименты с выборочными данными, например, добавив перекрытие между «хорошими» и «плохими» наборами данных.

Получение данных из набора данных MNE EEG

Библиотека MNE — это удобный и открытый ресурс, который специализируется на обработке сигналов мозга и предоставляет доступ к базам данных образцов [46]. Мы будем использовать одну из этих баз данных P300 для обучения нашей сети.

data_path = mne.datasets.sample.data_path() data_path

Чтобы загрузить базу данных с помощью Python, нужно указать путь к набору данных, который мы собираемся анализировать. В данном случае это образец аудиовизуальной базы данных, в котором данные ЭЭГ были отфильтрованы в пределах 0–40 Гц.

Исходные данные, которые мы получаем, являются необработанными, то есть просто набором потоковых выборок биомедицинских сигналов из многих каналов ЭЭГ, в отличие от сигналов, нарезанных или сфокусированных на интересующем событии.

raw_fname = data_path + '/MEG/sample/sample_audvis_ filt 0–40_raw.fif'

event_fname = data_path + '/MEG/sample/sample_audvis_ filt 0–40_raw-eve.fif'

#Получим ссылку набазу данных ипредварительно загру зим воперативную память

raw_data = mne.io.read_raw_fif(raw_fname, preload=True)

#Вторая ссылка

#точка устанавливается как среднее значение всех на пряжений сигналов ЭЭГ спомощью следующей функции.

#Также можно установить опорное напряжение надругое число.

raw_data.set_eeg_reference()

101

Рекомендовано к покупке и изучению сайтом МедУнивер - https://meduniver.com/

Глава 5. Применение методов машинного обучения для ИМК

Далее загружаем базу данных и сохраняем ее в переменной с именем «raw_data». Функция выбора позволяет нам выбирать интересующие источники. В этом случае мы собираем данные с электродов ЭЭГ. Данные ЭОГ также включены, поскольку они регистрируются с использованием одних и тех же электродов. Используемый набор сырых данных включает и данные МЭГ (магнитоэнцефалография), но их анализ предлагается провести читателю самостоятельно.

# Определим, какие данные хотим выгрузить изнабора данных

raw_data = raw_data.pick(picks=["eeg","eog"]) picks_eeg_only = mne.pick_types(raw_data.info,

eeg=True,

eog=True,

meg=False,

exclude='bads')

Необработанный файл ЭЭГ содержит события, которые позволяют узнать, когда что то произошло во время записи ЭЭГ. Например, события с идентификатором 5 соответствуют случаям, когда участникам показывали смайлики, а события 1–4 соответствуют испытаниям, в которых участникам показывали шахматную доску либо с левой, либо с правой стороны экрана и с тональным сигналом, направленным либо в левое ухо, либо в правое ухо. Мы знаем, что в этих испытаниях участникам был представлен смайлик (события с идентификатором 5, которые вызовут отклик P300). Итак, мы начнем с нарезки (или эпохирования) данных за 0.5 с до того, как изображение было представлено (чтобы иметь базовую линию), и через 1 с после того, как изображение было представлено. Мы можем изменить это значение на значения близкие к 0.3 с, что позволит обрезать кадр точно до того места, где находится P300.

events = mne.read_events(event_fname) event_id = 5

tmin = –0.5 tmax = 1

epochs = mne.Epochs(raw_data, events, event_id, tmin, tmax, proj=True,

picks=picks_eeg_only, baseline=(None, 0), preload=True,

reject=dict(eeg=100e 6, eog=150e 6),

verbose = False) print(epochs)

102

Получение данных из набора данных MNE EEG

К сожалению, указанный набор данных содержит только 12 примеров событий P300. Обычно в приложении должно быть не менее 100 примеров. Для этого используем один канал ЭЭГ с наивысшим показателем компонента P300 для обучения нашей сети. Можно использовать более одного канала, но для простоты используем только один. На приведенном ниже графике датчика показано название канала ЭЭГ, который мы используем.

#Это канал, используемый для мониторинга ответа P300. channel = «EEG 058»

#Показать график положения датчика, который используется sensor_position_fi gure = epochs.plot_sensors(show_

names=[channel])

Получим отображение с положениями датчиков, как на рис. 53.

Sensor positions (eeg)

EEG 058

Рис. 53. Представление исходного набора данных

На рис. 54 приведен график тепловой карты, представляющий 12 событий P300, найденных в наборе данных. На этом графике, в области 0.3–0.4 с, можно увидеть заметное отклонение сигнала— искомый компонент P300. Сразу становится очевидна сложность его обнаружения, даже если линейный график под тепловым графиком представляет собой среднее значение для 12 образцов.

epochs.plot_image(picks=channel)

Теперь, когда есть данные о компонентах P300, нужны контрпримеры, чтобы сопоставить эти данные. Также соберем все другие события, содержащиеся в нашем наборе данных.

103

Рекомендовано к покупке и изучению сайтом МедУнивер - https://meduniver.com/

Глава 5. Применение методов машинного обучения для ИМК

event_id=[1,2,3,4]

epochsNoP300 = mne.Epochs(raw_data, events, event_id, tmin, tmax, proj=True,

picks=picks_eeg_only, baseline=(None, 0), preload=True,

reject=dict(eeg=100e 6, eog=150e 6),

verbose = False) print(epochsNoP300)

Рис. 54. Тепловая карта набора данных Р300

В приведенном наборе данных значительно больше событий, отличныхот P300,поэтомубудемиспользоватьтолькоподмножество,чтобысохранить необходимый баланс между данными класса. Самое важное, что следует отметить на графике (рис. 55)—это то, что для среднего значения данных нет значительного отклонения во временном интервале 0.3–0.4 с.

Рис. 55. Тепловая карта набора данных Р300

104

Получение данных из набора данных MNE EEG

Вот еще один полезный универсальный график (рис. 56) для визуализации того, как выглядят эти образцы. Для его создания используем следующий код:

mne.viz.plot_compare_evokeds({'P300': epochs. average(picks=channel), Другие: epochsNoP300[0:12]. average(picks=channel)})

Обратите внимание на то, что изображение, описанное в примере задачи ранее, показано в момент времени равный 0 с. Синяя линия (рис. 56) соответствует тому, когда испытуемому показывали смайлик, а оранжевая линия соответствует тому, когда испытуемому показывали шахматную доску.

Далее нужно сделать еще несколько шагов, чтобы полностью преобразовать данные набора данных в то, что легко усваивается нейронной сетью:

масштабируйте данные, помня о возможных выбросах. Если мы просто масштабируем данные, используя минимальное и максимальное значение набора данных, рискуем тем, что наши данные будут определяться выбросами, а обычные значения будут сжаты в центре. Чтобы избежать этого, можем использовать некоторые статистические значения (например, несколько стандартных отклонений от среднего) для масштабирования данных.

Создайте переменную метки, где образцы P300 помечены как 1,

аобразцы, отличные от P300, помечены как 0.

Объедините данные в единую структуру данных.

Выполните различные преобразования типов данных.

Рис. 56. Визуализация полученного сигнала Р300

105

Рекомендовано к покупке и изучению сайтом МедУнивер - https://meduniver.com/

Глава 5. Применение методов машинного обучения для ИМК

Блок кода ниже выполняет эти шаги последовательно:

eeg_data_scaler = RobustScaler()

# Унас есть 12 p300 образцов

p300s = np.squeeze(epochs.get_data(picks=channel))

# Унас есть 208 образцов, отличных от p300.

others = np.squeeze(epochsNoP300.get_data(picks=channel))

#Отмасштабируем данные p300, используя RobustScaler p300s = p300s.transpose()

p300s = eeg_data_scaler.fit_transform(p300s) p300s = p300s.transpose()

#Отмасштабируем данные, отличные от p300, используя

RobustScaler

others = others.transpose()

others = eeg_data_scaler.fit_transform(others) others = others.transpose()

## Подготовим обучающую итестовые выборки

#Определим выборки, обучающие итестовые образцы ис тинных P300

p300s_train = p300s[0:9] p300s_test = p300s[9:12]

p300s_test = torch.tensor(p300s_test).float()

#Определим выборки, обучающие итестовые образцы неистинных P300

others_train = others[30:39] others_test = others[39:42]

others_test = torch.tensor(others_test).float()

#Объедините всё вих окончательные структуры training_data = torch.tensor(np.concatenate((p300s_

train, others_train), axis = 0)).float() positive_testing_data = torch.tensor(p300s_test).float() negative_testing_data = torch.tensor(others_test).float()

# Распечатайте размер каждой изнаших структур данных print("training data count: " + str(training_data.shape[0])) print("positive testing data count: " + str(positive_

testing_data.shape[0]))

106

Получение данных из набора данных MNE EEG

print("negative testing data count: " + str(negative_ testing_data.shape[0]))

# Создаем учебные метки

labels = torch.tensor(np.zeros((training_data.shape[0],1))). float()

labels[0:10] = 1.0

print("training labels count: " + str(labels.shape[0]))

Классификация набора данных  с помощью нейронной сети

Используя сети, созданные на предыдущем шаге, будем тренироваться на реальных данных ЭЭГ, начиная с весов по умолчанию, заканчивая любым обучением с созданными нами образцами данных.

# Убедитесь, что мы каждый раз начинаем снепредобучен ной модели

tutorial_model = torch.load("/home/tutorial_model_ default_state")

##Определим функцию обучения, которую необходимо по вторно инициализировать при каждой загрузке

optimizer = torch.optim.Adam(tutorial_model. parameters(), lr = learning_rate)

##Используем процедуру обучения спримерами данных print(«Ниже приведен график потерь для сеанса обуче

ния») набору данных. train_network(training_data, labels, iterations = 50)

Получим график, как на рис. 57.

Итак, давайте классифицируем наборы тестовых данных.

# Классифицируем положительный тестовый набор данных classification_1 = tutorial_model(positive_testing_data) for index, value in enumerate(classification_1.data.

tolist()):

print("P300 Положительная классификация {1}: {0:.2f}%". format(value[0] * 100, index + 1))

print()

# Классифицируем отрицательный тестовый набор данных classification_2 = tutorial_model(negative_testing_data)

107

Рекомендовано к покупке и изучению сайтом МедУнивер - https://meduniver.com/

Глава 5. Применение методов машинного обучения для ИМК

for index, value in enumerate(classifi cation_2.data. tolist()):

print("P300 Отрицательная классификация {1}: {0:.2f}%". format(value[0] * 100, index + 1))

P300 Отрицательная классификация 1: 100.00%

P300 Отрицательная классификация 2: 99.94%

P300 Отрицательная классификация 3: 100.00%

P300 Отрицательная классификация 1: 99.92%

P300 Отрицательная классификация 2: 0.04%

P300 Отрицательная классификация 3: 0.00%

Рис. 57. Функция потерь для набора Р300

Обратите внимание: в то время как положительные тестовые образцы P300 показали себя очень хорошо, один из отрицательных образцов P300 был неправильно классифицирован. Отчасти это является следствием отсутствия достаточного количества данных для обучения. Сеть не смогла отличить один из отрицательных образцов от остальных положительных. Давайте посмотрим, как образцы выглядят рядом друг с другом:

rcParams['fi gure.fi gsize'] = 15, 5

plt.plot(list(range(0, eeg_sample_length)), positive_ testing_data[0], color = "g")

plt.plot(list(range(0, eeg_sample_length)), positive_ testing_data[1], color = "g")

108