مقدمة إلى CatBoost. تقرير ياندكس

اسمي ستاس كيريلوف ، أنا مطور رائد في مجموعة ML- منصات في ياندكس. نحن نعمل على تطوير أدوات التعلم الآلي ، ودعم وتطوير البنية التحتية لهم. يوجد أدناه حديثي الأخير حول كيفية عمل مكتبة CatBoost. تحدثت في التقرير عن نقاط الدخول وميزات المدونة لأولئك الذين يريدون فهمها أو أن يصبحوا مساهمين.


- يعيش CatBoost على GitHub بموجب ترخيص Apache 2.0 ، أي أنه مفتوح ومجاني للجميع. يتطور المشروع بنشاط ، والآن يوجد في مستودعنا أكثر من أربعة آلاف نجم. CatBoost مكتوب بلغة C ++ ، وهي مكتبة لزيادة التدرج على أشجار القرار. يدعم عدة أنواع من الأشجار ، بما في ذلك ما يسمى الأشجار "المتماثلة" ، والتي يتم استخدامها في المكتبة بشكل افتراضي.

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



التدرج اللوني هو خوارزمية نبني فيها تنبؤات بسيطة تعمل على تحسين وظائفنا الموضوعية. أي بدلاً من بناء نموذج معقد على الفور ، نقوم ببناء العديد من النماذج الصغيرة بدورها.



كيف هي عملية التعلم في CatBoost؟ سوف أخبرك كيف تعمل من حيث الشفرة. أولاً ، نقوم بتحليل معلمات التدريب التي يمر بها المستخدم ، والتحقق من صحتها ، ومن ثم معرفة ما إذا كنا بحاجة إلى تحميل البيانات. نظرًا لأنه يمكن بالفعل تحميل البيانات - على سبيل المثال ، في Python أو R. التالي ، نقوم بتحميل البيانات وإنشاء شبكة من الحدود لتقدير الميزات العددية. هذا ضروري لجعل التعلم سريعًا.

الميزات الفئوية التي نعالجها بشكل مختلف قليلاً. نقوم بتصنيف الميزات في البداية ، ثم إعادة ترقيم التجزئة من الصفر إلى عدد القيم الفريدة للميزة الفئوية من أجل قراءة مجموعات من الميزات الفئوية بسرعة.

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



تتكون الدورة التدريبية نفسها من أربع نقاط. أولاً ، نحن نحاول بناء شجرة واحدة. ثم ننظر إلى أي نوع من الزيادة أو النقص في الجودة يعطي. ثم نتحقق لمعرفة ما إذا كان كاشف إعادة التدريب قد عمل أم لا. ثم ، إذا كان الوقت مناسبًا ، فقم بحفظ اللقطة.



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

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

ثم نقوم بتجميع المشتقات في رسم بياني ، كما نفعل لكل مرشح مقسم. باستخدام الرسوم البيانية ، نحاول تقييم التغير في الوظيفة الهدف الذي سيحدث إذا اخترنا مرشح الانقسام هذا.

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



من الصعب للغاية تحديد مكان واحد يتم فيه التدريب ، لذلك في هذه الشريحة - يمكنك استخدامها كنقطة دخول - يتم سرد الملفات الرئيسية التي نستخدمها للتدريب. هذا هو greedy_tensor_search ، الذي نعيش فيه الإجراء نفسه لاختيار الجشع من الانقسامات. هذا هو train.cpp ، حيث لدينا المصنع الرئيسي لتدريب وحدة المعالجة المركزية. هذا aprox_calcer ، حيث تكمن وظائف تحديث القيم في الأوراق. وكذلك score_calcer - وظيفة لتقييم بعض المرشحين.

أجزاء مهمة على قدم المساواة هي catboost.pyx و core.py. هذا هو رمز المجمع بيثون ، على الأرجح العديد منكم سوف تدرج نوعا من الاشياء في المجمع بيثون. مكتوب برنامج python wrapper مكتوب بلغة Cython ، تتم ترجمة Cython بلغة C ++ ، لذلك يجب أن يكون هذا الرمز سريعًا.

يوجد برنامج R-wrapper في مجلد R-package. ربما يتعين على شخص ما إضافة بعض الخيارات أو إصلاحها ، ولخيارات لدينا مكتبة منفصلة - catboost / libs / options.

لقد جئنا من Arcadia إلى GitHub ، لذلك لدينا العديد من القطع الأثرية المثيرة للاهتمام التي ستواجهها.





لنبدأ بهيكل المستودع. لدينا مجلد استخدام حيث البدائية الأساسية هي: المتجهات ، والخرائط ، وأنظمة الملفات ، والعمل مع السلاسل ، والتدفقات.

لدينا مكتبة توجد بها المكتبات المشتركة التي تستخدمها ياندكس - كثير ، وليس فقط CatBoost.

يعد مجلد CatBoost and المساهمة رمزًا لمكتبات الجهات الخارجية التي نرتبط بها.

دعنا نتحدث الآن عن بدائل C ++ التي ستواجهها. الأول هو المؤشرات الذكية. في Yandex ، استخدمنا THolder منذ std :: unique_ptr ، ويستخدم MakeHolder بدلاً من std :: make_unique.



لدينا SharedPtr الخاصة بنا. علاوة على ذلك ، يوجد في شكلين ، SimpleSharedPtr و AtomicSharedPtr ، والتي تختلف في نوع العداد. في حالة واحدة ، يكون ذريًا ، مما يعني أنه كما لو أن عدة تدفقات يمكنها امتلاك كائن. لذلك سيكون في مأمن من وجهة نظر التحويل بين التدفقات.

فئة منفصلة ، IntrusivePtr ، تتيح لك امتلاك الكائنات الموروثة من فئة TRefCounted ، أي الفئات التي تحتوي على عداد مرجعي مضمن. هذا هو لتخصيص مثل هذه الكائنات في وقت واحد ، دون تخصيص كتلة التحكم مع عداد.

لدينا أيضا نظامنا الخاص للإدخال والإخراج. IInputStream و IOutputStream واجهات للإدخال والإخراج. لديهم طرق مفيدة ، مثل ReadTo و ReadLine و ReadAll ، بشكل عام ، كل ما يمكن توقعه من InputStreams. ولدينا تطبيقات من هذه التدفقات للعمل مع وحدة التحكم: Cin ، Cout ، Cerr و Endl بشكل منفصل ، وهو مشابه لـ std :: endl ، أي أنه يعمل على مسح الدفق.



لدينا أيضًا تطبيقات واجهة خاصة بنا للملفات: TInputFile ، TOutputFile. هذه قراءة مخزنة. أنها تنفذ القراءة المخزنة مؤقتًا والكتابة المخزنة مؤقتًا إلى ملف ، بحيث يمكنك استخدامها.

يستخدم Util / system / fs.h أساليب NFs :: Exists و NFs :: Copy ، إذا كنت بحاجة فجأة إلى نسخ شيء ما أو التحقق من وجود بعض الملفات بالفعل.



لدينا حاويات الخاصة بنا. لقد انتقلوا إلى استخدام std :: vector منذ فترة طويلة ، أي أنهم يرثون ببساطة من std :: vector ، std :: set و std :: map ، ولكن لدينا أيضًا THashMap و THashSet ، التي لها واجهات متوافقة جزئيًا مع unordered_map و unordered_set. لكن بالنسبة لبعض المهام ، تبين أنها أسرع ، لذلك لا نزال نستخدمها.



مراجع الصفيف هي مماثلة للأمراض المنقولة جنسياً :: span من C ++. صحيح ، لم يظهر معنا في السنة العشرين ، ولكن قبل ذلك بكثير. نحن نستخدمها بنشاط لنقل الإشارات إلى المصفوفات ، كما لو تم تخصيصها على مخازن مؤقتة كبيرة ، حتى لا يتم تخصيص مخازن مؤقتة في كل مرة. لنفترض أنه ، لحساب عدد المشتقات أو بعض التقديرات ، يمكننا تخصيص ذاكرة في بعض المخازن المؤقتة الكبيرة المخصصة مسبقًا وتمرير TArrayRef فقط إلى وظيفة العد. انها مريحة جدا ، ونحن نستخدمها كثيرا.



يستخدم Arcadia مجموعة الطبقات الخاصة به للعمل مع الأوتار. هذا ، أولاً ، TStingBuf - تناظرية str :: string_view من C ++ 17.

TString ليست على الإطلاق std :: sting ، بل هي سلسلة CopyOnWrite ، لذلك تحتاج إلى العمل معها بعناية فائقة. بالإضافة إلى ذلك ، TUtf16String هو نفس TString ، فقط نوعه الأساسي ليس char ، ولكن 16 بت wchar.

ولدينا أدوات لتحويل من سلسلة إلى سلسلة. هذا هو ToString ، وهو تناظرية std :: to_string و FromString يقترن TryFromString ، والذي يسمح لك بتحويل السلسلة إلى النوع الذي تحتاجه.



لدينا بنية الاستثناء الخاصة بنا ، والاستثناء الأساسي في مكتبات الممرات هو yexception ، والذي يرث من الأمراض المنقولة جنسياً :: استثناء. لدينا ماكرو ythrow يضيف معلومات حول المكان الذي تم طرح الاستثناء فيه على yexception ، إنه مجرد غلاف مناسب.

يوجد تماثل بين std :: current_exception - CurrentExceptionMessage ، هذه الدالة يطرح الاستثناء الحالي كسلسلة.

هناك وحدات ماكرو للتأكيدات والتحقق - هذه هي Y_ASSERT و Y_VERIFY.



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

لقد حدث أن لدينا نسختين من التسلسل في CatBoost. يعمل الخيار الأول من خلال أساليب الواجهة "حفظ وتحميل" ، والتي تتسلسل إلى الدفق. يتم استخدام خيار آخر في التدريب الموزع الخاص بنا ، فهو يستخدم مكتبة BinSaver داخلية قديمة إلى حد ما ، وهو مناسب لتسلسل الكائنات المتعددة الأشكال التي يجب تسجيلها في مصنع خاص. هذا ضروري للتدريب الموزع ، الذي من غير المرجح أن يكون لدينا وقت للحديث عنه هنا.



لدينا أيضًا تعزيزنا التماثلي أو std :: اختياري - TMaybe. تناظرية الأمراض المنقولة جنسيا :: البديل - TVariant. تحتاج إلى استخدامها.



هناك اصطلاح معيّن أننا داخل كود CatBoost نلقي TCatBoostException بدلاً من yexception. هذا هو نفس yexception ، يتم دائمًا إضافة تتبع المكدس فقط عند طرحه.

ونستخدم أيضًا الماكرو CB_ENSURE للتحقق من بعض الأشياء بشكل مريح ورمي استثناءات إذا لم يتم تنفيذها. على سبيل المثال ، نستخدم هذا غالبًا لتحليل الخيارات أو تحليل المعلمات التي يجتازها المستخدم.


روابط من الشريحة: الأولى والثانية

قبل أن تبدأ ، نوصيك بأن تتعرف على نمط الشفرة ، فهي تتكون من جزأين. الأول هو نمط تعليمات برمجية للأركيد العام ، والذي يقع مباشرة في جذر المستودع في ملف CPP_STYLE_GUIDE.md. يوجد أيضًا في جذر المستودع دليل منفصل لفريقنا: catboost_command_style_guide_extension.md.

نحن نحاول تنسيق كود Python باستخدام PEP8. لا يعمل هذا دائمًا ، نظرًا لرمز Cython ، لا يعمل نظام linter بالنسبة لنا ، وأحيانًا يحدث شيء ما مع PEP8.



ما هي ملامح التجمع لدينا؟ تهدف مجموعة Arcadia في الأصل إلى جمع معظم تطبيقات محكمة الإغلاق ، أي أنه سيكون هناك حد أدنى من التبعيات الخارجية بسبب الربط الثابت. هذا يسمح لك باستخدام نفس ثنائي على إصدارات مختلفة من لينكس دون إعادة تجميع ، وهو مناسب للغاية. أهداف التجميع موصوفة في ملفات ya.make. مثال على ya.make يمكن رؤيته على الشريحة التالية.



إذا أردت فجأة إضافة نوع من المكتبة أو البرنامج أو أي شيء آخر ، فيمكنك أولاً ، مجرد إلقاء نظرة على ملفات ya.make المجاورة ، وثانياً ، استخدام هذا المثال. هنا قمنا بإدراج أهم عناصر ya.make. في بداية الملف ، نقول إننا نريد أن نعلن عن مكتبة ، ثم نقوم بإدراج وحدات الترجمة التي نود وضعها في هذه المكتبة. هنا يمكن أن يكون كل من ملفات cpp ، على سبيل المثال ، ملفات pyx التي سيبدأ Cython تلقائيًا بها ، ثم المحول البرمجي. يتم سرد تبعيات المكتبة من خلال الماكرو PEERDIR. إنه ببساطة يكتب المسارات إلى المجلد مع المكتبة أو مع قطعة أثرية أخرى في الداخل ، بالنسبة لجذر المستودع.

يوجد شيء مفيد ، GENERATE_ENUM_SERIALIZATION ، مطلوب لإنشاء طرق ToString و FromString لفئات التعداد والتعدادات الموضحة في بعض ملفات الرأس التي تمر بها إلى هذا الماكرو.



الآن عن أهم شيء - كيفية تجميع وتشغيل نوع من الاختبار. في جذر المستودع يوجد البرنامج النصي ya ، الذي يقوم بتنزيل مجموعة الأدوات والأدوات اللازمة ، ويحتوي على الأمر ya make - الأمر الفرعي make - الذي يسمح لك بإنشاء إصدار -r باستخدام مفتاح التبديل -r وإصدار تصحيح الأخطاء باستخدام مفتاح التبديل -d. يتم تمرير القطع الأثرية الموجودة فيه وفصلها بمسافة.

لبناء بيثون ، أشرت على الفور إلى أعلام هنا قد تكون مفيدة. نحن نتحدث عن إنشاء نظام Python ، في هذه الحالة مع Python 3. إذا كان لديك فجأة مجموعة أدوات CUDA مثبتة على جهاز الكمبيوتر المحمول أو آلة التطوير الخاصة بك ، ثم للتجميع بشكل أسرع ، نوصي بتحديد –d have_cuda no flag. CUDA يبني لبعض الوقت ، وخاصة على أنظمة 4 النواة.



يا ide يجب أن تعمل بالفعل. هذه هي الأداة التي سوف تولد حل clion أو كيو تي بالنسبة لك. بالنسبة لأولئك الذين جاءوا مع Windows ، لدينا حل Microsoft Visual Studio ، والذي يوجد في مجلد msvs.

المستمع:
- هل لديك كل الاختبارات من خلال بيثون المجمع؟

ستاس:
- لا ، لدينا اختبارات منفصلة في مجلد pytest. هذه اختبارات لواجهة CLI لدينا ، أي تطبيقنا. صحيح ، أنها تعمل من خلال pytest ، أي أن هذه هي وظائف Python التي نقوم بإجراء مكالمة تحقق من عملية فرعية والتحقق من أن البرنامج لا يتعطل ويعمل بشكل صحيح مع بعض المعلمات.

المستمع:
- ماذا عن اختبارات الوحدة في C ++؟

ستاس:
- لدينا أيضا اختبارات وحدة في C ++. عادة ما تقع في مجلد lib في المجلدات الفرعية ut. وهي مكتوبة على هذا النحو - اختبار وحدة أو اختبار وحدة ل. هناك أمثلة. هناك وحدات ماكرو خاصة لإعلان فئة اختبار الوحدة ، وسجلات منفصلة لوظيفة اختبار الوحدة.

المستمع:
- للتحقق من أنه لم ينكسر أي شيء ، هل من الأفضل إطلاق كل من هؤلاء وأولئك؟

ستاس:
- نعم. الشيء الوحيد هو أن اختباراتنا مفتوحة المصدر خضراء فقط على نظام Linux. لذلك ، إذا قمت بترجمة ، على سبيل المثال ، تحت Mac ، إذا فشلت خمسة اختبارات ، فلا يوجد ما يدعو للقلق. بسبب اختلاف تطبيق العارضين على منصات مختلفة أو بعض الاختلافات الطفيفة الأخرى ، يمكن أن تكون النتائج مختلفة للغاية.



