Xgboost: Распределенные вычисления с Dask

Созданный на 13 февр. 2017  ·  46Комментарии  ·  Источник: dmlc/xgboost

Здравствуйте, я автор Dask , библиотеки для параллельных и распределенных вычислений на Python. Мне любопытно, есть ли в этом сообществе интерес к сотрудничеству в распространении XGBoost на Dask либо для параллельного обучения, либо для ETL.

Вероятно, есть два компонента Dask, которые имеют отношение к этому проекту:

  1. Общая система для параллельных и распределенных вычислений, построенная на произвольном динамическом планировании задач. Соответствующие API здесь, вероятно, dask.delayed и concurrent.futures .
  2. Параллельное и распределенное подмножество API Pandas, dask.dataframe , полезное для разработки функций и предварительной обработки данных. Это не реализует весь API Pandas, но довольно близко.

Есть ли здесь интерес к сотрудничеству?

Самый полезный комментарий

Блокнот: https://gist.github.com/19c89d78e34437e061876a9872f4d2df
Короткий скринкаст (шесть минут): https://youtu.be/Cc4E-PdDSro

Критическая обратная связь очень приветствуется. Еще раз прошу простить мое невежество в этой области.

Все 46 Комментарий

@mrocklin Я думал, что у Dask есть интеграция со sklearn. Вы взглянули на нашу оболочку sklearn, чтобы увидеть, будет ли она работать с этим?

Значимая интеграция с распределенной системой обычно должна выполняться на уровне каждого алгоритма, а не на уровне библиотеки. Есть несколько способов, которыми SKLearn и Dask могут помочь друг другу, да, но они не особенно глубоки.

Dask dataframe был бы хорошим началом. В нашей базе кода у нас есть проверка на кадр данных pandas. Возможно, для начала подойдет dask dataframe.

Итак, что произойдет, если кто-то прибудет с многотерабайтным кадром данных dask? Вы просто конвертируете его в Pandas и продолжаете? Или есть способ разумно распараллелить XGBoost в кластере, указав на различные кадры данных pandas, которые составляют кадр данных dask?

Пользователи могут указать размер партии? Я полагаю, что пользователи могут получить пользу от partial_fit.

cc @tqchen , который лучше знаком с распределенной частью кода.

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

@mrocklin Я думаю, что наиболее важной частью является модуль xgboost-spark и xgboost-flink, который встраивает xgboost в функцию mapPartition spark/flink. Я думаю, в Даске было бы что-то подобное

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

см. соответствующий код в https://github.com/dmlc/xgboost/blob/master/jvm-packages/xgboost4j-spark/src/main/scala/ml/dmlc/xgboost4j/scala/spark/XGBoost.scala#L112 .

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

Запуск других распределенных систем из Dask обычно вполне выполним. Как вы перемещаете данные из распределенной системы хостинга (spark/flink/dask) в xg-boost? Или это для распределенного обучения на малых данных?

Более конкретно, я ожидаю построить систему следующим образом:

  • На каждом работнике dask я запускаю сервер Rabit. Dask предоставляет этим серверам Rabit достаточно информации, чтобы найти друг друга.
  • Я создаю некоторое локальное состояние XGBoost для каждого рабочего, которое представляет текущую модель обучения.
  • Я неоднократно подаю этот объект для каждого рабочего объекта pandas dataframes или массивы numpy
  • Я слушаю какой-то сигнал от XGBoost, который говорит мне остановиться

Соответствует ли это вашим ожиданиям? Легко ли вам указать мне на соответствующий Python API?

Да, см. соответствующую информацию здесь https://github.com/dmlc/xgboost/blob/master/tests/distributed/ для API Python.

Что вам нужно будет сделать дополнительно, так это запустить средство отслеживания кроликов на стороне водителя (вероятно, это место, которое управляет dask), это делается в сценарии dmlc-submit здесь https://github.com/dmlc/dmlc-core /дерево/мастер/трекер/dmlc_tracker

