در این نوشته به تعریف هایپرپارامتر، تفاوت آن با پارامترهای الگوریتم و چگونگی تنظیم هایپرپارامترها می پردازیم که یکی از وظایف چالش برانگیز در آموزش مدل های یادگیری ماشین است. به طور کلی سه راه برای بهبود مدل های یادگیری ماشین وجود دارد:
در ادامه به بررسی بیشتر سومین مورد یعنی تنظیم هایپرپارامترهای الگوریتم و راهکاری برای رسیدن به مقدار مناسبی (نه بهترین مقدار) برای آن می پردازیم.
پارامترهای مدل، ویژگی هایی از داده آموزشی هستند که در طول آموزش توسط الگوریتم های یادگیری ماشین، یادگرفته می شوند، مانند شیب و عرض از مبدا در رگرسیون خطی. پارامترهای مدل در هر آزمایشی متفاوت هستند و بستگی به داده ها و نوع مسئله دارند. در حالی که، هایپرپارامترها باید توسط دانشمند داده، قبل از آموزش، مشخص می شوند. برای مثال تعداد و اندازه لایه های مخفی در شبکه عصبی، هایپرپارامتر هستند. در الگوریتم جنگل تصادفی (Random Forest)، هایپرپارامتر تعداد درختان تصمیم در جنگل است. اما پارامترهای الگوریتم جنگل تصادفی، متغیرها و حد آستانه هایی(thresholds) هستند که برای تقسیم هر گره که در هنگام آموزش، یاد گرفته می شوند.
کتابخانه Scikit-Learnپایتون (و یا موارد مشابه در نرم افزارهای دیگر) هایپرپارامترهای پیش فرضی برای هر مدل در نظر گرفته اند اما معمولا این مقادیر، برای مسئله مورد نظر ما بهینه نیستند. تعیین بهترین هایپرپارامترها معمولا کار غیر ممکنی است ولی با تجربه و خطا می توان به مقادیر مناسبی دست یافت. برای این منظور، نیاز به نتایج تجربی داریم و باید تعداد زیادی از ترکیبات هایپرپارامترها را مورد آزمون قرار دهیم و کارایی هر مدل به دست آمده را ارزیابی کنیم.
معمولا ایده مبهمی در مورد تنظیم هایپرپارامترها داریم. بهترین روش برای محدود کردن مقادیر هایپرپارامترها در مسئله، آزمایش و ارزیابی تعداد زیادی از مقادیر برای هر هایپرپارامتر است. با استفاده از متد RandomizedSearchCV کتابخانه Scikit-Learnپایتون، می توان شبکه ایی (grid) از بازه های از مقادیر هایپرپارامترها را تعریف کرد و به صورت تصادفی نمونه هایی از مقادیر این شبکه را انتخاب کرد و مورد ارزیابی قرار داد.
در ادامه مثالی از تنظیم مقادیر هایپرپارامتر در الگوریتم جنگل تصادفی را بررسی می کنیم. برای مشاهده هایپر پارامترهای پیش فرض، یک درخت تصادفی را ایجاد و مقادیر پیش فرض را با دستورات زیر مشاهده می کنیم.
from sklearn.ensemble import RandomForestRegressor
rf = RandomForestRegressor(random_state = 42)
from pprint import pprint
# Look at parameters used by our current forest print('Parameters currently in use:\n') pprint(rf.get_params())
Parameters currently in use: {'bootstrap': True, 'criterion': 'mse', 'max_depth': None, 'max_features': 'auto', 'max_leaf_nodes': None, 'min_impurity_decrease': 0.0, 'min_impurity_split': None, 'min_samples_leaf': 1, 'min_samples_split': 2, 'min_weight_fraction_leaf': 0.0, 'n_estimators': 10, 'n_jobs': 1, 'oob_score': False, 'random_state': 42, 'verbose': 0, 'warm_start': False}
همانطور که مشاهده می کنید لیستی طولانی از هایپرپارامترها نشان داده شده است. بهتر است بازه هایی از مقادیر را برای هر هایپرپارامتر امتحان و نتایج را بررسی کنیم. برای استفاده از RandomizedSearchCV نیاز به ایجاد شبکه ایی از هایپرپارامترها داریم تا در مرحله آموزش، نمونه هایی از آن را امتحان کنیم. در کد زیر مجموعه ایی از مقادیر برای هر یک از هایپرپارامترها الگوریتم جنگل تصادفی انتخاب شده است.
from sklearn.model_selection import RandomizedSearchCV
# Number of trees in random forest n_estimators = [int(x) for x in np.linspace(start = 200, stop = 2000, num = 10)] # Number of features to consider at every split max_features = ['auto', 'sqrt'] # Maximum number of levels in tree max_depth = [int(x) for x in np.linspace(10, 110, num = 11)] max_depth.append(None) # Minimum number of samples required to split a node min_samples_split = [2, 5, 10] # Minimum number of samples required at each leaf node min_samples_leaf = [1, 2, 4] # Method of selecting samples for training each tree bootstrap = [True, False]# Create the random grid random_grid = {'n_estimators': n_estimators, 'max_features': max_features, 'max_depth': max_depth, 'min_samples_split': min_samples_split, 'min_samples_leaf': min_samples_leaf, 'bootstrap': bootstrap} pprint(random_grid)
در هر تکرار الگوریتم، ترکیب متفاوتی از ویژگی ها انتخاب می شود و در مورد کد بالا دارای 2*12*2*3*3*10=4320 حالت مختلف برای تنظیم هایپرپارامترها هستیم. اما مزیت RandomedSearchCV این است که همه ترکیبات موجود را مورد امتحان قرار نمی دهد، بلکه به صورت تصادفی نمونه هایی از مقادیر انتخاب می کند. در ادامه برای آموزش جستجوی تصادفی، نمونه ایی از RandomedSearchCV ایجاد می کنیم و آن را مانند هر مدل دیگری آموزش می دهیم:
# Use the random grid to search for best hyperparameters # First create the base model to tune rf = RandomForestRegressor() # Random search of parameters, using 3 fold cross validation, # search across 100 different combinations, and use all available cores rf_random = RandomizedSearchCV(estimator = rf, param_distributions = random_grid, n_iter = 100, cv = 3, verbose=2, random_state=42, n_jobs = -1)
# Fit the random search model rf_random.fit(train_features, train_labels)
در RandomizedSearchCV مهمترین آرگومان، n_iter است و برای کنترل تعداد ترکیبات متفاوتی که مورد آزمون قرار می گیرند، استفاده می شود (در اینجا مقدار 100 گرفته است). همچنین آرگومان cv برای مشخص کردن تعداد دسته هایی (folds) است که در اعتبار سنجی متقاطع (cross validation) مورد استفاده قرار می گیرد (در اینجا cv=3 است). تکرارهای بیشتر (n_iter بزرگتر) حالت های بیشتری از هایپرپارامترها را پوشش می دهد و همچنین تعداد دسته های بیشتر (cvبزرگتر)، در اعتبارسنجی متقاطع احتمال بیش برازش (overfitting) را کاهش می دهد، اما افزایش هر کدام از آنها زمان اجرا را افزایش می دهد. در یادگیری ماشین باید توازن برقرار باشد و توازن میان زمان و کارایی یکی از اصول مهم است.
با دستور زیر می توان بهترین هایپرپارامترهای بعد از آموزش جستجوی تصادفی را مشاهده کرد. با توجه به نتایج به دست آمده می توان بازه دقیق تری برای هر یک از هایپرپارامترها مشخص کرد.
rf_random.best_params_
{'bootstrap': True, 'max_depth': 70, 'max_features': 'auto', 'min_samples_leaf': 4, 'min_samples_split': 10, 'n_estimators': 400}
همانطور که اشاره شد، جستجوی تصادفی امکان دستیابی به بازه کوچکتری از مقادیر هایپرپارامتر را فراهم می کند و فضای جستجوی ما را کوچکتر می سازد. اکنون می دانیم جستجوی خود را در کجا متمرکز کنیم و می توان ترکیبی از تنظیمات مناسب را امتحان کرد. این کار را با متد GridSearchCV انجام می دهیم که به جای نمونه برداری تصادفی، همه ترکیبات مورد ارزیابی قرار می گیرد. در شکل بالا تفاوت بین جستجوی تصادفی و جستجوی گرید را مشاهده می کنید. برای استفاده از Grid Search، بر اساس بهترین مقادیر ارائه شده توسط جستجوی تصادفی، شبکه دیگری ایجاد می کنیم.
from sklearn.model_selection import GridSearchCV
# Create the parameter grid based on the results of random search param_grid = { 'bootstrap': [True], 'max_depth': [80, 90, 100, 110], 'max_features': [2, 3], 'min_samples_leaf': [3, 4, 5], 'min_samples_split': [8, 10, 12], 'n_estimators': [100, 200, 300, 1000] }
# Create a based model rf = RandomForestRegressor()
# Instantiate the grid search model grid_search = GridSearchCV(estimator = rf, param_grid = param_grid, cv = 3, n_jobs = -1, verbose = 2)
در این حالت 1*4*2*3*3*4=288 حالت مختلف از تنظیمات، امتحان می شوند. این بار همه 288 حالت، مورد بررسی قرار می گیرند. می توان مدل را آموزش داد، بهترین پارامترها را نمایش داد و کارایی آن را مورد ارزیابی قرار داد.
# Fit the grid search to the data grid_search.fit(train_features, train_labels) grid_search.best_params_
{'bootstrap': True, 'max_depth': 80, 'max_features': 3, 'min_samples_leaf': 5, 'min_samples_split': 12, 'n_estimators': 100}
best_grid = grid_search.best_estimator_
در این نوشته به بررسی مفهوم هایپرپارامتر در مدل های یادگیری ماشین و تفاوت آن با پارامترهای مدل پرداختیم. در ادامه روشی برای تنظیم هایپر پارامترها در الگوریتم جنگل مطرح شده است. در این روش، ابتدا با استفاده از متد RandomizedSearchCV کتابخانه Scikit-Learn پایتون، تعداد زیادی از مقادیر مجاز برای هایپرپارامترها را تعریف می کنیم و این متد به طور تصادفی تعدادی از آنها امتحان می کند. با استفاده از نتایج به دست آمده، فضای جستجوی خود را کوچکتر می کنیم. در مرحله بعد با استفاده از متد GridSearchCV بازه های کوچکتر اما دقیق تری را امتحان می کنیم. این بار کل فضای جستجو، مورد ارزیابی قرار می گیرد. توجه کنید هیچ گاه نمی توان به بهترین هایپرپارامترها دست یافت.
منبع سایت : https://towardsdatascience.com/
کانال من در تلگرام : https://t.me/meteorjournal