Код машинного обучения модульного тестирования - PullRequest
28 голосов
/ 10 февраля 2010

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

Ясно, что правильно добавить модульные тесты, но не ясно, как это сделать. Многие компоненты моей программы дают несколько субъективный ответ, и я не могу автоматизировать проверки работоспособности.

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

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

Ответы [ 6 ]

12 голосов
/ 10 февраля 2010

"тогда я не проверяю все, что может пойти не так."

Правильно.

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

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

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

Мудро выбирайте свои тесты.

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

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

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

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

11 голосов
/ 10 февраля 2010

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

10 голосов
/ 10 февраля 2010

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

Окончательная мысль об этом - книга Майкла Фезера Эффективная работа с унаследованным кодом .Раньше было полезное резюме этого на сайте ObjectMentor, но, увы, сайт пошел по пути компании.Однако WELC оставил наследие в обзорах и других статьях. Проверьте их (или просто купите книгу) , хотя ключевые уроки - это те, которые С.Лотт и Тванфоссон освещают в своих ответах.


2019 обновление: я исправилссылка на резюме WELC с версией из веб-архива Wayback Machine (спасибо @milia).

Кроме того, несмотря на то, что мы знаем, что ответы, которые содержат в основном ссылки на другие сайты, являются ответами низкого качества :) - здесьссылка на новый (2019 новый) учебник Google по тестированию и отладке кода ML .Я надеюсь, что это будет источником света для будущих Искателей, которые наткнуться на этот ответ.

7 голосов
/ 10 февраля 2010

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

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

TEST_ALMOST_EQ(result, 4.0);

Выше TEST_ALMOST_EQ может убедиться, что result находится между 3,9 и 4,1 (например).

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

x = 0;
for (100 times) {
  x += result_probabilistic_test();
}

avg = x/100;
TEST_RANGE(avg, 10.0, 15.0);

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

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

НТН.

1 голос
/ 10 февраля 2010

Как правило, для статистических показателей вы должны добавить эпсилон для своего ответа. И.Е. Среднеквадратичная разница ваших очков будет <0,01 или около того. Другой вариант - запустить несколько раз, и если он «слишком часто» завершится неудачно, у вас возникнет проблема. </p>

0 голосов
/ 07 апреля 2013
  1. Получить соответствующий набор тестовых данных (возможно, подмножество того, что вы обычно используете)
  2. Рассчитать некоторую метрику для этого набора данных (например, точность)
  3. Запишите полученное значение (перекрестная проверка)
  4. Это должно дать представление о том, что установить порог для

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

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