www.machinelearningmastery.ru

Машинное обучение, нейронные сети, искусственный интеллект
Header decor

Home

Тестирование конвейеров машинного обучения (ML)

Дата публикации Jul 18, 2019

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

Давайте посмотрим на традиционные методологии тестирования и как мы можем применить их к нашим конвейерам данных / ML.

Испытательная пирамида

Ваша стандартная упрощенная пирамида тестирования выглядит так:

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

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

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

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

Модульные тесты

«Это система для проверки ваших мыслей на предмет вселенной и определения их соответствия» Исаак Азимов.

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

def add_difference(asimov_dataset):    
asimov_dataset['total_naughty_robots_previous_day'] =
asimov_dataset['total_naughty_robots'].shift(1)

asimov_dataset['change_in_naughty_robots'] =
abs(asimov_dataset['total_naughty_robots_previous_day'] -
asimov_dataset['total_naughty_robots']) return asimov_dataset[['total_naughty_robots',
'change_in_naughty_robots', 'robot_takeover_type']]

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

import pandas as pd 
from pandas.testing import assert_frame_equal
import numpy as np def test_change():
asimov_dataset_input = pd.DataFrame({
'total_naughty_robots': [1, 4, 5, 3],
'robot_takeover_type': ['A', 'B', np.nan, 'A']
}) expected = pd.DataFrame({
'total_naughty_robots': [1, 4, 5, 3],
'change_in_naughty_robots': [np.nan, 3, 1, 2],
'robot_takeover_type': ['A', 'B', np.nan, 'A']
}) result = add_difference(asimov_dataset_input)

assert_frame_equal(expected, result)

Для каждого элемента независимой функциональности вы должны написать модульный тест, убедившись, что каждая часть процесса преобразования данных оказывает ожидаемое влияние на данные. Для каждой части функциональности вы должны также рассмотреть различные сценарии (есть ли оператор if? Тогда все условия должны быть проверены). Затем они будут выполняться как часть конвейера непрерывной интеграции (CI) при каждом коммите.

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

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

Интеграционные тесты

Потому что «безоблачный глаз был лучше, независимо от того, что он видел». Фрэнк Герберт,

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

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

Поэтому, если мы возьмем функцию, протестированную модулем выше, и добавим следующие две функции:

def remove_nan_size(asimov_dataset): 
return asimov_dataset.dropna(subset=['robot_takeover_type']) def clean_data(asimov_dataset):
asimov_dataset_with_difference = add_difference(asimov_dataset)
asimov_dataset_without_na = remove_nan_size(
asimov_dataset_with_difference) return asimov_dataset_without_na

Тогда мы можем проверить, что объединение функций внутриclean_dataдаст ожидаемый результат с помощью следующего кода:

def test_cleanup(): 
asimov_dataset_input = pd.DataFrame({
'total_naughty_robots': [1, 4, 5, 3],
'robot_takeover_type': ['A', 'B', np.nan, 'A']
})
expected = pd.DataFrame({
'total_naughty_robots': [1, 4, 3],
'change_in_naughty_robots': [np.nan, 3, 2],
'robot_takeover_type': ['A', 'B', 'A']
}).reset_index(drop=True) result = clean_data(asimov_dataset_input).reset_index(drop=True)

assert_frame_equal(expected, result)

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

from sklearn.linear_model import LogisticRegression def get_reression_training_score(asimov_dataset, seed=9787): 
clean_set = clean_data(asimov_dataset).dropna()
input_features = clean_set[['total_naughty_robots',
'change_in_naughty_robots']]
labels = clean_set['robot_takeover_type']

model = LogisticRegression(random_state=seed).fit(
input_features, labels) return model.score(input_features, labels) * 100

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

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

Мы можем гарантировать, что результаты всегда одинаковы, предоставляя одинаковое начальное число для генератора случайных чисел. Все основные библиотеки позволяют вам устанавливать начальное число (Tensorflow немного особенный, так как требует, чтобы вы установили начальное значение через numpy, так что имейте это в виду). Тест может выглядеть следующим образом:

from numpy.testing import assert_equal def test_regression_score(): 
asimov_dataset_input = pd.DataFrame({
'total_naughty_robots': [1, 4, 5, 3, 6, 5],
'robot_takeover_type': ['A', 'B', np.nan, 'A', 'D', 'D']
})
result = get_reression_training_score(asimov_dataset_input,
seed=1234)
expected = 50.0 assert_equal(result, expected)

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

Проверка ML

Зачем? «Чтобы показать полную бесполезность знания ответа на неправильный вопрос». Урсула К. Ле Гуин.

Теперь, когда мы проверили наш код, нам нужно также проверить, что компонент ML решает проблему, которую мы пытаемся решить. Когда мы говорим о разработке продукта, необработанные результаты модели ML (хотя и точные, основанные на статистических методах) почти никогда не являются желаемыми конечными результатами. Эти результаты обычно объединяются с другими бизнес-правилами перед использованием пользователем или другим приложением. По этой причине нам необходимо проверить, что модель решает пользовательскую проблему, а не только то, что точность / f1-оценка / другая статистическая мера достаточно высока.

Как это поможет нам?

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

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

Вывод

В конце концов «Магия - это просто наука, которую мы еще не понимаем» Артур Кларк.

Компоненты ML можно тестировать различными способами, что дает нам следующие преимущества:

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

Так что не бойтесь, если у вас есть набор навыков для написания кода, у вас есть набор навыков для написания теста и получения всех вышеперечисленных преимуществ 🙂

Так долго и спасибо за все испытания!


Первоначально опубликовано наhttp://intothedepthsofdataengineering.wordpress.com18 июля 2019 г.

Оригинальная статья

Footer decor

© www.machinelearningmastery.ru | Ссылки на оригиналы и авторов сохранены. | map