Xgboost: الحوسبة الموزعة مع داسك

تم إنشاؤها على ١٣ فبراير ٢٠١٧  ·  46تعليقات  ·  مصدر: dmlc/xgboost

مرحبًا ، أنا مؤلف Dask ، مكتبة للحوسبة المتوازية والموزعة في Python. لدي فضول لمعرفة ما إذا كان هناك اهتمام داخل هذا المجتمع للتعاون في توزيع XGBoost على Dask إما للتدريب الموازي أو من أجل ETL.

من المحتمل أن يكون هناك مكونان من Dask مناسبين لهذا المشروع:

  1. نظام عام للحوسبة المتوازية والموزعة ، مبني على جدولة المهام الديناميكية التعسفية. من المحتمل أن تكون واجهات برمجة التطبيقات ذات الصلة هنا dask.delayed و concurrent.futures
  2. مجموعة فرعية متوازية وموزعة من Pandas API ، dask.dataframe مفيدة لهندسة الميزات والمعالجة المسبقة للبيانات. هذا لا يطبق واجهة برمجة تطبيقات Pandas بالكامل ، ولكنه يقترب بشكل لائق.

هل هناك اهتمام بالتعاون هنا؟

التعليق الأكثر فائدة

مفكرة: https://gist.github.com/19c89d78e34437e061876a9872f4d2df
تسجيل قصير (ست دقائق): https://youtu.be/Cc4E-PdDSro

التعليقات النقدية موضع ترحيب كبير. مرة أخرى ، من فضلك اغفر جهلي في هذا المجال.

ال 46 كومينتر

mrocklin اعتقدت أن Dask لديها تكامل مع sklearn. هل ألقيت نظرة على غلاف sklearn لمعرفة ما إذا كان سيعمل مع ذلك؟

يجب أن يتم التكامل بشكل هادف مع نظام موزع على مستوى كل خوارزمية بدلاً من مستوى المكتبة. هناك بعض الطرق التي يمكن من خلالها لـ SKLearn و Dask مساعدة بعضهما البعض ، نعم ، لكنها ليست عميقة بشكل خاص.

سيكون Dask dataframe بداية جيدة. في قاعدة الكود لدينا ، لدينا فحص لإطار بيانات الباندا. قد يكون هذا هو المكان الذي يناسب dask dataframe كبداية.

إذن ماذا يحدث إذا وصل شخص ما بإطار بيانات dask متعدد تيرابايت؟ هل تقوم فقط بتحويله إلى Pandas والمضي قدمًا؟ أو هل هناك طريقة لموازنة XGBoost بذكاء عبر مجموعة ، مما يشير إلى إطارات بيانات الباندا المختلفة التي تشكل إطار بيانات dask؟

يمكن للمستخدمين تحديد حجم الدفعة؟ أتخيل أنه يمكن استفادة المستخدمين من خلال ميزة التهيئة الجزئية.

cctqchen الذي هو أكثر دراية بالجزء الموزع من الكود.

يمكن ربط النسخة الموزعة من xgboost بقاذفة الوظائف الموزعة ، ومن الأفضل الحصول على تغذية قسم البيانات في xgboost ثم المتابعة.

mrocklin أعتقد أن الجزء الأكثر صلة هو الوحدة النمطية xgboost-spark و xgboost-flink ، والتي تقوم بتضمين xgboost في وظيفة mapPartition الخاصة بـ spark / flink. أعتقد أنه سيكون هناك شيء مشابه في داسك

الشرط من جانب xgboost هو أن XGBoost يتعامل مع اتصال العملية البينية عن طريق rabit ، وسيحتاج إلى بدء تعقب (يربط كل وظيفة) من جانب العميل.

انظر التعليمات البرمجية ذات الصلة في https://github.com/dmlc/xgboost/blob/master/jvm-packages/xgboost4j-spark/src/main/scala/ml/dmlc/xgboost4j/scala/spark/XGBoost.scala#L112

تم تصميم Rabit ليتم تضمينه في نظام موزع آخر ، لذلك أعتقد أنه قد لا يكون من الصعب جدًا إجراء التعديل في جانب الثعبان.

عادةً ما يكون إطلاق أنظمة موزعة أخرى من Dask ممكنًا جدًا. كيف تقوم بنقل البيانات من نظام الاستضافة الموزع (سبارك / فلنك / داسك) إلى إكس جي-بوست؟ أم أن هذا للتدريب الموزع على البيانات الصغيرة؟