ОК, заполнение моей схемы из ранее:

Перед запуском любого кода XGBoost мы настраиваем сеть Rabit.

На узле драйвер/планировщик запускаем трекер кроликов

envs = {'DMLC_NUM_WORKER' : nworker,
        'DMLC_NUM_SERVER' : nserver}

rabit = RabitTracker(hostIP=ip_address, nslave=num_workers)
envs.update(rabit.slave_envs())
rabit.start(args.num_workers)  # manages connections in background thread

Я также могу пройти через аналогичный процесс, чтобы начать PSTracker . Это должно быть на той же централизованной машине или где-то еще в сети? Их должно быть несколько? Должно ли это быть настраиваемым пользователем?

В конце концов, мой трекер (и пстрекеры?) присоединяются к сети кроликов и блокируются.

rabit.join()  # join network

На рабочих узлах мне нужно сбросить эти переменные среды (которые я буду перемещать по обычным каналам dask) в локальную среду. Тогда достаточно просто позвонить xgboost.rabit.init()

import os
os.environ.update(envs)
xgboost.rabit.init()

Глядя на код Rabit, кажется, что переменные среды — единственный способ предоставить эту информацию. Вы можете это проверить? Есть ли способ предоставить информацию о хосте / порте трекера в качестве прямых входов?

Повышение квалификации

Затем я конвертирую свои массивы numpy / кадры данных pandas / разреженные массивы scipy в объекты DMatrix, это кажется относительно простым. Однако у меня, вероятно, будет несколько пакетов данных на одного работника. Есть ли чистый способ вызвать поезд несколько раз с дополнительными данными по мере их поступления? Меня беспокоят комментарии к этим строкам:

# Run training, all the features in training API is available.
# Currently, this script only support calling train once for fault recovery purpose.
bst = xgb.train(param, dtrain, num_round, watchlist, early_stopping_rounds=2)

Нужно ли ждать поступления всех данных перед началом обучения?

Пример набора данных/проблемы

Если предположить, что у меня все правильно, то есть ли стандартный пример распределенного обучения, который люди используют для демонстрации?

Нет необходимости запускать pstracker.

  • Трекер нужно запускать только в одном месте, скорее всего, в планировщике (драйвере), он не требует больших объемов данных и служит только для подключения работ.
  • Аргументы env могут передаваться как kwargs в rabit.init.
  • Поскольку бустинг дерева — это пакетный алгоритм, нам нужно дождаться загрузки всех данных, прежде чем начинать обучение.

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

    • В идеале мы должны использовать интерфейс data iter для передачи данных в DMatrix в виде мини-пакета, чтобы весь набор данных не должен был находиться в памяти.

    • Это делается через https://github.com/dmlc/xgboost/blob/master/include/xgboost/c_api.h#L117 , у которых еще нет оболочки python.

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

У меня было немного времени, чтобы поиграть с этим сегодня утром. Результаты здесь: https://github.com/mrocklin/dask-xgboost

Пока он обрабатывает только распределенное обучение одного набора данных в памяти. Возникли некоторые вопросы:

  1. Каков наилучший способ сериализации и передачи объектов DMatrix?
  2. Каков наилучший способ сериализации и возврата результата Booster?
  3. Как перечисленные выше переменные среды сопоставляются с аргументами в rabit.init ? Какова именно ожидаемая форма входных данных для rabit.init ? Очевидно, что передача результата slave_envs() в rabit.init не сработает, потому что он ожидает список. Должны ли мы преобразовать каждое имя ключа в --key , возможно, убрав префикс DMLC и преобразовав его в нижний регистр?
  4. Есть ли хороший способ проверить правильность? Как сравнить два объекта Booster? Должны ли мы ожидать, что распределенное обучение даст точно такой же результат, как и последовательное обучение?
  • Обычно вы не сериализуете DMatrix, это больше похоже на держатель данных времени обучения, я предполагаю, что данные передаются и совместно используются dask (массив/фрейм данных), а затем передаются в xgboost

    • Мы можем изучить лучшие способы передачи данных, отличные от прямого массива в памяти, возможно, путем предоставления итератора данных для xgboost.

  • Вы можете использовать Booster, если xgboost установлен с обеих сторон.
  • Извините, что не уточняю, как вещи передаются, это должно быть
