Aspiring Data Science
370 subscribers
425 photos
11 videos
10 files
1.87K links
Заметки экономиста о программировании, прогнозировании и принятии решений, научном методе познания.
Контакт: @fingoldo

I call myself a data scientist because I know just enough math, economics & programming to be dangerous.
Download Telegram
#profiling #optimisation #python #speed #sklearn #bollocks

Эскалёрновские волшебники-программисты в деле. Столкнулся с неприемлемо низкой скоростью построения отчёта классификационных метрик на 8M примеров. 15 секунд, ну куда это годится? Проверил кирпичики расчётов по нисходящей. Матрица ошибок считается за полторы секунды. Это чем же надо угандошить процессор, чтобы простое деление пары чисел и упаковка в словарь выполнялись больше 10 секунд и делали расчёты в ДЕСЯТЬ раз длиннее? Такое и специально не сразу сделаешь.
😁1
#optimisation #sklearn #python #numba #codegems

Итак, то, что у кудесников машинного обучения считается 15 СЕКУНД, на самом деле должно занимать 50 МИЛЛИСЕКУНД. Но зато они сотни строк качественного кода написали, наверное, покрытого тестами, и прочим. Почему я считаю это важным? Да потому что мне предстоит обсчитывать сотни моделей, и оказалось, что качество обучения (classification report, roc auc, калибрация по всему сету + в разбивке по группам) на test set оценивается для 1 модели.. 5 минут, и основным тормозом был classification_report. Мне вовсе не улыбается платить за кластер, ожидающий сотни и тысячи раз по 5 минут. Спасибо, что у нас хотя бы есть numpy и numba. Без нумбы, кстати, этот код на языке программирования, созданном "гениальным" Ван Россумом, выполняется даже не знаю сколько, я прождал минут 5-10 и забил.

Скорее всего, напрасная трата времени, но всё же запостил issue. Как обычно, похерят, видимо.
👍1😁1
#optimisation #numba #numpy #auc #fastauc

Ещё немного про оптимизацию. В попытке найти быструю реализацию roc_auc набрёл на библу factauc, где автор не поленился и сделал numba-оптимизированную, и даже сишную реализации. В сишную он явно вложился, вон сколько кода, и не напрасно: она получилась самой быстрой, почти вдвое быстрее нумбовской (что меня уже насторожило). Проверил на своём массивчике 8M float-ов, действительно самые тормозные catboost и sklearn (больше 2 секунд), фастаук уже позволяет прыгнуть до 0.6 секунды с нумба и до 0.4 с Си++. Глянул нумбовскую реализацию, а там argsort закомпилирован. Вспомнилось, что раньше нумба замедляла эту функцию. Вынес argsort "за скобки" njit-компилятора, и вуаля, С++ реализация побита, 0.3 секунды )) Даже неловко было сообщать автору, но что поделаешь.

P.S. Всеволод сказал, что на неделе предлагаемое улучшение потестит и, если что, в fastauc замёрджит )
1🔥1
#featureselection #diogenes #optimisation #gpu #cuda #cupy

Докладываю новости о проекте Диоген. Вчера добавил бюджет времени, переписал функции покрасивее, потестировал все ветки. С указанием допустимого времени работает просто отлично.

Сегодня ещё добавил функциональность random seed. Выяснилось, что нумба не подтягивает его из нампай "обычного" режима, надо в njit-нутой функции его ещё раз выставлять.

Отпрофилировал код на глубинах 1-2 взаимодействий признаков. Оказалось, что 80% времени кушает оценка кандидатов, и 20% времени - расчёт надёжности для лучших кандидатов. Из этих 80% основные опять же ~80% тратятся в прямой оценке MI кандидата и таргета.

Дальше они распадаются так: 20% на слияние многомерного вектора, 70% на перемешивание таргета (np.random.shuffle), 10% на сам расчёт MI из совместного распределения.

Очевидно, выгоднее всего оптимизировать шаффл таргета. Решил попробовать cupy как замену numpy: просто перенести таргет в память gpu и шаффлить прямо там. Улучшения таймингов это не дало, т.к. перемешанный, пусть и быстро, массив 120k элементов всё равно надо было копировать обратно в RAM для подсчёта MI.

К счастью, подумал я, cupy позволяет писать и запускать произвольные ядра Cuda в C++ прямо из питона. Почему бы не выполнить расчёт гистограммы и MI прямо на GPU? Капец я с этим намучался ) Я же совсем забыл, что программирование для GPU - это сущий ад после "обычного", в поточной парадигме: ваша программа выполняется сразу на тысячах потоков, куча ограничений и условий, разделяемая память,синхронизация, атомики, блоки... Плюс я совсем забыл С++ (даже то немногое, что знал). Да ещё cupy иногда радовал перлами типа невозможности подсчитать сумму массива без Visual Studio 2019 (хотя максимум считался нормально).

В итоге всё же добил эту идею, и сейчас у меня есть реализация критической части на Cuda )

Что же по скорости?

%timeit показывает, что массив 120k элементов ноутбучная 1050Ti шаффлит в 4 раза быстрее, чем i7-7700HQ. То есть я могу ожидать, что 0.8*0.8*0.7=40% всего времени исполнения сократится в 4 раза. Если поиск на CPU идёт 15 минут, то можно ожидать, что на GPU это будет 15*0.6+15*0,4/4=11 минут.

Напрямую сравнить CPU и GPU не получается, т.к. у разных библ разные сиды и порядок выполнения операций, а длительность всего поиска зависит от случайных решений. Пара запусков дала новое время 12.5-13.0 минут вместо 15. Возможно, где-то налажал, буду ещё профилировать. Но timeit шаффла массива 1M элементов даёт выигрыш уже не в 4, а в 40 раз, т.е., по идее, GPU будет ещё выгоднее для больших датасетов.
1