#earlystopping #pipelines #boostings
При тестировании отборщиков признаков в конвейере (а это, по идее, лучшая практика) вдруг осознал, что из 3-х основных бустингов только катбуст может обучать финальную модель с ранней остановкой, и то, если нет категориальных признаков в датасете. Все остальные требуют явного указания валидационного множества в fit_params, т.е. создаёшь такой его до запуска конвейера из начальных признаков (а как ещё-то?), первым этапом конвейера запускается отборщик признаков, убирает у тебя, скажем, половину фич, передаёт самые важные на обучение финальной модели, а она валится с ошибкой, что в валидационном множестве найдены несовпадающие признаки. Вопрос: каким местом думают разработчики популярных бустингов, почему не сделали передачу индексов или вообще сплиттеров вместо полноценных данных?
Пока выход виден только один, отказаться от лучшей практики и фиттить отборщик признаков отдельно. Или есть ещё варианты?
Почему это вообще считалось лучшей практикой? Наверное, потому, что весь конвейер было легко сохранить в один файл и обучать на любых новых данных почти одной строкой. Почти потому, что надо ж ещё просплитить данные было на train и eval.
Пока что, если хочется следовать остальным лучшим практикам (Early Stopping etc), выходит что конвейер надо сохранять 2 частями: препроцессинг (с потенциальным созданием новых фичей)+FS, и финальная моделька (потенциально + обёртка в виде HPT).
Что-то не могу придумать красивого варианта (
При тестировании отборщиков признаков в конвейере (а это, по идее, лучшая практика) вдруг осознал, что из 3-х основных бустингов только катбуст может обучать финальную модель с ранней остановкой, и то, если нет категориальных признаков в датасете. Все остальные требуют явного указания валидационного множества в fit_params, т.е. создаёшь такой его до запуска конвейера из начальных признаков (а как ещё-то?), первым этапом конвейера запускается отборщик признаков, убирает у тебя, скажем, половину фич, передаёт самые важные на обучение финальной модели, а она валится с ошибкой, что в валидационном множестве найдены несовпадающие признаки. Вопрос: каким местом думают разработчики популярных бустингов, почему не сделали передачу индексов или вообще сплиттеров вместо полноценных данных?
Пока выход виден только один, отказаться от лучшей практики и фиттить отборщик признаков отдельно. Или есть ещё варианты?
Почему это вообще считалось лучшей практикой? Наверное, потому, что весь конвейер было легко сохранить в один файл и обучать на любых новых данных почти одной строкой. Почти потому, что надо ж ещё просплитить данные было на train и eval.
Пока что, если хочется следовать остальным лучшим практикам (Early Stopping etc), выходит что конвейер надо сохранять 2 частями: препроцессинг (с потенциальным созданием новых фичей)+FS, и финальная моделька (потенциально + обёртка в виде HPT).
Что-то не могу придумать красивого варианта (
#boostings #mlgems
В процессе сравнения методов FS я словил когнитивный диссонанс. Уже энное количество лет я думал, что градиентные бустинги над деревьями - это прямо панацея для табличных данных, и всегда по дефолту использовал их.
Ну да, от деревянных методов не приходится ожидать хорошей экстраполяции (за пределы обучающей выборки), но я их раньше тестировал, интерполируя синтетические данные на сложных нелинейных трансцендентных функциях, связи отлично ловились, и я привык считать бустинги априори лучшим решением.
Только недавно я стал исследовать возможность и эффекты добавления альтернативных классов моделей в ансамбль.
Плюс, в моих DS проектах обычно не хватало времени и/или бюджета на тюнинг гиперпараметров, и я так с потолка оценивал эффект от HPT в +- 10% - nice to have, но не критично.
Всем, кто в опросе выше выбрал 1-й вариант, я советую запустить вот такой простой пример:
и попытаться понять, что происходит.
Очень большим открытием для меня стало, что бустинги не могут хорошо промоделировать даже сумму 3 случайных величин, особенно если одна их них сильно в другой шкале. Задача, с которой на ура справляется линейная регрессия!
Мне подсказали увеличить катбустовый (гипер)параметр border_count, но даже с максимальным значением RMSE всё равно высока. Ну хотя бы снижается втрое.
Какие выводы можно сделать из данного примера:
1) всегда проверяйте несколько альтернативных классов моделей, обязательно включая линейные
2) в некоторых случаях HPT даёт прирост не в 10-15, а в 300-500% (также справедливо для категориек в xgboost. ну плохо он умеет с ними обращаться, плохо). делайте HPT.
3) lightgbm с линейной регрессией в листьях (вместо константы) решает задачу LGBMRegressor (linear_tree=True)
4) в общем случае бустинги требуют в качестве препроцессора не только PolynomialFeatures для моделирования произведений, но и, похоже, "AdditiveFeatures", дающего суммы/линейные комбинации сырых признаков.
5) плохонький и простенький посчитанный численный эксперимент лучше любого предвзятого убеждения.
6) декомпозиция рулит
В процессе сравнения методов FS я словил когнитивный диссонанс. Уже энное количество лет я думал, что градиентные бустинги над деревьями - это прямо панацея для табличных данных, и всегда по дефолту использовал их.
Ну да, от деревянных методов не приходится ожидать хорошей экстраполяции (за пределы обучающей выборки), но я их раньше тестировал, интерполируя синтетические данные на сложных нелинейных трансцендентных функциях, связи отлично ловились, и я привык считать бустинги априори лучшим решением.
Только недавно я стал исследовать возможность и эффекты добавления альтернативных классов моделей в ансамбль.
Плюс, в моих DS проектах обычно не хватало времени и/или бюджета на тюнинг гиперпараметров, и я так с потолка оценивал эффект от HPT в +- 10% - nice to have, но не критично.
Всем, кто в опросе выше выбрал 1-й вариант, я советую запустить вот такой простой пример:
import numpy as np, pandas as pd
from lightgbm import LGBMRegressor
from catboost import CatBoostRegressor
from sklearn.metrics import root_mean_squared_error
X=np.random.normal(0,9,size=(10_000,3)) # generate 3 random features with normal distribution
X[:,0]=X[:,0]*1000 # make one feature of a bigger magnitude
y=X.sum(axis=1) # target is just an exact sum of our 3 features
model=CatBoostRegressor(verbose=0,eval_fraction=0.1)
model.fit(X,y,plot=True)
print(f"train RMSE={root_mean_squared_error(y,model.predict(X))}")
train RMSE=311.7677815427915
и попытаться понять, что происходит.
Очень большим открытием для меня стало, что бустинги не могут хорошо промоделировать даже сумму 3 случайных величин, особенно если одна их них сильно в другой шкале. Задача, с которой на ура справляется линейная регрессия!
Мне подсказали увеличить катбустовый (гипер)параметр border_count, но даже с максимальным значением RMSE всё равно высока. Ну хотя бы снижается втрое.
Какие выводы можно сделать из данного примера:
1) всегда проверяйте несколько альтернативных классов моделей, обязательно включая линейные
2) в некоторых случаях HPT даёт прирост не в 10-15, а в 300-500% (также справедливо для категориек в xgboost. ну плохо он умеет с ними обращаться, плохо). делайте HPT.
3) lightgbm с линейной регрессией в листьях (вместо константы) решает задачу LGBMRegressor (linear_tree=True)
4) в общем случае бустинги требуют в качестве препроцессора не только PolynomialFeatures для моделирования произведений, но и, похоже, "AdditiveFeatures", дающего суммы/линейные комбинации сырых признаков.
5) плохонький и простенький посчитанный численный эксперимент лучше любого предвзятого убеждения.
6) декомпозиция рулит
👍2❤1🔥1
#boostings #mlgems
Подумал, жаль, что даже в лучших в современных библиотеках машинного обучения нет параметра timeout. В xgboost, catboost, lightgbm есть максимальное количество деревьев n_estimators, но вряд ли кому есть дело до точного количества деревьев в решении. Что на самом деле важно, так это максимальное время обучения модели, правда? Так почему бы не дать возможность его непосредственно задать параметром timeout?
Запостил feature requests. Мне, правда, указывают, что можно для этих целей приспособить коллбэк и отлавливать исключение, но в xgboost неясно, сохранится ли лучшая модель, если используется защита от оверфита. Да и гораздо удобнее, если такой простой параметр будет во всех либах без необходимости конструировать и тестировать свои коллбэки.
Если кто согласен с полезностью такой фичи, буду рад поддержке в гитхабовских ветках.
Подумал, жаль, что даже в лучших в современных библиотеках машинного обучения нет параметра timeout. В xgboost, catboost, lightgbm есть максимальное количество деревьев n_estimators, но вряд ли кому есть дело до точного количества деревьев в решении. Что на самом деле важно, так это максимальное время обучения модели, правда? Так почему бы не дать возможность его непосредственно задать параметром timeout?
Запостил feature requests. Мне, правда, указывают, что можно для этих целей приспособить коллбэк и отлавливать исключение, но в xgboost неясно, сохранится ли лучшая модель, если используется защита от оверфита. Да и гораздо удобнее, если такой простой параметр будет во всех либах без необходимости конструировать и тестировать свои коллбэки.
Если кто согласен с полезностью такой фичи, буду рад поддержке в гитхабовских ветках.
GitHub
Feature Request: add timeout parameter to the .fit() method · Issue #10684 · dmlc/xgboost
Adding the timeout parameter to the .fit() method, that should force the library to return best known solution found so far as soon as provided number of seconds since the start of training are pas...
❤1👍1
#boostings #regression #trees #compositeregressor
В свете недавних разочарований по поводу неспособности деревянных моделей к хорошему прогнозу линейных комбинаций признаков сделал свою реализацию CompositeRegressor (совместимую с scikit-learn), которая призвана решать эту проблему (и решает) композицией сначала линейной, а на её невязках уже нелинейной "деревянной" модели.
Причём линейная может строиться не на всех исходных признаках, а лишь на их "устойчивом" подмножестве (чтобы не лезла в нелинейную часть, которую лучше оставить модельке верхнего уровня).
Сейчас пишу сопроводительную статью и (вопреки своей лени и дремучести) покрываю модуль тестами, т.к. хочу показать читателям не только полезный с точки зрения ds приём, но и грамотную программерскую реализацию, готовую к боевому внедрению, в т.ч. корпоративного уровня.
В свете недавних разочарований по поводу неспособности деревянных моделей к хорошему прогнозу линейных комбинаций признаков сделал свою реализацию CompositeRegressor (совместимую с scikit-learn), которая призвана решать эту проблему (и решает) композицией сначала линейной, а на её невязках уже нелинейной "деревянной" модели.
Причём линейная может строиться не на всех исходных признаках, а лишь на их "устойчивом" подмножестве (чтобы не лезла в нелинейную часть, которую лучше оставить модельке верхнего уровня).
Сейчас пишу сопроводительную статью и (вопреки своей лени и дремучести) покрываю модуль тестами, т.к. хочу показать читателям не только полезный с точки зрения ds приём, но и грамотную программерскую реализацию, готовую к боевому внедрению, в т.ч. корпоративного уровня.
🔥6👍5