rabit.init(['DMLC_KEY1=VALUE1', 'DMLC_KEY2=VALUE2']
  • Обычно бустер, обученный на распределенной и одиночной машине, отличается, но вот несколько вещей, которые нужно проверить.

    • Бустер, возвращаемый со всех рабочих, должен быть одинаковым

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

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

  1. Разумно ли использовать несколько воркеров для одних и тех же входных данных? (XGBoost связан с вычислениями?)
  2. Если мы работаем с большими наборами данных, нужно ли мне делать что-то особенное, чтобы сообщить каждому рабочему процессу XGBoost, что его данные отличаются от его аналогов?

Какой вариант использования более распространен?

Каждая работа должна работать с разными разделами данных (по строкам), они НЕ должны смотреть на одни и те же входные данные.

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

Обычно это соответствует операции mapPartition в таких фреймворках, как spark/flink.

Скажем, мой набор данных имеет 8 строк, 4 столбца, если мы запустим двух рабочих

  • рабочий 0 читает из строки 0-3
  • рабочий 1 читает с 4 по 7 строку

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

  1. Сохраните массив dask или кадр данных в кластере, дождитесь его завершения.
  2. Найдите, где закончился каждый фрагмент/раздел
  3. Скажите каждому рабочему конкатенировать именно эти фрагменты/разделы и тренироваться на них.

Это решение кажется управляемым, но не идеальным. Было бы удобно, если бы xgboost-python мог принимать результаты по мере их поступления. Однако я думаю, что следующее, что нужно сделать, это попробовать это на практике.

Поищу примеры в интернете. Если у кого-то возникнет искусственная проблема, которую я могу легко создать с помощью API numpy или pandas, это будет приветствоваться. А пока вот тривиальный пример на моем ноутбуке со случайными данными:

In [1]: import dask.dataframe as dd

In [2]: df = dd.demo.make_timeseries('2000', '2001', {'x': float, 'y': float, 'z': int}, freq='1s', partition_freq=
   ...: '1D')  # some random time series data

In [3]: df.head()
Out[3]: 
                            x         y     z
2000-01-01 00:00:00  0.778864  0.824796   977
2000-01-01 00:00:01 -0.019888 -0.173454  1023
2000-01-01 00:00:02  0.552826  0.051995  1083
2000-01-01 00:00:03 -0.761811  0.780124   959
2000-01-01 00:00:04 -0.643525  0.679375   980

In [4]: labels = df.z > 1000

In [5]: del df['z']

In [6]: df.head()
Out[6]: 
                            x         y
2000-01-01 00:00:00  0.778864  0.824796
2000-01-01 00:00:01 -0.019888 -0.173454
2000-01-01 00:00:02  0.552826  0.051995
2000-01-01 00:00:03 -0.761811  0.780124
2000-01-01 00:00:04 -0.643525  0.679375

In [7]: labels.head()
Out[7]: 
2000-01-01 00:00:00    False
2000-01-01 00:00:01     True
2000-01-01 00:00:02     True
2000-01-01 00:00:03    False
2000-01-01 00:00:04    False
Name: z, dtype: bool

In [8]: from dask.distributed import Client

In [9]: c = Client()  # creates a local "cluster" on my laptop

In [10]: from dask_xgboost import train
/home/mrocklin/Software/anaconda/lib/python3.5/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
  "This module will be removed in 0.20.", DeprecationWarning)

In [11]: param = {'max_depth': 2, 'eta': 1, 'silent': 1, 'objective': 'binary:logistic'}  # taken from example

In [12]: bst = train(c, param, df, labels)
/home/mrocklin/Software/anaconda/lib/python3.5/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
  "This module will be removed in 0.20.", DeprecationWarning)