بشكل ملموس ، أتوقع بناء نظام على النحو التالي:

  • في كل عامل dask أبدأ خادم Rabit. يعطي Dask خوادم Rabit هذه معلومات كافية للعثور على بعضها البعض.
  • أقوم بإنشاء حالة XGBoost محلية على كل عامل يمثل نموذج التدريب الحالي
  • لقد قمت بإطعام إطارات بيانات الباندا للكائن لكل عامل أو المصفوفات المعقدة
  • أستمع لبعض الإشارات من XGBoost التي تخبرني بالتوقف

هل يتوافق هذا مع توقعاتك؟ هل من السهل عليك توجيهي إلى Python API ذات الصلة؟

نعم ، راجع المعلومات ذات الصلة هنا https://github.com/dmlc/xgboost/blob/master/tests/distributed/ لواجهة برمجة تطبيقات python.

ما ستحتاج إلى القيام به بالإضافة إلى ذلك هو بدء متعقب rabit من جانب السائق (من المحتمل أن يكون المكان الذي يقود dask) ، ويتم ذلك في البرنامج النصي dmlc-submit هنا https://github.com/dmlc/dmlc-core / tree / master / tracker / dmlc_tracker

حسنًا ، أكمل المخطط التفصيلي الخاص بي من قبل:

قبل تشغيل أي كود XGBoost ، قمنا بإعداد شبكة Rabit

في عقدة برنامج التشغيل / المجدول ، نبدأ أداة تعقب 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 . هل يجب أن يكون هذا على نفس الجهاز المركزي أم يجب أن يكون في مكان آخر داخل الشبكة؟ هل يجب أن يكون هناك القليل من هؤلاء؟ هل يجب أن يكون هذا قابلًا للتكوين بواسطة المستخدم؟

في النهاية لدي متتبع (و pstrackers؟) ينضم إلى شبكة rabit والحظر.

rabit.join()  # join network

في العقد العاملة ، أحتاج إلى تفريغ متغيرات البيئة هذه (التي سأنتقل إليها عبر قنوات dask العادية) في البيئة المحلية. ثم مجرد استدعاء xgboost.rabit.init() يجب أن يكون كافياً

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

بالنظر إلى كود Rabit ، يبدو أن متغيرات البيئة هي الطريقة الوحيدة لتوفير هذه المعلومات. هل يمكنك التحقق من هذا؟ هل هناك طريقة لتوفير معلومات مضيف / منفذ تعقب كمدخلات مباشرة؟

تمرين

ثم أقوم بتحويل المصفوفات المتناثرة / إطارات بيانات الباندا / المصفوفات المتناثرة إلى كائنات 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
  • نظرًا لأن تعزيز الشجرة عبارة عن خوارزمية مجمعة ، فنحن بحاجة إلى انتظار استيعاب جميع البيانات قبل بدء التدريب.

    • لاحظ مع ذلك أن كل عامل يحتاج فقط لأخذ جزء (مجموعة فرعية من الصفوف) من البيانات.

    • من الناحية المثالية ، يجب أن نستخدم واجهة تكرار البيانات لتمرير البيانات إلى DMatrix كأسلوب دفعة صغيرة ، لذلك لا يتعين على مجموعة البيانات بأكملها أن تجلس في الذاكرة

    • يتم ذلك عبر https://github.com/dmlc/xgboost/blob/master/include/xgboost/c_api.h#L117 ، والتي لا تحتوي على غلاف بيثون حتى الآن.

    • بالنسبة للحل الأول ، أوصي بالمرور مباشرة بواسطة المصفوفة

كان لدي بعض الوقت للعب مع هذا الصباح. النتائج هنا: https://github.com/mrocklin/dask-xgboost

حتى الآن ، يتعامل فقط مع التعلم الموزع لمجموعة بيانات واحدة في الذاكرة. نشأت بعض الأسئلة:

  1. ما هي أفضل طريقة لتسلسل وتمرير كائنات DMatrix؟
  2. ما هي أفضل طريقة لإجراء تسلسل وإرجاع نتيجة Booster؟
  3. كيف متغيرات البيئة المذكورة أعلاه تعين الوسيطات في rabit.init ؟ ما هو شكل المدخلات المتوقع تحديدًا لـ rabit.init ؟ من الواضح أن تمرير نتيجة slave_envs() إلى rabit.init لن ينجح لأنه يتوقع قائمة. هل يجب علينا تحويل كل اسم مفتاح إلى --key ، ربما بإسقاط البادئة DMLC والتحويل إلى أحرف صغيرة؟
  4. هل هناك طريقة جيدة لاختبار الصحة؟ كيف نقارن بين كائنين معززين؟ هل يجب أن نتوقع أن ينتج عن التدريب الموزع نفس النتيجة بالضبط والتدريب المتسلسل؟
  • لا تقوم عادةً بتسلسل 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 أو dataframe على الكتلة ، وانتظر حتى تنتهي
  2. ابحث عن مكان انتهاء كل جزء / قسم
  3. اطلب من كل عامل أن يسلسل تلك الأجزاء / الأقسام بالضبط ويتدرب عليها

