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

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

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

Метод опорных векторов (SVM)

Процесс оптимизации SVM будет пытаться определить гиперплоскость для достижения трех разных правил с убывающей важностью.

Правило 1. Минимизация количества неправильно классифицированных экземпляров. Это основная цель построения гиперплоскости. Однако могут быть случаи, когда невозможно найти гиперплоскость, которая правильно разделяет все классы, и на основе которой можем определить точность нашего алгоритма. На рис. 49 показано, что линия A представляет лучший вариант для оптимизации SVM, чем линия B.

Рис. 49. Пример деления гиперплоскости [73]

Правило 2. Гиперплоскость должна максимизировать расстояние до ближайшей точки любой из меток разных классов, другими словами, гиперплоскость должна быть расположена как можно дальше от точек выборки (не нарушая при этом правило 1). На рис. 50 линия А соответствует этому правилу лучше, чем линия В.

Рис. 50. Пример оптимизации гиперплоскости [73]

89

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

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

Правило 3. В случае, когда одна линия не может отделить один класс от другого (например, когда точки одного класса окружают точки другого класса), тогда можно использовать так называемый «ядерный трюк» (англ. kernel trick). Он заключается в следующем: алгоритм SVM использует некоторые математические преобразования для размещения классов данных на разных уровнях, что поможет найти гиперплоскость, удовлетворяющую требуемому условию. Ядерный трюк получил свое название из-за использования ядерных функций, которые позволяют им оперировать в неявном пространстве признаков высокой размерности. На практике доступно для использования несколько типов ядерных функций, однако чаще всего используется функция радиального базиса, значение которой зависит только от нормы аргумента. Пример, показанный на рис. 46, может быть решен с помощью ядерного трюка, чтобы найти реальную границу между двумя командами. Отметим некоторые важные аспекты, которые следует учитывать при реализации алгоритмов SVM:

функции всегда должны быть числовыми;

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

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

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

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

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

90

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

вдоль своего аксона на другие нейроны ниже. Не все нейроны связаны одинаковым образом, некоторые нейроны могут иметь более сильные связи, чем другие, —это вес соединения. Каждый нейрон в нейронной сети связан с весом и так называемым «алгоритмом активации», который в конечном итоге решает, какой масштаб вывода создается при получении определенного накопленного количества ввода.

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

Компоненты Р300 могут проявляться по-разному в зависимости от того, от какого субъекта берутся данные ЭЭГ, а также от возможности нелинейного шума. Нам нужен алгоритм, способный адаптироваться к этим возможностям, а также к другим более тонким проблемам, с которыми мы, возможно, еще не сталкивались. Далее разберем на примере, как обучить и развернуть нейронную сеть, способную идентифицировать компоненты Р300, и решить первоначальную проблему идентификации, когда субъект удивлен каким либо изображением.

Искусственные нейронные сети очень малы по сравнению с огромными размерами структур, обнаруженных в мозге. Только несколько нейронов используется для кодирования ввода и вывода (рис. 51).

Однако для задач, в которых категории могут смешиваться, применяется нелинейный подход. В этом суть «проблемы XOR», которая преследовала первых теоретиков машинного обучения. Решение данной проблемы оказалось довольно простым: нужно всего лишь добавить больше слоев в сеть.

Далее в этой главе будут рассмотрены этапы создания и обучения нейронной сети на данных ЭЭГ. Для начала необходимо убедиться, что у вас установлена локальная версия Python не ниже Python 3.7 или выше. Если у вас еще нет совместимой версии Python, то нужно смотреть инструкции по установке в руководстве по Python для начинающих (Beginner's Guide to Python) [74].

Далее нужно будет установить следующие пакеты:

MNE — библиотека для обработки данных ЭЭГ;

MatPlotLib — библиотека для построения графиков;

91

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

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

Scikit-Learn — библиотека для машинного обучения;

PyTorch — библиотека для глубокого машинного обучения.

Рис. 51. Пример нейронной сети для линейных задач

Ниже приведен pip-скрипт, который устанавливает эти библиотеки в Python. Если какие-то из них не работают, то нужно обратиться к соответствующим страницам установки.

# Запустите их из консоли

!pip install mne !pip install sklearn

!pip install matplotlib !pip install torch

!pip install torchvision

!pip install tensorboardX

Для целей этого руководства мы будем отключать предупреждения: import warnings

warnings.fi lterwarnings('ignore')

Импортируйте все необходимые модули. Сюда входят различные подмодули, которые понадобятся, включая объект RobustScaler из scikit:

from collections import OrderedDict from pylab import rcParams

import torch

92

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

import torch.nn as nn

import torchvision.transforms import matplotlib.pyplot as plt import numpy as np

import mne

from sklearn.preprocessing import RobustScaler

Установите параметры рандомизатора для задания уровня согласованности:

torch.manual_seed(100)

Далее инициализируйте проект с несколькими постоянными параметрами:

eeg_sample_count — количество образцов, с которыми мы обучаем нашу сеть;

Learning_rate — насколько быстро сеть имеет тенденцию изменять свои веса;

eeg_sample_length — количество точек данных в выборке;

number_of_classes — количество выходных классов (одна выходная переменная с вероятностью 1.0 = 100%, 0.0 = 0%, что этот образец имеет Р300);

hidden1 — количество нейронов в первом скрытом слое;

hidden2 — количество нейронов во втором скрытом слое;

hidden3 — количество нейронов в третьем скрытом слое;

output — количество нейронов в выходном слое.

# Инициализация параметров

eeg_sample_count = 240 # How many samples are we training

learning_rate = 1e 3 # How hard the network will correct its mistakes while learning

eeg_sample_length = 226 # Number of eeg data points per sample

number_of_classes = 1 # We want to answer the "is this a P300?" question

hidden1 = 500 # Number of neurons in our first hidden layer

hidden2 = 1000 # Number of neurons in our second hidden layer

hidden3 = 100 # Number of neurons in our third hidden layer

output = 10 # Number of neurons in our output layer

93

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

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

Создание нейронной сети

Разрабатываемая в этой главе нейронная сеть будет иметь несколько отдельных компонентов, которые можно настраивать. Далее определим сетевой граф как наборы линейных узлов и узлов активации. Входные данные будут перемещаться по этому графу, накапливая смещения, масштабироваться по весу и преобразовываться с помощью функций активации, пока не пройдут через конечный выходной узел. Он передается через сигмовидную функцию, которая преобразует конечное значение в число 0–1. Это выходное число является предиктором Р300.

## Зададим сеть

tutorial_model = nn.Sequential()

# Input Layer (Size 226 -> 500) tutorial_model.add_module('Input Linear', nn.Linear(eeg_

sample_length, hidden1))

tutorial_model.add_module('Input Activation', nn.CELU())

# Скрытый слой 1 (Size 500 -> 1000) tutorial_model.add_module('Hidden Linear',

nn.Linear(hidden1, hidden2)) tutorial_model.add_module('Hidden Activation', nn.ReLU())

# Скрытый слой 2 (Size 1000 -> 100) tutorial_model.add_module('Hidden Linear2',

nn.Linear(hidden2, hidden3)) tutorial_model.add_module('Hidden Activation2', nn.ReLU())

# Скрытый слой 3 (Size 100 -> 10) tutorial_model.add_module('Hidden Linear3',

nn.Linear(hidden3, 10)) tutorial_model.add_module('Hidden Activation3',

nn.ReLU())

# Выходной слой (Size 10 -> 1) tutorial_model.add_module('Output Linear', nn.Linear(10,

number_of_classes))

tutorial_model.add_module('Output Activation', nn.Sigmoid())

Следующим этапом нам нужно определить функции обучения и потерь (англ. Loss Function, Cost Function). Функции потерь очень важны для предоставления обратной связи о том, насколько хорошо сеть обучается. Нулевое или почти нулевое значение функции потерь означает, что сеть точно предсказывает набор обучающих данных.

94

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

Мы можем использовать это число, чтобы определить, когда сеть «завершила» обучение.

В приведенном ниже коде мы определяем общую функцию потерь, доступную в PyTorch, и простую процедуру обучения, которая обновляет веса сети и вычисляет потери для каждой итерации.

# Определяем функцию потерь loss_function = torch.nn.MSELoss()

# Определияем процедуру обучения

def train_network(train_data, actual_class, iterations):

#Отслеживем потери накаждой итерации обучения loss_data = []

#Начать обучение наопределенное количество итераций for i in range(iterations):

# Начните склассификации

classification = tutorial_model(train_data)

# Определим насколько ошибалась сеть

loss = loss_function(classification, actual_class) loss_data.append(loss)

#Обнуление градиентов оптимизатора накаждой итерации optimizer.zero_grad()

