Как наша команда построила систему обнаружения сонливости на Python.

Члены команды: Грант Чжун, Жуй Инь, Хэ Ван, Аурангзайб Сиддики, Гаурав Чоудхари

Введение

«Каждый 25-й взрослый водитель сообщает, что за последние 30 дней засыпал за рулем»

Если вы ездили раньше, то в какой-то момент вам было дремы за рулем. Мы не хотим признавать это, но это важная проблема с серьезными последствиями, которую необходимо решать. Каждая четвертая дорожно-транспортное происшествие происходит из-за вождения в сонном состоянии, и каждый 25-й взрослый водитель сообщает, что за последние 30 дней засыпал за рулем. Самое страшное в том, что сонное вождение - это не просто засыпание во время вождения. Сонливое вождение может быть таким незначительным, как кратковременное бессознательное состояние, когда водитель не уделяет должного внимания дороге. Сонное вождение приводит к более чем 71 000 травм, 1500 смертельным случаям и денежным убыткам в размере 12,5 миллиардов долларов в год. В связи с актуальностью этой проблемы мы считаем важным разработать решение для обнаружения сонливости, особенно на ранних стадиях, чтобы предотвратить несчастные случаи.

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

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

Источник данных и предварительная обработка

Для наших тренировок и тестов мы использовали Набор данных о реальной сонливости, созданный исследовательской группой из Техасского университета в Арлингтоне специально для обнаружения многоступенчатой ​​сонливости. Конечная цель - выявить не только крайние и видимые случаи сонливости, но и позволить нашей системе обнаруживать более слабые сигналы сонливости. Набор данных состоит примерно из 30 часов видеороликов 60 уникальных участников. Из набора данных мы смогли извлечь черты лица из 44 видео 22 участников. Это позволило нам получить достаточный объем данных как для состояния готовности, так и для состояния сонливости.

Для каждого видео мы использовали OpenCV для извлечения 1 кадра в секунду, начиная с 3-х минутной отметки и до конца видео.

import cv2
data = []
labels = []
for j in [60]:
   for i in [10]:
      vidcap = cv2.VideoCapture(‘drive/My Drive/Fold5_part2/’ +     str(j) +’/’ + str(i) + ‘.mp4’)
      sec = 0
      frameRate = 1
      success, image = getFrame(sec)
      count = 0
      while success and count < 240:
         landmarks = extract_face_landmarks(image)
         if sum(sum(landmarks)) != 0:
            count += 1
            data.append(landmarks)
            labels.append([i])
            sec = sec + frameRate
            sec = round(sec, 2)
            success, image = getFrame(sec)
            print(count)
         else:
            sec = sec + frameRate
            sec = round(sec, 2)
            success, image = getFrame(sec)
            print(“not detected”)

Каждое видео длилось примерно 10 минут, поэтому мы извлекли около 240 кадров для каждого видео, в результате получилось 10560 кадров для всего набора данных.

Всего в кадре было 68 ориентиров, но мы решили оставить ориентиры только для глаз и рта (точки 37–68). Это были важные точки данных, которые мы использовали для извлечения функций для нашей модели.

Извлечение функций

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

Соотношение сторон глаза (EAR)

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

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

Соотношение сторон рта (MAR)

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

Круговорот зрачка (PUC)

PUC - это мера, дополняющая EAR, но при этом больше внимания уделяется зрачку, а не всему глазу.

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

Соотношение сторон рта выше соотношения сторон глаз (MOE)

Наконец, мы решили добавить MOE в качестве еще одной функции. MOE - это просто отношение MAR к EAR.

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

Хотя все эти функции имели интуитивный смысл, при тестировании с нашими моделями классификации они дали плохие результаты в диапазоне точности от 55% до 60%, что является лишь незначительным улучшением по сравнению с базовой точностью 50% для задачи двоичной сбалансированной классификации. Тем не менее, это разочарование привело нас к нашему самому важному открытию: функции не были неправильными, просто мы неправильно их рассматривали.