على سبيل المثال سنتخذ مهمة. أود أن أوضح بعض الأمثلة. لدينا ملف به مهام - open_problems.md. دعنا نحل المشكلة from4 من open_problems.md. يتم صياغته على النحو التالي: إذا قام المستخدم بتعيين معدل التعلم إلى صفر ، فيجب أن نسقط من TCatBoostException. تحتاج إلى إضافة خيارات التحقق من الصحة.



أولاً ، نحتاج إلى إنشاء فرع ، واستنساخ مفترق ، أصل استنساخ ، أصل أصل ، تشغيل الأصل في مفترقنا ثم إنشاء فرع والبدء في العمل فيه.

كيف تعمل خيارات التحليل؟ كما قلت ، لدينا مجلد catboost / libs / options مهم حيث يتم تخزين تحليل جميع الخيارات.



لدينا جميع الخيارات المخزنة في برنامج الالتفاف ، والذي يسمح لنا بفهم ما إذا كان المستخدم قد تم تجاوزه. إذا لم يكن الأمر كذلك ، فسيحتفظ ببعض القيمة الافتراضية في حد ذاته. بشكل عام ، يوزع CatBoost جميع الخيارات في شكل قاموس JSON كبير ، والذي يتحول أثناء التحليل إلى قواميس متداخلة وهياكل متداخلة.



اكتشفنا بطريقة ما - على سبيل المثال ، من خلال البحث باستخدام grep أو قراءة الكود - أن لدينا معدل التعلم في TBoostingOptions. دعونا نحاول كتابة التعليمات البرمجية التي تضيف ببساطة CB_ENSURE ، وأن معدل التعلم لدينا هو أكثر من مجرد std :: numeric_limits :: epsilon ، والذي أدخله المستخدم بشيء معقول أو أكثر.



هنا استخدمنا فقط الماكرو CB_ENSURE ، وكتبنا بعض الرموز والآن نريد إضافة اختبارات.



في هذه الحالة ، نضيف اختبارًا على واجهة سطر الأوامر. في مجلد pytest ، لدينا البرنامج النصي test.py ، حيث توجد بالفعل أمثلة قليلة للاختبار ويمكنك فقط اختيار مثال يشبه مهمتك ، ونسخه وتغيير المعلمات بحيث يبدأ في الانخفاض أو لا يقع ، وفقًا للمعلمات التي مرت بها. في هذه الحالة ، نأخذ وننشئ مجموعة بسيطة من سطرين. (نحن نسمي تجمعات البيانات في ياندكس. هذا هو خاصيتنا.) ومن ثم نتحقق من أن ثنائينا ينخفض ​​حقًا إذا تجاوزنا معدل التعلم 0.0.



نضيف أيضًا اختبارًا لحزمة python ، التي توجد في atBoost / python-package / ut / medium. لدينا أيضًا اختبارات كبيرة وكبيرة مرتبطة باختبارات بناء حزم عجلات بيثون.



وعلاوة على ذلك لدينا مفاتيح ليا جعل - تي و-. -t يجري الاختبارات ، -A يفرض جميع الاختبارات لتشغيل بغض النظر عما إذا كان لديهم علامات كبيرة أو متوسطة.

هنا ، للجمال ، وأنا أيضا استخدام مرشح اسمه الاختبار. يتم تعيينه باستخدام الخيار -F واسم الاختبار المحدد لاحقًا ، والذي قد يكون نجوم char البرية. في هذه الحالة ، استخدمت test.py::test_zero_learning_rate* ، لأنه بالنظر إلى اختبارات حزمة python الخاصة بنا ، سترى: تقريبًا ، تأخذ جميع الوظائف في تركيبات نوع المهمة. هذا هو أنه وفقًا للرمز ، تبدو اختبارات بيثون-الحزمة الخاصة بنا متشابهة بالنسبة لكل من وحدة المعالجة المركزية وتعلم وحدة معالجة الرسومات ويمكن استخدامها لاختبارات مدرب وحدة معالجة الرسومات.





ثم ارتكب تغييراتنا وادفعها إلى مستودعنا المتشعب. ننشر طلب التجمع. لقد انضم بالفعل ، كل شيء على ما يرام.

Source: https://habr.com/ru/post/ar458790/


All Articles