/home/mrocklin/Software/anaconda/lib/python3.5/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
  "This module will be removed in 0.20.", DeprecationWarning)
/home/mrocklin/Software/anaconda/lib/python3.5/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
  "This module will be removed in 0.20.", DeprecationWarning)
/home/mrocklin/Software/anaconda/lib/python3.5/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
  "This module will be removed in 0.20.", DeprecationWarning)
[14:46:20] Tree method is automatically selected to be 'approx' for faster speed. to use old behavior(exact greedy algorithm on single machine), set tree_method to 'exact'
[14:46:20] Tree method is automatically selected to be 'approx' for faster speed. to use old behavior(exact greedy algorithm on single machine), set tree_method to 'exact'
[14:46:20] Tree method is automatically selected to be 'approx' for faster speed. to use old behavior(exact greedy algorithm on single machine), set tree_method to 'exact'
[14:46:20] Tree method is automatically selected to be 'approx' for faster speed. to use old behavior(exact greedy algorithm on single machine), set tree_method to 'exact'

In [13]: bst
Out[13]: <xgboost.core.Booster at 0x7fbaacfd17b8>

Соответствующий код находится здесь, если кто-то хочет взглянуть: https://github.com/mrocklin/dask-xgboost/blob/master/dask_xgboost/core.py

Как я уже сказал, я новичок в XGBoost, поэтому, вероятно, что-то упускаю.

типичный пример игрушки, который можно попробовать, находится в https://github.com/dmlc/xgboost/tree/master/demo/data .
Однако он находится в формате libsvm, и его нужно немного разобрать, чтобы получить его в numpy.

Что-то большее (для чего вам действительно понадобится кластер)? Или есть стандартный способ создать набор данных произвольного размера?

Или, может быть, лучше задать вопрос: «Что бы вы (или кто-либо еще, читающий этот выпуск) хотели бы здесь увидеть?»

Строительство прогнозируют сейчас. Если я верну модель обратно рабочему процессу (проходя процесс рассола/разбора), а затем вызову bst.predict для некоторых данных, я получу следующую ошибку:

Doing rabit call after Finalize

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

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

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

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

Тестирование набора данных, который действительно имеет значение, было сложным, например (попробуйте 1 набор данных с 1 миллиардом строк). Kaggle может иметь какой-то большой набор данных, который может иметь отношение, около 10 миллионов.

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

Вот пример использования этих данных с пандами и xgboost на одном ядре. Приветствуются любые рекомендации по подготовке данных, параметрам или тому, как это сделать правильно.

In [1]: import pandas as pd

In [2]: df = pd.read_csv('train-0.1m.csv')

In [3]: df.head()
Out[3]: 
  Month DayofMonth DayOfWeek  DepTime UniqueCarrier Origin Dest  Distance  \
0   c-8       c-21       c-7     1934            AA    ATL  DFW       732   
1   c-4       c-20       c-3     1548            US    PIT  MCO       834   
2   c-9        c-2       c-5     1422            XE    RDU  CLE       416   
3  c-11       c-25       c-6     1015            OO    DEN  MEM       872   
4  c-10        c-7       c-6     1828            WN    MDW  OMA       423   

  dep_delayed_15min  
0                 N  
1                 N  
2                 N  
3                 N  
4                 Y  

In [4]: labels = df.dep_delayed_15min == 'Y'

In [5]: del df['dep_delayed_15min']

In [6]: df = pd.get_dummies(df)

In [7]: len(df.columns)
Out[7]: 652

In [8]: import xgboost as xgb
/home/mrocklin/Software/anaconda/lib/python3.5/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
  "This module will be removed in 0.20.", DeprecationWarning)

In [9]: dtrain = xgb.DMatrix(df, label=labels)

In [10]: param = {}  # Are there better choices for parameters?  I could use help here

In [11]: bst = xgb.train(param, dtrain)  # or other parameters here?
[17:50:28] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 124 extra nodes, 0 pruned nodes, max_depth=6
[17:50:30] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 120 extra nodes, 0 pruned nodes, max_depth=6
[17:50:32] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 120 extra nodes, 0 pruned nodes, max_depth=6
[17:50:33] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 116 extra nodes, 0 pruned nodes, max_depth=6
[17:50:35] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 112 extra nodes, 0 pruned nodes, max_depth=6
[17:50:36] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 114 extra nodes, 0 pruned nodes, max_depth=6
[17:50:38] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 106 extra nodes, 0 pruned nodes, max_depth=6
[17:50:39] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 116 extra nodes, 0 pruned nodes, max_depth=6
[17:50:41] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 104 extra nodes, 0 pruned nodes, max_depth=6
[17:50:43] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 100 extra nodes, 0 pruned nodes, max_depth=6

In [12]: test = pd.read_csv('test.csv')

In [13]: test.head()
Out[13]: 
  Month DayofMonth DayOfWeek  DepTime UniqueCarrier Origin Dest  Distance  \
0   c-7       c-25       c-3      615            YV    MRY  PHX       598   
1   c-4       c-17       c-2      739            WN    LAS  HOU      1235   
2  c-12        c-2       c-7      651            MQ    GSP  ORD       577   
3   c-3       c-25       c-7     1614            WN    BWI  MHT       377   
4   c-6        c-6       c-3     1505            UA    ORD  STL       258   

  dep_delayed_15min  
0                 N  
1                 N  
2                 N  
3                 N  
4                 Y  

In [14]: test_labels = test.dep_delayed_15min == 'Y'

In [16]: del test['dep_delayed_15min']

In [17]: test = pd.get_dummies(test)

In [18]: len(test.columns)  # oops, looks like the columns don't match up
Out[18]: 670

In [19]: dtest = xgb.DMatrix(test)

In [20]: predictions = bst.predict(dtest)  # this fails because of mismatched columns

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

cc @TomAugspurger , похоже, у него есть мысли по этому поводу.

Что касается Dask и Predict, я всегда могу снова настроить Rabit. Это кажется немного нечистым, потому что заставляет оценивать, а не делает вещи ленивыми. Но это не серьезный блокировщик для использования.

Возникли некоторые проблемы с прогнозированием. Два вопроса:

  1. Могу ли я вызывать Booster.predict несколько раз в течение одного и того же сеанса Rabit?
  2. Могу ли я вызывать rabit.init , Booster.predict и rabit.finalize в отдельных потоках?

В настоящее время я создаю новый трекер и вызываю rabit.init в основном потоке рабочего. Это прекрасно работает. Однако, когда я вызываю Booster.predict в рабочих потоках (каждый рабочий dask поддерживает пул потоков для вычислений), я получаю такие ошибки, как Doing rabit call after Finalize . Есть рекомендации?

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

Мне любопытно об этом. После того, как мы сериализуем-переносим-десериализуем обученную модель с рабочего на мою клиентскую машину, кажется, что она отлично работает с обычными данными, даже если нет сети rabit. Похоже, что модель, обученную с помощью Rabit, можно использовать для прогнозирования данных без Rabit. Это также кажется необходимым в производстве. Можете ли вы рассказать больше об ограничениях использования модели, обученной кроликам, здесь?

Пример набора данных/проблемы
Если предположить, что у меня все правильно, то есть ли стандартный пример распределенного обучения, который люди используют для демонстрации?

Было бы неплохо воспроизвести результаты этого эксперимента:

https://github.com/Microsoft/LightGBM/wiki/Experiments#parallel — эксперимент

с новой опцией binning + fast hist от XGBoost (# 1950) можно будет получить аналогичные результаты.

типичный пример игрушки, который можно попробовать, находится в https://github.com/dmlc/xgboost/tree/master/demo/data .
Однако он находится в формате libsvm, и его нужно немного разобрать, чтобы получить его в numpy.

Вас может заинтересовать этот PR в sklearn: https://github.com/scikit-learn/scikit-learn/pull/935

@mrocklin Нет ограничений на повторное использование модели. Таким образом, модель, обученная в распределенной версии, может быть использована в последовательной версии. Просто текущее ограничение предиктора (при компиляции с rabit) имеет смешанную функцию с функцией обучения (поэтому произошел вызов rabit).

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

да. Действительно, это решает проблему. dask-xgboost теперь поддерживает прогнозирование: https://github.com/mrocklin/dask-xgboost/commit/827a03d96977cda8d104899c9f42f52dac446165

Спасибо за обходной путь @tqchen !

Вот рабочий процесс с dask.dataframe и xgboost для небольшого образца набора данных авиакомпаний на моем локальном ноутбуке. Всем ли это кажется нормальным? Есть ли элементы API XGBoost, которые мне здесь не хватает?

In [1]: import dask.dataframe as dd

In [2]: import dask_xgboost as dxgb

In [3]: df = dd.read_csv('train-0.1m.csv')

In [4]: df.head()
Out[4]: 
  Month DayofMonth DayOfWeek  DepTime UniqueCarrier Origin Dest  Distance  \
0   c-8       c-21       c-7     1934            AA    ATL  DFW       732   
1   c-4       c-20       c-3     1548            US    PIT  MCO       834   
2   c-9        c-2       c-5     1422            XE    RDU  CLE       416   
3  c-11       c-25       c-6     1015            OO    DEN  MEM       872   
4  c-10        c-7       c-6     1828            WN    MDW  OMA       423   

  dep_delayed_15min  
0                 N  
1                 N  
2                 N  
3                 N  
4                 Y  

In [5]: labels = df.dep_delayed_15min == 'Y'

In [6]: del df['dep_delayed_15min']

In [7]: df = df.categorize()

In [8]: df = dd.get_dummies(df)

In [9]: data_train, data_test = df.random_split([0.9, 0.1], random_state=123)

In [10]: labels_train, labels_test = labels.random_split([0.9, 0.1], random_state=123)

In [11]: from dask.distributed import Client

In [12]: client = Client()  # in a large-data situation I probably should have done this before calling categorize above (which requires computation)

In [13]: param = {}  # Are there better choices for parameters?

In [14]: bst = dxgb.train(client, {}, data_train, labels_train)
[14:00:46] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 120 extra nodes, 0 pruned nodes, max_depth=6
[14:00:48] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 120 extra nodes, 0 pruned nodes, max_depth=6
[14:00:50] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 122 extra nodes, 0 pruned nodes, max_depth=6
[14:00:53] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 118 extra nodes, 0 pruned nodes, max_depth=6
[14:00:55] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 120 extra nodes, 0 pruned nodes, max_depth=6
[14:00:57] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 114 extra nodes, 0 pruned nodes, max_depth=6
[14:00:59] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 118 extra nodes, 0 pruned nodes, max_depth=6
[14:01:01] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 118 extra nodes, 0 pruned nodes, max_depth=6
[14:01:04] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 94 extra nodes, 0 pruned nodes, max_depth=6
[14:01:06] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 102 extra nodes, 0 pruned nodes, max_depth=6

In [15]: bst
Out[15]: <xgboost.core.Booster at 0x7f689803af60>

In [16]: predictions = dxgb.predict(client, bst, data_test)

In [17]: predictions
Out[17]: 
Dask Series Structure:
npartitions=1
None    float32
None        ...
Name: predictions, dtype: float32
Dask Name: _predict_part, 9 tasks

Моя краткосрочная цель — написать короткий пост об этом в блоге, чтобы, надеюсь, кто-то еще с большим опытом работы с XGBoost и с большим количеством времени принял этот проект и продвигал его вперед. (Я, как и все здесь, одновременно работаю над несколькими другими подобными проектами.)

Я неравнодушен к набору данных об авиакомпаниях только потому, что он у меня уже есть в корзине S3. Однако я согласен с тем, что набор данных Criteo поможет лучше продемонстрировать масштабирование.

Я до сих пор не уверен, какие параметры использовать или как судить о результате. Для параметров могу использовать эксперимент от @szilard здесь . Есть ли хороший способ судить о предсказаниях? Например, мы ищем predictions > 0.5 , чтобы соответствовать labels_test ?

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

Например, мы ищем прогнозы> 0,5, чтобы соответствовать labels_test?

да. Если вы возьмете среднее значение этого на тестовом наборе, это точность теста. Но вполне вероятно, что набор данных несбалансирован (гораздо больше отсутствие кликов, чем кликов). В этом случае показатель ROC AUC является лучшим показателем.

from sklearn.metrics import roc_auc_score
print(roc_auc_score(labels_test, predictions))

предполагая, что predictions представляет собой одномерный массив положительных вероятностей, оцененных моделью для каждой строки в тестовом наборе.

@mrocklin Один дополнительный вопрос: разрешает ли dask многопоточные рабочие задания? Я знаю, что это не очень актуально для python из-за GIL. Но xgboost может обеспечить многопоточное обучение для каждого работника, при этом все еще распределяя координацию друг с другом. Мы всегда должны устанавливать аргументы nthread xgboost равным количеству работающих ядер этого работника.

Короткий ответ: «да». Чаще всего Dask используется с такими проектами, как NumPy, Pandas, SKLearn и другими, которые в основном представляют собой просто код C и Fortran, завернутый в Python. GIL не влияет на эти библиотеки. Некоторые люди используют Dask для приложений, аналогичных PySpark RDD (см. dask.bag ), и это будет затронуто. Хотя эта группа в меньшинстве.

Так что да, Dask позволяет выполнять многопоточные задачи. Как мы говорим XGBoost использовать несколько потоков? Пока что в своих экспериментах я вижу высокую загрузку ЦП без изменения каких-либо параметров, так что, может быть, по умолчанию все работает хорошо?

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

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

Конечно, должно быть выполнено в
https://github.com/mrocklin/dask-xgboost/commit/c22d066b67c78710d5ad99b8620edc55182adc8f

В понедельник, 20 февраля 2017 г., в 18:31, Тяньци Чен, [email protected]
написал:

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

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


Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/dmlc/xgboost/issues/2032#issuecomment-281205747 или отключить звук
нить
https://github.com/notifications/unsubscribe-auth/AASszPELRoeIvqEzyJhkKumIs-vd0PHiks5reiJngaJpZM4L_PXa
.

Блокнот: https://gist.github.com/19c89d78e34437e061876a9872f4d2df
Короткий скринкаст (шесть минут): https://youtu.be/Cc4E-PdDSro

Критическая обратная связь очень приветствуется. Еще раз прошу простить мое невежество в этой области.

@mrocklin отличная демонстрация! Я думаю, что производительность во время выполнения (и, возможно, использование памяти) можно значительно улучшить, используя 'tree_method': 'hist', 'grow_policy': 'lossguide' в параметре dict.

Спасибо @ogrisel. При этих параметрах время тренировки увеличивается с шести минут до одной минуты. Однако использование памяти, похоже, остается примерно таким же.

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

@tqchen или @ogrisel , если у кого-то из вас есть время просмотреть реализацию на https://github.com/mrocklin/dask-xgboost/blob/master/dask_xgboost/core.py , я был бы признателен. Я понимаю, однако, что просмотр чужой кодовой базы не всегда занимает первое место в списках приоритетов.

Если все в порядке, я добавлю еще немного в README, опубликую в PyPI, и тогда, вероятно, мы сможем закрыть эту проблему.

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

Я отправил dask-xgboost в PyPI и переместил его на https://github.com/dask/dask-xgboost .

Спасибо @tqchen и @ogrisel за вашу помощь. Сотрудничество сделало это относительно легко.

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

Была ли эта страница полезной?
0 / 5 - 0 рейтинги