Skip to main content

Машинное обучение: анализ временных рядов Azure Machine Learning для поиска аномалий

Дата публикации: 13.12.2017

Обнаружение аномалий — одна из важнейших функций для решений в области «интернета вещей» (IoT), которые собирают и анализируют временные изменения в потоке данных от различных датчиков. Во многих случаях поток данных со временем не претерпевает значительных изменений. Однако если они появляются, это чаще всего означает, что в системе возникла аномалия, способная нарушить её работу. В этой статье я расскажу, как использовать модуль Time Series Anomaly Detection сервиса машинного обучения Azure Machine Learning для определения аномальных показателей датчиков.


Для раскрытия темы я расширю функционал приложения RemoteCamera Universal Windows Platform (UWP), разработанного мною к предыдущей статье, и добавлю список, в котором будут отображаться аномальные значения. Приложение RemoteCamera получает изображение с веб-камеры и вычисляет его яркость, которая при условии неизменности сцены в кадре колеблется вокруг определённых значений. Яркость легко изменить, например, прикрыв камеру рукой, что приведёт к заметному отклонению в потоке данных. Это помогает получить хорошую выборку для обнаружения аномалий во временном ряду.



Поиск аномалий

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

Сначала я покажу, как находить такие отклонения, анализируя z-оценки. Чем эта оценка больше, тем выше вероятность того, что в потоке значений есть отклонение. Чтобы найти аномалии, нужно определить границы z-оценок, принимаемых за нормальные. Все z-оценки, выходящие за заданные пределы, будут считаться аномальными. Следует принимать во внимание, что из-за фиксированного порога, задаваемого в этом сценарии, возможны многочисленные ложные срабатывания. Чтобы уменьшить их число, применяют более сложные алгоритмы. В нашем случае, модуль Azure Time Series Anomaly Detection основан на перестановочных мартингалах, анализирующих, может ли ряд данных быть произвольно реорганизован без потери вероятности обнаружения определённого значения. Проще говоря, может ли каждое значение быть обнаружено в наборе данных с равной вероятностью. Коммутативный набор данных отличается низким коэффициентом аномалий. Если коммутативность нарушена, коэффициент аномалий растёт, указывая на нестандартные значения.

В этой статье я расскажу, как создавать такие алгоритмы машинного обучения. Я буду использовать решение Microsoft Azure Machine Learning Studio. Об этом продукте также рассказывал Джеймс Маккефри в сентябре 2014 года. Я расширю тему этой статьи и продемонстрирую эксперименты с машинным обучением. Кроме того, я покажу, как развернуть полученное решение в виде веб-службы, а затем — как использовать эту службу в приложении RemoteCamera.

Обучение с использованием набора данных

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



Кнопка Acquire training dataset становится активной, если запустить предпросмотр изображения с камеры (при помощи кнопок управления на главной вкладке). При нажатии этой кнопки приложение начинает сбор данных для обучения. Этот процесс проходит в фоновом режиме, его ход сопровождается круговой анимацией. В итоге будет создан набор данных для обучения, состоящий из 100 точек данных. Каждая из них будет представлена экземпляром структуры BrightnessDataPoint:

public struct BrightnessDataPoint
{
  public DateTime Time { get; private set; }
  public byte Brightness { get; private set; }

  public BrightnessDataPoint(byte brightness)
  {
    Time = DateTime.Now;
    Brightness = brightness;
  }
}

 

Структура BrightnessDataPoint сохраняет значение яркости, а также время, в которое оно было зафиксировано. Затем набор таких значений экспортируется в файл BrightnessData.csv, который выглядит следующим образом:

Time,Brightness
9/8/2017 11:30:00,103
9/8/2017 11:30:01,103
9/8/2017 11:30:02,102
9/8/2017 11:30:03,42
9/8/2017 11:30:04,46
9/8/2017 11:30:05,149
9/8/2017 11:30:06,99
9/8/2017 11:30:07,101
9/8/2017 11:30:08,104

 

Затем в текстовом поле отобразится точное расположение набора данных для обучения. Я использую значения, разделённые запятыми (файл CSV). Их легко загрузить в Machine Learning Studio.

