На прошлой неделе я потратил некоторое время на участие в конкурсе машинного обучения Numerai. Ниже приведены мои заметки о конкурсе: что я пробовал, что сработало, а что нет. Сначала знакомство с Numerai и соревнованиями…

Numerai - это хедж-фонд, который использует конкуренцию для получения прогнозов для большого ансамбля, который они используют внутри компании для совершения сделок. Еще одна деталь, которая делает соревнование уникальным, заключается в том, что предоставленные данные были зашифрованы таким образом, что их можно использовать для прогнозов. Каждую неделю Numerai выпускает новый набор данных, и соревнования сбрасываются. После непродолжительного контроля 1–2 места как по очкам, так и по оригинальности, к концу недели я все еще контролировал капитал с потерями 0,68714. В целом это заработало биткойнов на сумму около 8,17 долларов США.

Вот образец данных обучения:

Проверка

Моим первым шагом в конкурсе было создание набора для проверки, чтобы я мог запускать модели локально и получить представление о том, как модели будут вести себя в таблице лидеров. Использование простого стратифицированного разделения, поддерживающего целевое распределение, оказалось не репрезентативным для таблицы лидеров, поэтому я обратился к состязательной проверке. Эта умная идея была представлена ​​@fastml в блоге здесь. По сути:

  1. Обучите классификатор определять, поступают ли данные из поезда или из набора тестов.
  2. Отсортируйте данные обучения по вероятности попадания в тестовый набор.
  3. Выберите данные обучения, наиболее похожие на данные теста, в качестве набора для проверки.

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

Базовая модель

Теперь, когда у меня был хороший набор для проверки, я хотел обучить, проверить и загрузить базовую модель. В качестве отправной точки я использовал логистическую регрессию с настройками по умолчанию и без разработки функций. Это дает около 0,69290 потерь при проверке и 0,69162 в общедоступной таблице лидеров. Это не очень хорошо, но теперь я знаю, на что способна простая модель. Для сравнения, первое место в настоящее время составляет 0,64669, то есть базовый показатель ниже лишь примерно на 6,5%. Это означает, что любые улучшения будут очень небольшими. Мы можем продвинуть это немного дальше с помощью регуляризации L2 на 1e-2, которая достигает 0,69286 (-0,006% от базового уровня).

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

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

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

Анализ данных и разработка функций

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

Распределения очень похожи для каждой функции и цели. Как насчет корреляции между функциями:

Хорошо, многие функции сильно коррелированы. Мы можем использовать это в нашей модели, включив полиномиальные функции (например, PolynomialFeatures (степень = 2) из scikit-learn). Их добавление снижает наши потери при проверке до 0,69256 (-0,05% от базового уровня).

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

Здесь не так много полезной информации. Как насчет полиномиальных функций:

Полиномиальный PCA дает немного лучший результат за счет смещения многих целевых значений «1» к краям и многих целевых значений «0» к центру. Все еще не очень хорошо, поэтому я решил пока опустить PCA.

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

Здесь t-SNE захватил действительно хорошие функции для визуализации (например, локальные кластеры), а также, кстати, для классификации! Я добавляю в модель эти 2D-функции, чтобы получить максимальную потерю при проверке: 0,68947 (-0,5% от базовой линии). Я подозреваю, что это помогает потому, что на самом деле существует множество локальных функций, которые логистическая регрессия не может извлечь, но которые полезны при классификации для цели. Запуская неконтролируемый метод, специально разработанный для выравнивания данных по попарному сходству, модель может использовать эту информацию.

Поскольку t-SNE является стохастическим, несколько запусков приведут к различным вложениям. Чтобы воспользоваться этим, я запустил t-SNE 5 или 6 раз с разными сложностями и размерами (2D и 3D), а затем добавлю эти дополнительные функции. Теперь потеря проверки составляет 0,68839 (-0,65% от базового уровня).

Обратите внимание, что некоторые реализации t-SNE некорректно работают в 3D. Нанесите их на график, чтобы убедиться, что вы видите каплю, а не форму пирамиды.

Дополнительные вложения

Поскольку t-SNE работал так хорошо, я реализовал несколько других методов внедрения, включая автокодеры, шумоподавляющие автокодеры и генеративные состязательные сети. Автоэнкодеры выучили отличные реконструкции с точностью ›95%, даже с шумом, но их изученные вложения не улучшили модель. GAN, включая вариант с полууправлением, не превзошел логистическую регрессию. Я также вкратце поэкспериментировал с ядерным PCA и isomaps (также методами нелинейного уменьшения размерности). В обоих случаях потери при проверке немного улучшились, но для их выполнения потребовалось значительно больше времени, что уменьшило мою способность к быстрой итерации, поэтому в конечном итоге они были отброшены. Я никогда не пробовал LargeVis или параметрический t-SNE, но, возможно, их стоит изучить. Параметрический t-SNE был бы особенно интересен, так как он позволяет подгонять тестовую задержку, а не обучать встраиванию всех выборок сразу.

Парные взаимодействия

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

Поиск гиперпараметров

Теперь, когда у нас есть полезные функции и несколько моделей, которые хорошо работают, я хотел запустить поиск по гиперпараметрам и посмотреть, сможет ли он превзойти существующие модели. Поскольку GridSearchCV и RandomSearchCV из scikit-learn исследуют только гиперпараметры, а не целые архитектуры, я решил использовать tpot, который выполняет поиск по обоим. Было обнаружено, что использование рандомизированного PCA превосходит PCA и что регуляризация L1 (разреженность) немного превосходит регуляризацию L2 (сглаживание), особенно в сочетании со случайным PCA. К сожалению, ни одно из обнаруженных взаимодействий не вошло в окончательный ансамбль: победила ручная инженерия.

Ансамбль

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

Окончательный ансамбль состоял из 4 моделей: логистическая регрессия, деревья с градиентным бустом, машины факторизации и парная модель, описанная выше. Я использовал одни и те же функции для каждой модели, состоящей из 21 исходной функции и пяти прогонов T-SNE в 2D с затруднениями 5,0, 10,0, 15,0, 30,0 и 50,0 и одного прогона T-SNE в 3D с трудностями 30 (я включил только один прогон, потому что он занимает значительно больше времени в 3D). Эти функции были объединены с полиномиальными взаимодействиями и прошли через модели, чтобы получить окончательную потерю журнала в 0,68714 в таблице лидеров.

Заключение

В целом это было интересное соревнование - сильно отличавшееся от чего-то вроде Kaggle. Мне особенно понравилось экспериментировать с зашифрованными данными, что было для меня впервые. Хотя выплаты и бонусы за «оригинальность» - интересная механика, часто лучше рассматривать награды как баллы, а не как валюту, поскольку это сделало соревнование в целом более увлекательным. С другой стороны, теперь у меня есть свой первый биткойн… :)

Код: https://github.com/jimfleming/numerai

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