Evalml: أداء الفرقة المكدسة ضعيف

تم إنشاؤها على ٦ أبريل ٢٠٢١  ·  11تعليقات  ·  مصدر: alteryx/evalml

خطوات التكاثر:

  1. تحميل مجموعة بيانات السعادة في Evalml
  2. تشغيل طويل بما يكفي لتضمين التجميع
  3. يظهر معامل الارتداد الأساسي في مرتبة أعلى من الانحدار المكدس.
    مجموعة بيانات السعادة الكاملة. csv.zip
bug performance

ال 11 كومينتر

dancuarini حاولت إعادة إنتاج هذا محليًا لكن لم أتمكن من ذلك ؛ يمكن أن يكون بسبب خطوات إضافية قبل تشغيل AutoMLSearch (على سبيل المثال: حجم تقسيم البيانات ، وإفلات الأعمدة). دعنا نتحدث عن تكوين المشكلة!

هذا ما حاولت تشغيله محليًا:

from evalml.automl import AutoMLSearch
import pandas as pd
import woodwork as ww
from evalml.automl.callbacks import raise_error_callback

happiness_data_set = pd.read_csv("Happiness Data Full Set.csv")
y = happiness_data_set['Happiness']
X = happiness_data_set.drop(['Happiness'], axis=1)
# display(X.head())

X = ww.DataTable(X)
X_train, X_holdout, y_train, y_holdout = evalml.preprocessing.split_data(X, y, problem_type='regression', test_size=0.2, random_seed=0)
# print(X.types)

automl = AutoMLSearch(X, y, problem_type="regression", objective="MAE", error_callback=raise_error_callback, max_batches=20, ensembling=True)
automl.search()

ينتج عن هذا الترتيب التالي:

image

التقدم الحالي: تمت مناقشته مع dancuarini حول عدم القدرة على إعادة النسخ محليًا ، وسوف يظل على اتصال مع Cmancuso حول

@ angela97lin انتظر ، هل أنت متأكد من أنك لا تستطيع التراجع عن هذا؟ هنا تظهر الفرقة المكدسة في منتصف الترتيب - أتوقع أن تكون في القمة!

شكرا لتقاسم الناسخ :)

dsherry في حين أنه من المريب بعض الشيء أن المجموعة المكدسة ليست في القمة ، كانت المشكلة الأصلية هي أن أداء المجموعة المكدسة كان ضعيفًا لدرجة أنه تم تصنيفه أعلى من الانحدار الأساسي!

@ angela97lin آه نعم فهمت! لقد أرسلت لك بعض الملاحظات.

أعتقد أن أي دليل على أن فرقنا ليست دائمًا قريبة من القمة يمثل مشكلة.

حفر في هذا أكثر قليلا. أعتقد أن هناك بعض الأسباب المحتملة لسوء أداء المُجمع مع مجموعة البيانات هذه:

  1. مجموعة البيانات صغيرة حقًا ، وتعني إستراتيجيتنا الحالية لتقسيم البيانات أنه يتم تزويد المجمع بمجموعة فرعية صغيرة جدًا من البيانات والتحقق من صحتها. في الوقت الحالي ، إذا أردنا تدريب مجموعة مكدسة ، فسنقسم بعض البيانات (المحددة بـ ensembling_indices ) لكي يتدرب المجمع عليها. هذا لمنع فرط تجهيز المجموعة من خلال تدريب المتعلم على نفس البيانات التي تم تدريب خطوط الإدخال عليها بالفعل. نقوم بعد ذلك بتقسيم سيرة ذاتية واحدة ، مع تقسيم البيانات أكثر من ensembling_indices . بالنسبة لمجموعة البيانات هذه المكونة من 128 صفًا ، نقوم بالتدريب والتحقق من صحة 17 و 8 صفوف ، على التوالي. لقد قدمت رقم 2144 لمناقشة ما إذا كنا نريد إجراء تقسيم إضافي للسيرة الذاتية.

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

على سبيل المثال ، هذا هو جدول الترتيب النهائي:
image

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

هذا هو رمز repro لهذا:

من اعلى:

import pandas as pd
import woodwork as ww
happiness_data_set = pd.read_csv("Happiness Data Full Set.csv")
y = happiness_data_set['Happiness']
X = happiness_data_set.drop(['Happiness'], axis=1)

X = ww.DataTable(X)
X_train, X_holdout, y_train, y_holdout = evalml.preprocessing.split_data(X, y, problem_type='regression', test_size=0.25, random_seed=0)