Чтобы реализовать этот функционал, я написал два класса: BrightnessFileStorage и AnomalyDetector. Первый класс BrightnessFileStorage определяется файлом BrightnessFileStorage.cs во вложенной папке AnomalyDetection сопроводительного кода. Класс BrightnessFileStorage сохраняет набор объектов BrightnessDataPoint в файл CSV с использованием класса DataWriter.

Второй класс AnomalyDetector обрабатывает логику, относящуюся к обнаружению аномалий. В частности, он включает публичный метод Add-TrainingValue, который вызывается сразу после вычисления яркости изображения (см. обработчик событий ImageProcessor_ProcessingDone в файле MainPage.xaml.cs в сопроводительном коде). AddTrainingValue работает следующим образом. Сначала я создаю экземпляр BrightnessDataPoint, который затем добавляется в набор. Когда набор насчитывает 100 элементов, я сохраняю его в файл CSV. Затем я запускаю событие TrainingDataReady, которое обрабатывается в MainPage. Цель — прервать сбор данных для обучения и отобразить в интерфейсе пользователя местонахождение файла:

private async void AnomalyDetector_TrainingDataReady(
  object sender, TrainingDataReadyEventArgs e)
{
  await ThreadHelper.InvokeOnMainThread(() =>
  {
    remoteCameraViewModel.IsTrainingActive = false;
    remoteCameraViewModel.TrainingDataSetFilePath = e.FilePath;
  });
}

 

 

 

private const int trainingDataSetLength = 100;
private List<BrightnessDataPoint> trainingDataSet = 
  new List<BrightnessDataPoint>();

public event EventHandler<TrainingDataReadyEventArgs> TrainingDataReady;

public async Task AddTrainingValue(byte brightness)
{
  trainingDataSet.Add(new BrightnessDataPoint(brightness));

  // Check if all data points were acquired
  if (trainingDataSet.Count == trainingDataSetLength)
  {
    // If so, save them to csv file
    var brightnessFileStorage = 
      await BrightnessFileStorage.CreateAsync();
    await brightnessFileStorage.WriteData(trainingDataSet);

    // ... and inform listeners that the training data set is ready
    TrainingDataReady?.Invoke(this,
      new TrainingDataReadyEventArgs(
      brightnessFileStorage.FilePath));
  }
}

 

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

Анализ z-оценок


После получения набора данных для обучения я подготовлю первый эксперимент в Machine Learning Studio согласно инструкциям, описанным в статье Джеймса Маккефри в 2014 году. Для начала я загружаю файл BrightnessData.csv, затем планирую эксперимент с использованием визуального конструктора. Короче говоря, все компоненты находятся в меню в левой части окна Machine Learning Studio. Чтобы разместить элемент на плане вашего эксперимента, просто перетащите его в область эксперимента (это центральная часть окна Machine Learning Studio). У каждого компонента свои входные и выходные данные. Вам нужно соединить совместимые узлы, чтобы контролировать потоки данных между модулями. У компонентов могут быть дополнительные настройки, которые можно задать в окне свойств (в правой части окна Machine Learning Studio).



Алгоритм машинного обучения, изображённый выше, может работать в двух режимах: эксперимент и веб-служба. Различие лишь во входных данных. В режиме эксперимента в их роли выступает загруженный набор данных для обучения (BrightnessData), а в режиме веб-службы — её собственные входные данные. Вне зависимости от режима, входные данные преобразовываются в набор данных, после чего значения столбца яркости нормализуются с помощью преобразования в z-оценки. В ходе этого преобразования значения яркости пересчитываются в z-оценки, которые показывают их разброс относительно среднего значения. Разброс измеряется в среднеквадратичных отклонениях. Чем значительнее этот разброс, тем выше вероятность того, что текущее значение является аномальным. Я применяю нормализацию z-оценок, поскольку зачастую базовый или нормальный уровень яркости зависит от того, что фиксирует камера. Таким образом, преобразование в z-оценку обеспечивает корректный уровень яркости, когда нормализация близка к 0. Необработанные значения яркости различаются в примерном диапазоне от 40 до 150. После нормализации все значения яркости укладываются в пределы примерно от –4.0 до +4.0. Следовательно, чтобы найти аномальные значения, мне нужно лишь применить пороговый фильтр. Я применяю пороговый фильтр OutOfRange в Azure Machine Learning с нижним порогом –2 и верхним 1.5. Я выбрал эти значения на основе графика z-оценок и задал их в панели свойств порогового фильтра в Machine Learning Studio.



После указания порога набор данных представляет собой столбец данных логического типа, где указывается, находится ли в конкретный момент точка вне заданного диапазона. Чтобы дополнить эту информацию фактическими значениями яркости, которые были определены как аномальные, я совмещаю этот столбец с первоначальным набором данных, а затем разбиваю полученный набор на два подмножества. Одно содержит только аномальные значения, второе — стандартные. Перед разбивкой я меняю тип данных в столбце, поскольку модуль Split Data не поддерживает логические значения. После этого в результате эксперимента выдается первое подмножество. В случае с веб-службой, этот результат передаётся клиенту. Чтобы просмотреть значения какого-либо набора данных, нужно использовать опцию Results dataset | Visualize из контекстного меню набора данных в Machine Learning Studio. Эта опция будет доступна, если вы уже запускали данный эксперимент.



Анализ временных рядов в машинном обучении

А теперь научимся применять модуль Azure Time Series Anomaly Detection (ATSAD) для определения аномалий. Как показано ниже, процесс этого эксперимента напоминает предыдущий. Первоначальный набор данных нормализуется преобразованием в z-оценки и передаётся в модуль ATSAD (он находится в узле Time Series в Machine Learning Studio). Для этого необходимо настроить несколько входных параметров в окне свойств (bit.ly/2xUGTg2). Сначала нужно указать столбцы данных и времени, затем настроить тип мартингала. В нашем случае я буду использовать мартингал Power. Станет доступным ещё одно текстовое поле — Epsilon, где можно ввести любое значение чувствительности детектора в диапазоне от 0 до 1. Затем нужно настроить три параметра функции определения странности значений:

  • RangePercentile: этот параметр следует использовать для обнаружения значений, очевидно находящихся вне диапазона, таких как всплески или провалы. В этом эксперименте данный параметр будет работать по аналогии с предыдущим экспериментом, но анализ будет более полным.
  • SlowPos- и SlowNegTrend: используйте этот параметр для выявления изменений тенденций в вашем наборе данных в сторону положительных или отрицательных значений. Это полезно, когда ваше решение отслеживает увеличение или уменьшение наблюдаемых значений.





Далее нужно задать максимальное количество значений мартингала и странности в журнале. Можно ввести любое целое число от 10 до 1000. Методом проб и ошибок я остановился на следующих настройках детектора:

  • Epsilon = 0.4
  • Длина журнала значений мартингала и странности = 50

Последний параметр детектора — это порог предупреждения. Он задаёт минимальный коэффициент аномальности значений. По умолчанию задан порог предупреждения 3.5. Для своего эксперимента я поменял это значение на 2.

Запросив визуализацию выходных данных модуля ATSAD, можно увидеть, что к набору входных данных добавляется два столбца: коэффициент аномальности, измеряющий отклонения, и индикатор предупреждения с двоичным значением (0 или 1), указывающим на аномальность значения. На основании показаний второго индикатора я разбиваю набор данных на два подмножества: стандартные и аномальные значения. В результате эксперимента выдаётся только подмножество аномальных значений. В остальных деталях эксперимент идентичен предыдущему, и я не буду описывать их заново. Замечу только, что самый важный аспект эксперимента для веб-службы — это описание входных и выходных данных. Назовем эти данные следующим образом: Data (входные данные веб-службы) и AnomalyDetectionResult (выходные данные веб-службы).

Клиент веб-службы

После настройки экспериментов я могу развернуть их в виде веб-служб, получить к ним доступ через приложение RemoteCamera и выявлять аномальные показатели яркости изображения. Чтобы создать веб-службу, нужно запустить эксперимент, а затем нажать значок Deploy Web Service в нижней области окна Machine Learning Studio. Если вы не добавили в эксперимент модули ввода и вывода веб-службы, в этой области отобразится кнопка Set Up Web Service. После ее нажатия в эксперимент будут добавлены модули ввода и вывода веб-службы, а название кнопки изменится на Deploy Web Service.



Когда процесс развёртывания веб-службы завершится, откроется панель управления веб-службой. На этой панели отображается сводная информация о развёрнутой веб-службе, ключ API, а также инструкции по отправке запросов и обработке ответов (API Help Page). В частности, при нажатии гиперссылки request/response отображаются URL веб-службы и детальная структура запросов и ответов в формате JSON.



Далее я сохраняю ключ API и создаю маппинги из JSON в C# с помощью службы JSONUtils (jsonutils.com). Затем я сохраняю полученные классы в соответствующие файлы — AnomalyDetectionRequest.cs и AnomalyDetectionResponse.cs во вложенной папке AnomalyDetection. Их структуры схожи — оба файла обычно содержат классы со свойствами, которые по большей части реализуются автоматически. AnomalyDetectionRequest и AnomalyDetectionResponse представляют собой передачу соответствующих объектов JSON между клиентом и веб-службой. К примеру, определение класса AnomalyDetectionRequest и зависимых объектов показано ниже. Обратите внимание, что для преобразования набора точек данных яркости в формат входных данных для веб-службы Machine Learning Studio (двумерные массивы строк) я использую вспомогательный класс ConversionHelper. Полное определение этого вспомогательного класса содержится в сопроводительном коде. Этот класс имеет два публичных метода. С их помощью набор точек данных яркости преобразуются в тип string[,] (BrightnessDataToStringTable) и обратно (AnomalyDetectionResponseToBrightnessData).

public class AnomalyDetectionRequest
{
  public Inputs Inputs { get; set; }
  public GlobalParameters GlobalParameters { get; set; }

  public AnomalyDetectionRequest(
    IList<BrightnessDataPoint> brightnessData)
  {
    Inputs = new Inputs()
    {
      Data = new Data()
      {
        ColumnNames = new string[]
        {
          "Time",
          "Brightness"
        },

          Values = ConversionHelper.
            BrightnessDataToStringTable(brightnessData)
      }
    };
  }
}

public class Inputs
{ 
  public Data Data { get; set; }
}

public class Data
{
  public string[] ColumnNames { get; set; }
  public string[,] Values { get; set; }
}

public class GlobalParameters { }

 

 

После создания маппинга объектов из JSON в C# можно приступить к написанию клиента веб-службы. Для этого я сначала установлю пакет Microsoft.AspNet.WebApi.Client NuGet, а затем использую его для определения класса AnomalyDetectionClient (см. соответствующий файл в сопроводительном коде). В этом классе есть три закрытых поля: baseAddress, apiKey and httpClient. В первом поле содержится URL веб-службы Machine Learning Studio, во втором — ключ API. Оба этих значения используются для создания экземпляра класса HttpClient (из установленного ранее пакета NuGet):

public AnomalyDetectionClient()
{
  httpClient = new HttpClient()
  {
    BaseAddress = new Uri(baseAddress),
  };

  httpClient.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Bearer", apiKey);
}c class GlobalParameters { }

 

 

После создания клиента я могу начать отправку запросов в веб-службу Machine Learning Studio при помощи метода AnomalyDetectionClient.DetectAnomalyAsync. Этот метод обеспечивает получение набора точек данных яркости в качестве тестовых данных. Эти тестовые данные используются вместо файла CSV, который я использовал для экспериментов. С их помощью создается экземпляр запроса AnomalyDetection. Экземпляр этого класса затем отправляется в веб-службу для анализа при помощи метода расширения PostAsJsonAsync. Полученный ответ JSON преобразуется в экземпляр класса AnomalyDetectionResponse, который в итоге выдаётся функцией DetectAnomalyAsync. Смотрим, нет ли ошибок. Если необходимо, «выбрасываем» исключения.

public async Task<IList<BrightnessDataPoint>> 
  DetectAnomalyAsync(IList<BrightnessDataPoint> brightnessData)
{
  var request = new AnomalyDetectionRequest(brightnessData);

  var response = await httpClient.PostAsJsonAsync(string.Empty, request);

  IList<BrightnessDataPoint> result; 

  if (response.IsSuccessStatusCode)
  {
    var anomalyDetectionResponse = await 
      response.Content.ReadAsAsync<AnomalyDetectionResponse>();

    result = ConversionHelper.
      AnomalyDetectionResponseToBrightnessData(anomalyDetectionResponse);
  }
  else
  {
    throw new Exception(response.ReasonPhrase);
  }

  return result;
}

 

 

AnomalyDetectionClient используется в методе AddTestValue класса AnomalyDetector. Как и AddTrainingValue, AddTestValue также вызывается обработчиком событий ImageProcessor_ProcessingDone (см. файл MainPage.xaml.cs в сопроводительном коде). Однако AddTestValue работает немного иначе, чем метод AddTrainingValue. В AddTrainingValue я добавляю точки данных яркости в экземпляр класса BrightnessDataset, который на внутреннем уровне использует универсальный класс List для введения скользящего интервала. В этом интервале хранятся тестовые значения (см. октябрьскую статью Джеймса Маккефри). По умолчанию скользящий интервал насчитывает 30 элементов, но это значение можно менять при помощи конструктора BrightnessDataset. Как показано на ниже, я отправляю данные для анализа после заполнения интервала. Затем проверяю наличие элементов в наборе аномальных значений, выданном веб-службой. Если элементы присутствуют, я запускаю событие AnomalyDetected, которое также используется для передачи аномалий в прослушиватели.

public event EventHandler<AnomalyDetectedEventArgs> AnomalyDetected;
private BrightnessDataset dataSet = new BrightnessDataset();

public async Task AddTestValue(byte brightness)
{
  dataSet.Add(new BrightnessDataPoint(brightness));

  if (dataSet.IsFull)
  {
    try
    {
      var anomalousValues = await anomalyDetectionClient.
        DetectAnomalyAsync(dataSet.Data);

      if (anomalousValues.Count > 0)
      {
        AnomalyDetected?.Invoke(this,
          new AnomalyDetectedEventArgs(anomalousValues));
      }
    }
    catch (Exception ex)
    {
      Debug.WriteLine(ex);
    }
  }
}

 

Чтобы отобразить аномальные значения в интерфейсе, я обрабатываю событие AnomalyDetected в классе MainPage следующим образом.

private async void AnomalyDetector_AnomalyDetected(
  object sender, AnomalyDetectedEventArgs e)
{
  await ThreadHelper.InvokeOnMainThread(() =>
  {
    foreach (var anomalousValue in e.AnomalousValues)
    {
      if (!remoteCameraViewModel.AnomalousValues.Contains(anomalousValue))
      {
        remoteCameraViewModel.AnomalousValues.Add(anomalousValue);
      }
    }
  });
}

 

Я выполняю итерацию набора полученных значений, проверяя, не были ли они уже добавлены в локальное хранилище данных (свойство AnomalousValues модели просмотра). Если нет, то я добавляю их в набор наблюдаемых значений. В результате этого в списке, показанном на первой картинке, появятся только новые аномальные значения. Эта дополнительная проверка нужна, поскольку за время между двумя последовательными запросами в веб-службу в скользящем интервале изменился только один элемент.

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

Заключение

Я показал процедуру создания двух разных эксперимента по обнаружению аномалий в Azure Machine Learning Studio. Оба эксперимента были развёрнуты также в виде веб-служб и совмещены с клиентским приложением RemoteCamera, которое отправляет локально полученные данные временных рядов для машинного анализа с целью обнаружения аномалий. В данном случае я использовал веб-службу приложения Universal Windows Platform (UWP). Этот же код можно использовать для доступа к веб-службе через веб-приложение ASP.NET, в котором логика машинного обучения обрабатывается серверной частью, а не в конечной точке. В контексте IoT такой точкой может быть простой датчик.

Автор статьи: Александр Гуреев

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