Нормализация функций

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

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

Чтобы нормализовать особенности каждого человека, мы взяли первые три кадра для каждого видео с предупреждением и использовали их в качестве основы для нормализации. Среднее значение и стандартное отклонение каждого признака для этих трех кадров были рассчитаны и использованы для нормализации каждого признака индивидуально для каждого участника. Математически уравнение нормализации выглядело так:

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

Основные методы и результаты классификации

После того, как мы извлекли и нормализовали наши функции, мы хотели попробовать ряд методов моделирования, начиная с самых базовых моделей классификации, таких как логистическая регрессия и наивный байесовский метод, и переходя к более сложным моделям, содержащим нейронные сети и другие подходы к глубокому обучению. Здесь важно отметить компромисс между производительностью и интерпретируемостью. Хотя мы отдаем приоритет наиболее эффективным моделям, интерпретируемость также важна для нас, если мы хотим коммерциализировать это решение и представить его последствия для бизнеса заинтересованным сторонам, которые не знакомы с жаргоном машинного обучения. Чтобы обучить и протестировать наши модели, мы разделили наш набор данных на данные из 17 видео и данные из 5 видео соответственно. В результате наш обучающий набор данных содержит 8160 строк, а наш тестовый набор данных содержит 2400 строк.

Как мы вводим последовательность в основные методы классификации?

Одна из проблем, с которыми мы столкнулись во время этого проекта, заключалась в том, что мы пытались предсказать метку для каждого кадра в последовательности. В то время как сложные модели, такие как LSTM и RNN, могут учитывать последовательные данные, базовые модели классификации не могут.

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

Из различных методов классификации, которые мы опробовали, метод K-ближайшего соседа (kNN, k = 25) имел самую высокую точность вне выборки - 77,21%. Наивный Байес показал худшие результаты - 57,75%, и мы пришли к выводу, что это произошло потому, что модели сложнее работать с числовыми данными. Хотя kNN давал самую высокую точность, частота ложноотрицательных результатов была довольно высокой и составляла 0,42, что означает, что существует 42% вероятность того, что кто-то действительно сонный будет обнаружен нашей системой как бдительный. Чтобы уменьшить количество ложноотрицательных результатов, мы снизили порог с 0,5 до 0,4, что позволило нашей модели предсказывать больше случаев сонливости, чем тревоги. Хотя точность для некоторых других моделей увеличилась, kNN по-прежнему сообщает о самой высокой точности - 76,63% (k = 18), несмотря на снижение собственной точности.

Важность функции

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

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

Сверточная нейронная сеть (CNN)

Сверточные нейронные сети (CNN) обычно используются для анализа данных изображения и сопоставления изображений с выходными переменными. Однако мы решили построить одномерную CNN и отправить числовые характеристики в качестве последовательных входных данных, чтобы попытаться понять пространственные отношения между каждой функцией для двух состояний. Наша модель CNN имеет 5 слоев, включая 1 сверточный слой, 1 сглаживание позже, 2 полностью связанных плотных слоя и 1 выпадающий слой перед выходным слоем. Сглаженный слой сглаживает вывод сверточного слоя и делает его линейным перед передачей в первый плотный слой. Слой выпадения случайным образом отбрасывает 20% выходных узлов из второго плотного слоя, чтобы наша модель не соответствовала обучающим данным. Последний плотный слой имеет единственный выходной узел, который выводит 0 для предупреждения и 1 для сонливости.

Сети с долговременной краткосрочной памятью (LSTM)

Другой метод работы с последовательными данными - использование модели LSTM. Сети LSTM - это особый вид рекуррентных нейронных сетей (RNN), способный изучать долгосрочные зависимости в данных. Рекуррентные нейронные сети - это нейронные сети с обратной связью, которые имеют внутреннюю память, которая позволяет информации сохраняться.

Как RNN могут иметь пространство внутренней памяти при обработке новых данных?

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

Мы решили использовать сеть LSTM, потому что она позволяет нам изучать длинные последовательности, не беспокоясь о проблемах исчезновения градиента, с которыми сталкиваются традиционные RNN. В сети LSTM есть три шлюза для каждого временного шага: Забыть шлюз, Входной шлюз и Выходной шлюз.

Забыть ворота: как следует из названия, ворота пытаются «забыть» часть памяти из предыдущего вывода.

Входной шлюз: элемент решает, что следует сохранить на входе, чтобы изменить память.

Выходной шлюз: гейт решает, какой будет выход, комбинируя вход и память.

Сначала мы преобразовали наши видео в пакеты данных. Затем каждая партия была отправлена ​​через полностью связанный уровень с 1024 скрытыми блоками с использованием сигмоидной функции активации. Следующий слой - это наш слой LSTM с 512 скрытыми блоками, за которыми следуют еще 3 слоя FC до финального выходного слоя, как показано ниже.

После настройки гиперпараметров наша оптимизированная модель LSTM достигла общей точности 77,08% с гораздо более низким уровнем ложноотрицательных результатов 0,3 по сравнению с частотой ложноотрицательных результатов нашей модели kNN (0,42).

Трансферное обучение

Трансферное обучение фокусируется на использовании знаний, полученных при решении одной проблемы, и их применении для решения другой, но связанной проблемы. Это полезный набор методов, особенно в тех случаях, когда у нас ограниченное время для обучения модели или ограниченные данные для полного обучения нейронной сети. Поскольку данные, с которыми мы работали, имели очень мало уникальных выборок, мы полагали, что эта проблема будет хорошим кандидатом для использования трансферного обучения. Мы решили использовать модель VGG16 с набором данных Imagenet.

VGG16 - это модель сверточной нейронной сети, предложенная К. Симоняном и А. Зиссерманом из Оксфордского университета в их статье «Очень глубокие сверточные сети для распознавания крупномасштабных изображений». Модель смогла достичь 92,7% точности тестов в топ-5 в ImageNet, который представляет собой набор данных из более чем 14 миллионов изображений, принадлежащих к 1000 классам.

ImageNet - это набор данных с более чем 15 миллионами помеченных изображений с высоким разрешением, принадлежащих примерно к 22 000 различным категориям. Изображения были собраны из Интернета и промаркированы людьми, использующими краудсорсинговый инструмент Amazon Mechanical Turk. С 2010 года в рамках Pascal Visual Object Challenge ежегодно проводится конкурс ImageNet Large-Scale Visual Recognition Challenge (ILSVRC). ILSVRC использует меньший набор ImageNet с примерно 1000 изображений в каждой из 1000 категорий. Существует приблизительно 1,2 миллиона обучающих изображений, 50 000 изображений для проверки и 150 000 изображений для тестирования. ImageNet состоит из изображений с разным разрешением. Поэтому разрешение изображений нужно изменить на фиксированное значение 256 × 256. Изображение масштабируется и обрезается, а центральный патч 256 × 256 формирует результирующее изображение.

Входными данными для слоя cov1 является изображение RGB 224 x 224. Изображение проходит через стопку сверточных слоев, где используются фильтры с очень маленьким воспринимающим полем: 3 × 3. В одной из конфигураций модель также использует фильтры свертки 1 × 1, которые можно рассматривать как линейное преобразование входных каналов с последующими нелинейными преобразованиями. Шаг свертки установлен на 1 пиксель; пространственное заполнение входных данных сверточного слоя таково, что пространственное разрешение сохраняется после свертки, то есть заполнение составляет 1 пиксель для сверточных слоев 3 × 3. Пространственное объединение выполняется пятью слоями максимального объединения, которые следуют за некоторыми сверточными слоями. Не все усл. за слоями следует max-pooling. Максимальное объединение выполняется в окне размером 2 × 2 пикселя с шагом 2.

Три уровня с полным соединением (FC) следуют за стеком сверточных слоев: первые два имеют по 4096 каналов каждый, третий выполняет 1000-позиционную классификацию ILSVRC и, следовательно, содержит 1000 каналов. Последний слой - это слой soft-max. Конфигурация полносвязных слоев одинакова во всех сетях.

Все скрытые слои имеют нелинейность выпрямления (ReLU). Также следует отметить, что при запрете одной сети ни одна из сетей не содержит нормализации локального отклика (LRN), поскольку такая нормализация не улучшает производительность модели, но приводит к увеличению времени вычислений.

Мы разделили обучающие видео на 34 000 изображений, которые были скриншоты каждые 10 кадров. Мы скармливали эти изображения модели VGG16. Мы считали, что количества изображений было достаточно для обучения предварительно обученной модели. После обучения модели для 50 эпох мы получили следующие оценки точности. Наши результаты показаны ниже.

Было ясно, что модель переоснащена. Возможное объяснение этого заключается в том, что изображения, которые мы пропустили через модель, были 22 респондентами, которые практически неподвижно сидели перед камерой с ненарушенным фоном. Таким образом, несмотря на использование большого количества кадров (34 000) в нашей модели, модель, по сути, пыталась учиться на 22 наборах практически идентичных изображений. Следовательно, в истинном смысле модели не было достаточно обучающих данных.

Заключение

В ходе этого проекта мы узнали довольно много вещей. Во-первых, более простые модели могут быть столь же эффективны при выполнении задач, как и более сложные модели. В нашем случае модель K-Nearest Neighbor дала точность, аналогичную модели LSTM. Однако, поскольку мы не хотим ошибочно классифицировать сонливых людей как бдительных, в конечном итоге лучше использовать более сложную модель с более низким уровнем ложноотрицательных результатов, чем более простую модель, которая может быть дешевле в развертывании. Во-вторых, нормализация имела решающее значение для нашей работы. Мы осознали, что у всех разные исходные параметры соотношения сторон глаз и рта, и была необходима нормализация для каждого участника. Вне времени выполнения наших моделей предварительная обработка данных и извлечение / нормализация функций занимали большую часть нашего времени. Будет интересно обновить наш проект и посмотреть, как мы можем уменьшить количество ложноотрицательных результатов для kNN и других более простых моделей.

Будущее

Двигаясь вперед, мы можем сделать несколько вещей, чтобы улучшить наши результаты и настроить модели. Во-первых, нам нужно учесть расстояние между лицевыми ориентирами, чтобы учесть любое движение объекта на видео. На самом деле участники не будут статичными на экране, и мы полагаем, что резкие движения участника могут сигнализировать о сонливости или пробуждении от микросна. Во-вторых, мы хотим обновить параметры с помощью наших более сложных моделей (NN, ансамбли и т. Д.), Чтобы добиться лучших результатов. И, наконец, в-третьих, мы хотели бы собрать наши собственные тренировочные данные от более широкой выборки участников (больше данных !!!), включая новые отчетливые сигналы сонливости, такие как внезапное движение головы, движение рук или даже отслеживание движений глаз.

Предварительный просмотр продукта

Мы хотели показать несколько скриншотов нашей системы в действии!

Во-первых, нам нужно откалибровать систему для участника, как показано ниже.

Теперь система должна автоматически определять, находится ли участник в состоянии сонливости или насторожен. Примеры приведены ниже.

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

Полный проект и код можно посмотреть на GitHub!

Подтверждение

Мы хотели бы выразить особую благодарность доктору Джойдипу Гошу, который смог предоставить невероятно ценные советы на протяжении всего этого проекта.

использованная литература



Https://arxiv.org/abs/1904.07312

Https://pypi.org/project/opencv-python/

Https://towardsdatascience.com/understanding-rnn-and-lstm-f7cdf6dfc14e

Https://neurohive.io/en/popular-networks/vgg16/