automl = AutoMLSearch(X, y, problem_type="regression", objective="MAE", error_callback=raise_error_callback, max_batches=10, ensembling=True)
automl.search()

import woodwork as ww
from evalml.automl.engine import train_and_score_pipeline
from evalml.automl.engine.engine_base import JobLogger

# Get the pipelines fed into the ensemble but only use the ones better than the stacked ensemble
input_pipelines = []
input_info = automl._automl_algorithm._best_pipeline_info
from evalml.model_family import ModelFamily

trimmed = dict()
trimmed.update({ModelFamily.RANDOM_FOREST: input_info[ModelFamily.RANDOM_FOREST]})
trimmed.update({ModelFamily.XGBOOST: input_info[ModelFamily.XGBOOST]})
trimmed.update({ModelFamily.DECISION_TREE: input_info[ModelFamily.EXTRA_TREES]})

for pipeline_dict in trimmed.values():
    pipeline_class = pipeline_dict['pipeline_class']
    pipeline_params = pipeline_dict['parameters']
    input_pipelines.append(pipeline_class(parameters=automl._automl_algorithm._transform_parameters(pipeline_class, pipeline_params),
                                                      random_seed=automl._automl_algorithm.random_seed))
ensemble_pipeline = _make_stacked_ensemble_pipeline(input_pipelines, "regression")
X_train = X.iloc[automl.ensembling_indices]
y_train = ww.DataColumn(y.iloc[automl.ensembling_indices])
train_and_score_pipeline(ensemble_pipeline, automl.automl_config, X_train, y_train, JobLogger())

بمجرد استخدام هذه العائلات النموذجية الثلاثة ، نحصل على درجة MAE تبلغ ~ 0.22 ، وهي أفضل بكثير من أي خط أنابيب فردي.

#output of train_and_score_pipeline(ensemble_pipeline, automl.automl_config, X_train, y_train, JobLogger())
{'scores': {'cv_data': [{'all_objective_scores': OrderedDict([('MAE',
                  0.22281276417465426),
                 ('ExpVariance', 0.9578811127332543),
                 ('MaxError', 0.3858477236606914),
                 ('MedianAE', 0.2790362808260225),
                 ('MSE', 0.0642654425375983),
                 ('R2', 0.9152119239698017),
                 ('Root Mean Squared Error', 0.2535062968401343),
                 ('# Training', 17),
                 ('# Validation', 9)]),
    'mean_cv_score': 0.22281276417465426,
    'binary_classification_threshold': None}],
  'training_time': 9.944366216659546,
  'cv_scores': 0    0.222813
  dtype: float64,
  'cv_score_mean': 0.22281276417465426},
 'pipeline': TemplatedPipeline(parameters={'Stacked Ensemble Regressor':{'input_pipelines': [GeneratedPipeline(parameters={'Imputer':{'categorical_impute_strategy': 'most_frequent', 'numeric_impute_strategy': 'most_frequent', 'categorical_fill_value': None, 'numeric_fill_value': None}, 'One Hot Encoder':{'top_n': 10, 'features_to_encode': None, 'categories': None, 'drop': 'if_binary', 'handle_unknown': 'ignore', 'handle_missing': 'error'}, 'Random Forest Regressor':{'n_estimators': 184, 'max_depth': 25, 'n_jobs': -1},}), GeneratedPipeline(parameters={'Imputer':{'categorical_impute_strategy': 'most_frequent', 'numeric_impute_strategy': 'mean', 'categorical_fill_value': None, 'numeric_fill_value': None}, 'One Hot Encoder':{'top_n': 10, 'features_to_encode': None, 'categories': None, 'drop': 'if_binary', 'handle_unknown': 'ignore', 'handle_missing': 'error'}, 'XGBoost Regressor':{'eta': 0.1, 'max_depth': 6, 'min_child_weight': 1, 'n_estimators': 100},}), GeneratedPipeline(parameters={'Imputer':{'categorical_impute_strategy': 'most_frequent', 'numeric_impute_strategy': 'mean', 'categorical_fill_value': None, 'numeric_fill_value': None}, 'One Hot Encoder':{'top_n': 10, 'features_to_encode': None, 'categories': None, 'drop': 'if_binary', 'handle_unknown': 'ignore', 'handle_missing': 'error'}, 'Extra Trees Regressor':{'n_estimators': 100, 'max_features': 'auto', 'max_depth': 6, 'min_samples_split': 2, 'min_weight_fraction_leaf': 0.0, 'n_jobs': -1},})], 'final_estimator': None, 'cv': None, 'n_jobs': -1},}),

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

  1. المتعلم المعدني الذي نستخدمه (LinearRegressor) ليس هو الأفضل. لقد اختبرت ذلك عبر الفرع stacking_test الذي أنشأته حيث قمت بتحديث المعادن الافتراضية إلى RidgeCV (scikit-learn default ، لكن ليس لدينا في EvalML) ، وأداء المجمع أفضل بكثير:
    image

الخطوات التالية بعد المناقشة مع dsherry :

جرب # 1 و # 3 (باستخدام Elastic Net) على مجموعات البيانات الأخرى ، وقم بإجراء اختبارات الأداء ، ومعرفة ما إذا كان بإمكاننا الحصول على أداء أفضل بشكل عام.

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

أوافق أيضًا على أن متعلم المعادن يحتاج إلى استخدام تنظيم قوي. لقد استخدمت Elastic Net في H2O-3 StackedEnsemble ، وتذكر مرة واحدة فقط أن المجموعة جاءت في المرتبة الثانية في لوحة الصدارة. في كل مرة اختبرت ، كانت الأولى. يجب ألا يسمح التنظيم أبدًا للنماذج الرديئة بتقليل أداء المجموعة.

وقد أدى ذلك إلى تغذية لوحة المتصدرين بالكامل حتى من 50 نموذجًا في المتعلم المعدني. :-)