#Научим сеть тому, как вследующий раз сделать лучше loss.backward()

optimizer.step()

#Построим график потерь вконце обучения rcParams['figure.figsize'] = 10, 5 plt.title("Loss vs Iterations") plt.plot(list(range(0, len(loss_data))), loss_data) plt.show()

#Сохраним состояние сети поумолчанию, чтобы мы могли переобучиться свесов поумолчанию.

torch.save(tutorial_model, "/home/tutorial_model_ default_state")

Пример обучения с учителем

Как было сказано выше, из всех алгоритмов машинного обучения существует подмножество, называемое алгоритмами обучения с учителем — это алгоритмы, в которых определены входные и выходные данные каждого примера. Представьте, что у вас выпускной экзамен по онлайн-­курсу. Каждый вопрос на экзамене будет иметь некоторую

95

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

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

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

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

Таким образом, алгоритмы обучения с учителем способны прогнозировать результат на основе некоторых входных характеристик. У этих алгоритмов есть процесс обучения, в ходе которого они учатся предсказывать на основе серии примеров с правильным выводом.

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

Наконец, во время работы с задачами обучения с учителем, обычно при выполнении процесса обучения данные делятся на три разных набора. В нашем случае, когда можем научить алгоритм распознавать P300 из других ЭЭГ, вы можете предоставить набор точек данных, соответствующих волнам P300 и набору других данных ЭЭГ. Затем разделите данные на обучающий набор (используется для ввода в модель для обучения), набор проверки (используется для оценки производительности модели и ее настройки на основе этого) и тестовый набор (используется для оценки окончательной производительности модели). Использование трех отдельных баз данных позволит уменьшить смещение модели, поэтому она хорошо работает при прогнозировании примеров, для которых она никогда раньше не применялась.

Теперь, когда мы узнали немного больше об обучении с учителем, можем применить эти знания для обучения нейронной сети, которую создали.

96

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

Создание образа данных

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

## Create sample data using the parameters sample_positives = [None, None] # Element [0] is the

sample, Element [1] is the class

sample_positives[0] = torch.rand(int(eeg_sample_count / 2), eeg_sample_length) * 0.50 + 0.25

sample_positives[1] = torch.ones([int(eeg_sample_count / 2), 1], dtype=torch.float32)

sample_negatives = [None, None] # Element [0] is the sample, Element [1] is the class

sample_negatives_low = torch.rand(int(eeg_sample_count / 4), eeg_sample_length) * 0.25

sample_negatives_high = torch.rand(int(eeg_sample_count / 4), eeg_sample_length) * 0.25 + 0.75

sample_negatives[0] = torch.cat([sample_negatives_low, sample_negatives_high], dim = 0)

sample_negatives[1] = torch.zeros([int(eeg_sample_count / 2), 1], dtype=torch.float32)

samples = [None, None] # Combine the two

samples[0] = torch.cat([sample_positives[0], sample_ negatives[0]], dim = 0)

samples[1] = torch.cat([sample_positives[1], sample_ negatives[1]], dim = 0)

## Create test data that isn't trained on test_positives = torch.rand(10, eeg_sample_length) *

0.50 + 0.25 # Test 10 good samples

test_negatives_low = torch.rand(5, eeg_sample_length) * 0.25 # Test 5 bad low samples

test_negatives_high = torch.rand(5, eeg_sample_length) * 0.25 + 0.75 # Test 5 bad high samples

test_negatives = torch.cat([test_negatives_low, test_ negatives_high], dim = 0)

97

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

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

print("We have created a sample dataset with " + str(samples[0].shape[0]) + " samples")

print("Half of those are positive samples with a score of 100%")

print("Half of those are negative samples with a score of 0%")

print("We have also created two sets of 10 test samples to check the validity of the network")

Распознавание образа данных

На рис. 52 приведен график, отображающий представление анализируемого набора данных. Среднее значение «хороших» образцов класса 1 представлено зеленой линией. Вы можете видеть, что он характеризуется значениями около 0.5 и большей амплитудой, чем «плохой» класс.

Два средних значения «плохих» образцов класса 0 находятся на верхнем и нижнем краях, представленных красными линиями. Мы создали два «плохих» класса, оба с меньшей амплитудой, чем «хорошие» классы, и сосредоточились либо на 0.25, либо на 0.75. Пример для каждого из этих классов показан светло-серым цветом.

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

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

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

plt.title("Sample Data Set")

98