يبدو أن هذا الحل يمكن إدارته ، لكنه ليس مثاليًا. سيكون من الملائم أن تقبل xgboost-python النتائج فور وصولها. ومع ذلك ، أعتقد أن الشيء التالي الذي يجب فعله هو تجربته في الممارسة العملية.

سأبحث حول الإنترنت للحصول على أمثلة. إذا كان لدى أي شخص مشكلة مصطنعة يمكنني إنشاؤها بسهولة باستخدام واجهة برمجة تطبيقات 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

أي شيء أكبر (ستحتاج بالفعل إلى كتلة)؟ أم أن هناك طريقة قياسية لإنشاء مجموعة بيانات ذات حجم عشوائي؟

أو ربما يكون السؤال الأفضل هو: "ما الذي تود (أو أي شخص آخر يقرأ هذا العدد) أن تراه هنا؟"

توقع بناء الآن. إذا قمت بنقل النموذج مرة أخرى إلى عامل (يمر بعملية pickle / unpickle) ثم اتصلت بـ bst.predict في بعض البيانات ، فسأحصل على الخطأ التالي:

Doing rabit call after Finalize

كان افتراضي ، في هذه المرحلة ، أن النموذج قائم بذاته ولم يعد بحاجة إلى استخدام الأرانب. يبدو أنه يعمل بشكل جيد على جهاز العميل. هل لديك أية أفكار حول سبب تلقي هذا الخطأ عند الاتصال بـ predict ؟

جزء من التنبؤ لا يزال يستخدم rabit ، ويرجع ذلك أساسًا إلى أن المتنبئ لا يزال يستخدم المتعلم مع بعض إجراءات التهيئة التي يتم مشاركتها مع التدريب. في النهاية يجب إصلاح هذا ، ولكن هذا هو الحال الآن.

أعتقد أنه طالما أنها تعمل بشكل جيد لمجموعة البيانات المشتركة ، فهي نقطة انطلاق مثيرة للاهتمام.

هناك أسباب لاستخدام مجموعة للبيانات المتوسطة على أي حال (سهولة الجدولة في بيئة المجموعة) ، قد يكون بعض مستخدمي pyspark مهتمين بتجربتها إذا قمنا بالإعلان عنها قليلاً

كان الاختبار على مجموعة البيانات المهمة حقًا صعبًا ، على سبيل المثال (جرب مجموعة بيانات واحدة تحتوي على مليار صف). قد تكون Kaggle مجموعة بيانات كبيرة يمكن أن تكون ذات صلة بحوالي 10 ملايين.

يعرض هذا المستودع تجارب على مجموعة بيانات شركات الطيران ، والتي أعتقد أنها موجودة في عشرات الملايين من الصفوف وعشرات الأعمدة (ألف بعد ترميز واحد ساخن؟) بالنسبة لمعيارهم ، يبدو أنهم أخذوا عينة من 100 ألف صف وتم إنشاؤها بشكل مصطنع أكبر مجموعات البيانات من هذه العينة. من المفترض أن نتمكن من توسيع نطاق هذا إذا لزم الأمر.

فيما يلي مثال على استخدام هذه البيانات مع حيوانات الباندا و 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

على أي حال ، هنا خيار. تبدو مجموعة بيانات شركات الطيران معروفة جيدًا ويمكن أن تكون كبيرة بشكل غير مريح في الممارسة العملية. مرة أخرى ، التعلم الآلي ليس تخصصي ، لذلك لا أعرف ما إذا كان هذا مناسبًا أم لا.

ccTomAugspurger ، الذي يبدو مثل ذلك النوع من الرجل الذي قد يكون لديه أفكار حول هذا الأمر.

فيما يتعلق بـ Dask والتنبؤ ، يمكنني دائمًا إعداد rabit مرة أخرى. هذا يبدو غير نظيف بعض الشيء لأنه يفرض التقييم بدلاً من إبقاء الأمور كسولة. لكن هذا ليس مانعًا خطيرًا للاستخدام.

الوقوع في بعض المشاكل مع التنبؤ. سؤالين:

  1. هل يمكنني الاتصال بـ Booster.predict عدة مرات في نفس جلسة rabit؟
  2. هل يمكنني الاتصال بـ rabit.init و Booster.predict و rabit.finalize في سلاسل منفصلة؟

أقوم حاليًا بإنشاء أداة تعقب جديدة ، وأتصل بـ rabit.init على مؤشر ترابط العامل الرئيسي. هذا يعمل بشكل جيد. ومع ذلك ، عندما أتصل بـ Booster.predict في سلاسل العمليات (يحتفظ كل عامل dask بمجموعة مؤشرات ترابط للحساب) أحصل على أخطاء مثل Doing rabit call after Finalize . أي توصيات؟

جزء من التنبؤ لا يزال يستخدم rabit ، ويرجع ذلك أساسًا إلى أن المتنبئ لا يزال يستخدم المتعلم مع بعض إجراءات التهيئة التي يتم مشاركتها مع التدريب. في النهاية يجب إصلاح هذا ، ولكن هذا هو الحال الآن.

أشعر بالفضول حيال هذا. بعد أن قمنا بإجراء تسلسل - نقل - إلغاء تسلسل النموذج المدرب من عامل إلى جهاز العميل الخاص بي ، يبدو أنه يعمل بشكل جيد على البيانات العادية على الرغم من عدم وجود شبكة rabit. يبدو أن نموذجًا تم تدريبه باستخدام Rabit يمكن استخدامه للتنبؤ بالبيانات بدون rabit. يبدو هذا أيضًا أنه سيكون ضروريًا في الإنتاج. هل يمكنك أن تقول المزيد عن قيود استخدام نموذج تدرب على الأرانب هنا؟

مثال على مجموعة البيانات / المشكلة
إذا افترضنا أن كل شيء أعلاه صحيح ، فهل هناك مثال تدريب معياري موزع يستخدمه الناس في العرض التوضيحي؟

سيكون من الرائع إعادة إنتاج نتائج هذه التجربة:

https://github.com/Microsoft/LightGBM/wiki/Experiments#parallel -experiment

مع خيار binning + fast fast الجديد من XGBoost (# 1950) ، يجب أن يكون من الممكن الحصول على نتائج مماثلة.

مثال لعبة نموذجي يمكنك تجربته في https://github.com/dmlc/xgboost/tree/master/demo/data
إنه بتنسيق libsvm رغم ذلك ، ويحتاج إلى القليل من التحليل لتحويله إلى numpy

قد تكون مهتمًا بهذا العلاقات العامة في 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 في عينة صغيرة من مجموعة بيانات شركات الطيران على جهاز الكمبيوتر المحمول المحلي. هل هذا يبدو جيدا للجميع؟ هل هناك عناصر واجهة برمجة تطبيقات لـ 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 سؤال متابعة واحد ، هل تسمح داسك بوظائف متعددة الخيوط؟ أعلم أن هذا ليس وثيق الصلة بـ Python بسبب GIL. ولكن يمكن أن تسمح xgboost بالتدريب متعدد الخيوط لكل عامل مع استمرار التنسيق مع بعضها البعض بشكل موزع. يجب أن نضع دائمًا وسيطات nthread لـ xgboost لتكون عدد النوى العاملة لهذا العامل

الإجابة المختصرة هي "نعم". يتم استخدام Dask في معظم الأحيان مع مشاريع مثل NumPy و Pandas و SKLearn وغيرها والتي تكون في الغالب مجرد كود C و Fortran ، وملفوفة ببايثون. لا يؤثر GIL على هذه المكتبات. بعض الأشخاص يستخدمون Dask لتطبيقات مماثلة لـ PySpark RDD (انظر dask.bag ) وسوف يتأثرون. هذه المجموعة هي في الأقلية بالرغم من ذلك.

لذا نعم ، يسمح Dask بالمهام متعددة الخيوط. كيف يمكننا إخبار XGBoost باستخدام خيوط متعددة؟ في تجاربي حتى الآن ، أرى استخدامًا مرتفعًا لوحدة المعالجة المركزية دون تغيير أي معلمات ، فربما يعمل كل شيء بشكل جيد افتراضيًا؟

يستخدم XGBoost خيوط متعددة بشكل افتراضي ، وسيستخدم جميع خيوط وحدة المعالجة المركزية المتاحة على الجهاز (بدلاً من ذلك العامل) إذا لم يتم تعيين nthread. يمكن أن يؤدي ذلك إلى إنشاء حالة سباق عندما يتم تعيين عدة عمال لنفس الجهاز.

لذلك من الجيد دائمًا تعيين معلمة nthread على الحد الأقصى لعدد النوى المسموح للعامل باستخدامها. عادة ما يتم استخدام الممارسة الجيدة حول 4 خيوط لكل عامل

بالتأكيد ، يجب أن يتم إنجازه في
https://github.com/mrocklin/dask-xgboost/commit/c22d066b67c78710d5ad99b8620edc55182adc8f

يوم الإثنين 20 فبراير 2017 الساعة 6:31 مساءً ، Tianqi Chen [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' في البارامترات.

شكرا @ 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 التقييمات