ما عليك سوى نشر بعض التحديثات الإضافية على هذا:

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

من هذا:

  • موافقrpeck! يجب أن نقوم بتحديث المتعلم المعدني لاستخدام تنظيم قوي بالتأكيد. يبدو أن أداء ElasticNetCV أفضل من LinearRegressor الخاص بنا في العديد من مجموعات البيانات. تتعقب هذه المشكلة: https://github.com/alteryx/evalml/issues/1739
  • dsherry وأنا أعدنا مناقشة إستراتيجيتنا لتقسيم البيانات: في الوقت الحالي ، قمنا بتقسيم البيانات للمجموعة. ومع ذلك ، هذا على أساس الافتراض بأننا نريد تدريب المتعلم على مؤشرات هذه المجموعة. من خلال تطبيق scikit-Learn ، عندما نقوم بتدريب StackedEnsembler على تقسيم مؤشرات المجموعة هذه ، ينتهي بنا الأمر بتدريب كل من خطوط أنابيب الإدخال والمتعلم على هذه المجموعة الصغيرة من البيانات. قد يكون هذا على الأرجح سبب عدم أداءنا بشكل جيد. في حين أن المعلمات الخاصة بخطوط أنابيب الإدخال لدينا من الضبط باستخدام البيانات الأخرى ، لم يتم تركيب خطوط الأنابيب هذه. على المدى الطويل ، قد يسمح لنا تنفيذ التنفيذ الخاص بنا بالمرور في خطوط الأنابيب المدربة إلى المجموعة ، وفي هذه الحالة سيكون لدينا السلوك الذي نريده. في الوقت الحالي ، ليس هذا هو الحال.

الخطوة التالية: اختبر هذه الفرضية باستخدام أداة التجميع يدويًا. حاول تدريب خطوط أنابيب الإدخال يدويًا على 80٪ من البيانات ، وإنشاء تنبؤات تم التحقق من صحتها على البيانات الموضوعة جانبًا لتجميع المعادن وتدريبها باستخدام تنبؤات خارجية.

نتائج التجربة تبدو جيدة: https://alteryx.quip.com/4hEyAaTBZDap/Ensembling-Performance-Using-More

الخطوات التالية:

بعد بعض البحث ، نعتقد أن المشكلة لا تتعلق بكيفية أداء المجموعة ، بل تتعلق بكيفية الإبلاغ عن أداء المجموعة. حاليًا ، نقوم بتقسيم مجموعة منفصل يمثل 20٪ من البيانات ، ثم نقوم بتقسيم آخر للتحقق من صحة التدريب ، ونبلغ درجة المجموعة على أنها بيانات التحقق من الصحة. هذا يعني أنه في بعض الحالات ، يتم حساب درجة المجموعة باستخدام عدد صغير جدًا من الصفوف (مثل مجموعة بيانات السعادة أعلاه).

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

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

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

النتائج مجدولة هنا: https://alteryx.quip.com/jI2mArnWZfTU/Ensembling-vs-Best-Pipeline-Validation-Scores#MKWACADlCDt

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات