40 گام به سوی آینده‌ای هوشمند - مجموعه وبینارهای رایگان در حوزه هوش مصنوعی
Filter by دسته‌ها
chatGTP
آموزش هوش مصنوعی و انواع آن
آموزش‌های پایه‌ای هوش مصنوعی
اصول هوش مصنوعی
پایتون و ابزارهای یادگیری عمیق
کتابخانه‌ های یادگیری عمیق
یادگیری با نظارت
یادگیری بدون نظارت
یادگیری تقویتی
یادگیری عمیق
یادگیری نیمه نظارتی
آموزش‌های پیشرفته هوش مصنوعی
بینایی ماشین
پردازش زبان طبیعی
پردازش گفتار
چالش‌های عملیاتی
داده کاوی و بیگ دیتا
رایانش ابری و HPC
سیستم‌‌های امبدد
علوم شناختی
دیتاست
اخبار
تیتر یک
رسانه‌ها
آموزش پردازش زبان طبیعی
آموزش علوم داده
اینفوگرافیک
پادکست
ویدیو
رویدادها
کاربردهای هوش مصنوعی
کسب‌و‌کار
تحلیل بازارهای هوش مصنوعی
کارآفرینی
هوش مصنوعی در ایران
هوش مصنوعی در جهان
 مهندسی ویژگی خودکار با استفاده از شبکه‌های عصبی

مهندسی ویژگی خودکار با استفاده از شبکه‌های عصبی

برای همگان مشخص است که مهندسی ویژگی یکی از مهم‌ترین گام‌های تولید مدل‌های دقیق است. بعضی از برنامه‌نویس‌ها عاشق این مرحله هستند ولی من علاقه‌ چندانی به این مرحله ندارم. به نظر من این مرحله بسیار خسته‌کننده است و معتقدم که هر کار خسته‌کننده‌ای را می‌توان به صورت خودکار درآورد. اگر چه راهکار پیشنهادی من باعث نمی‌شود تنظیمات دستی کاملاً حذف شود، ولی تا حد زیادی انجام عملیات به صورت دستی را کاهش می‌دهد به نتایج بهتری و منجر می‌شود. همچنین با این راهکار مدلی ایجاد می‌کنیم که به‌طور مداوم روش‌های ارتقای گرادیان را بر روی دیتاست‌های ساختاریافته اعمال می‌کند.

مهندسی ویژگی

«برای اینکه این مرحله به‌درستی انجام شود ممکن است لازم باشد هفته‌ها برای تحلیل کاوشگرانه داده‌ها وقت صرف شود. خوشبختانه شبکه‌های عصبی در یافتن تعاملات مهارت دارند».

وقتی دسته‌ای از ویژگی‌ها به مدل خورانده می‌شود، مدل باید یاد بگیرد که کدام ویژگی‌ها با هم در تعامل هستند و این تعامل چگونه است. در دیتاست‌های بزرگ ممکن است لازم باشد مدل بی‌نهایت ترکیب را آزمون کند، لذا مدل روی تعاملاتی متمرکز می‌شود که سریع‌تر به جواب می‌رسند. با مهندسی ویژگی می‌توان برای اطمینان از تمرکز مناسب مدل روی ویژگی‌های خاص، به‌طور دستی، آن ویژگی‌ها را ایجاد کرد یا آنها را با هم ترکیب نمود.

متناسب با داده‌ها و مسئله مورد بررسی، روش‌های مختلفی برای مهندسی ویژگی وجود دارد. بیشتر این روش‌ها در دسته‌های زیر قرار می‌گیرند:

  • پاک‌سازی داده‌ها: برخی از برنامه‌نویسان پاک‌سازی داده‌ها‌ را مهندسی ویژگی به شمار می‌آورند، اما پاک‌سازی داده‌ها خود یک مرحله منحصربه‌فرد است. به طور خلاصه باید قبل از انجام مهندسی ویژگی مطمئن شوید که داده‌ها قابل استفاده هستند. پاک‌سازی داده‌ها شامل اصلاح و رفع خطاهای داده‌ها، مدیریت داده‌های گمشده، مدیریت داده‌های پرت، کدگذاری وان-هات (one-hot)، مقیاس‌دهی ویژگی، و موارد بسیار دیگری می‌شود. (به نظر من پا‌ک‌سازی داده‌ها بدتر از مهندسی ویژگی است و بسیار خوشحال می‌شوم اگر کسی راهی برای خودکارسازی آن معرفی کند.)
  • کدگذاری میانگین: این مرحله شامل تبدیل ویژگی‌های دسته‌ای، مانند کد پستی، به اطلاعات قابل استفاده برای مدل است. برای مثال، می‌توان ستونی برای نمایش میانگین درآمد فروش یک کد پستی ایجاد کرد.
  • متغیرهای تأخیر: گاهی افزودن یک عنصر سری زمانی به داده‌ها می‌تواند کارساز باشد. با اضافه‌کردن مقادیری از دوره‌های قبلی مدل می‌توان مشخص کرد داده‌ها با گذر زمان چه تغییری می‌کنند (مثلاً فروش ماه گذشته، فروش ماه قبل‌تر و فروش ماه‌های قبل‌تر). این فرآیند چندان پیچیده نیست و با چند حلقه ساده به راحتی می‌توان آن را به صورت خودکار در آورد.
  • تعاملات: این مرحله شامل ترکیب ویژگی‌ها به روش‌های متفاوت است. مثلاً، احتمالاً با تقسیم تعداد خریدهایی که در اثر تبلیغات انجام شده‌اند بر تعداد کل دفعاتی که یک پیام تبلیغاتی باز شده است، نرخ تبدیل تبلیغات برخط را اندازه می‌گیرند. اما اگر نرخ تبدیل تا حد زیادی وابسته به قیمت محصول باشد، چطور؟ در این حالت می‌توانید بر اساس آستانه‌های قیمتی ستون‌های جداگانه تعریف کنید. با این حال، ممکن است شناسایی و مدیریت تعاملات از مرتبه سه (یا بیشتر) بسیار دشوار باشد (برای مثال نرخ تبدیل تبلیغات می‌تواند هم به قیمت و هم به نوع محصول بستگی داشته باشد). بااین‌حال، بررسی تعاملات ظریف‌ترین و وقت‌گیر‌ترین گام در مهندسی ویژگی است. برای اینکه این مرحله به‌درستی انجام شود ممکن است لازم باشد هفته‌ها برای تحلیل کاوشگرانه داده‌ها وقت صرف شود. خوشبختانه، یافتن تعاملات از مهارت‌های اصلی شبکه‌های عصبی است. تنها باید اطمینان حاصل کرد که مدل در جست‌وجوی این تعاملات است و از این به بعد آنها را مورد توجه قرار خواهد داد.

مفاهیم

شبکه عصبی بخشی از ویژگی‌های ورودی را بر می‌دارد و تعاملاتی بین آنها تعریف می‌کند. این تعاملات برای رسیدن به بهترین پیش‌بینی مناسب هستند. همان‌طور که قبلاً مطرح شد، با مهندسی ویژگی می‌توانیم مدل را وادار کنیم ترکیب‌های خاصی از آنها را در نظر بگیرد. حال چه می‌شود اگر در عوض بتوان شبکه عصبی را وادار کرد تا آنها را در نظر بگیرد؟ چه می‌شود اگر بتوان مطمئن شد که شبکه عصبی این ویژگی‌ها را به‌نحو‌ی مهندسی کند که خروجی نهایی بیشترین دقت را داشته باشد؟ نکته اصلی این است که به مدل آموزش دهید از همان ابتدا بر این ویژگی‌ها متمرکز شود.

[irp posts=”۱۰۰۹۶″]

فرض کنید ویژگی‌های A، B، C و D را با خروجی هدف Y داریم. اولین گام برای حل این مسئله ایجاد مدلی است که تمام ویژگی‌ها را پیش‌بینی کند. چرا پیش‌بینی ویژگی‌ها اهمیت دارد؟ زیرا هدف این است که شبکه عصبی تعاملات مربوط به هر ویژگی را یاد بگیرد.

مفاهیم مهندسی ویژگی
نمونههایی از شبکههای ویژگی

 

نکته جالب راجع به این مرحله این است که در اینجا نگران خروجی مدل نیستیم. آخرین لایه مخفی (گره‌های سبزرنگ نمودار) که دربرگیرنده ویژگی‌های مهندسی‌شده جدید است آن چیزی است که استخراج می‌شود. می‌توان این ویژگی‌ها را برای پیش‌بینی خروجی هدف Y (در کنار ویژگی‌های اصلی) به مدل نهایی خوراند.

شبکه ویژگی کامل
نمونهای از یک شبکه ویژگی کامل

 

زیرکی آن است که اطمینان حاصل شود که شبکه‌های ویژگی‌ از طریق مدل نهایی آموزش ‌ببینند نه طی یک فرآیند مجزا. و زیرکانه‌تر از آن آموزش یک لایه تعبیه‌شده است که به تمام لایه‌های ویژگی خورانده ‌شود. خبر خوب این که پس از ماه‌ها تلاش موفق به ارائه راه‌حلی فرای انتظاراتم شدم.

کد

برای تشریح این روش احتمال بروز علائم شدید در افراد مبتلا به ویروس کرونا پیش‌بینی می‌شود. دسترسی به دیتاست «Cleaned-Data.csv» از طریق آدرس زیر مهیاست:

 https://www.kaggle.com/iamhungundji/covid19-symptoms-checker?select=Cleaned-Data.csv

 در ادامه داده‌ها به دیتاست‌های آموزش، اعتبارسنجی و آزمون تقسیم می‌شوند:

import pandas as pd
import tensorflow as tf
from sklearn.model_selection import train_test_split
from tensorflow import feature_column
from tensorflow.keras import layers
from tensorflow.keras.callbacks import ModelCheckpoint
from sklearn.metrics import log_lossX_train = pd.read_csv('covid_data.csv')
y_train = X_train.pop('Severity_Severe').to_frame()
X_train = X_train.iloc[:,:23]X_train, X_val, y_train, y_val = train_test_split(
    X_train, y_train,test_size=0.2,random_state=42)X_val, X_test, y_val, y_test = train_test_split(
    X_val, y_val,test_size=0.5,random_state=42)

اکنون باید مشخص کرد که مدلِ ویژگی‌ برای چه ویژگی‌هایی ساخته شود. به دلیل اینکه تعداد ویژگی‌ها زیاد نیست برای همه آنها مدل ویژگی تعریف خواهیم کرد به غیر از ویژگی کشور(Country) که برای تعبیه‌سازی استفاده خواهد شد. وقتی مدل صدها ویژگی دارد، بهتر است ویژگی‌های برتر را، مانند مثال زیر، به طور عینی تعریف کنید:

model_cols = ['Fever','Tiredness','Dry-Cough',
              'Difficulty-in-Breathing',
              'Sore-Throat','None_Sympton',
              'Pains','Nasal-Congestion',
              'Runny-Nose','Diarrhea',
              'None_Experiencing','Age_0-9',
              'Age_10-19','Age_20-24','Age_25-59',
              'Age_60_','Gender_Female','Gender_Male',
              'Gender_Transgender','Contact_Dont-Know',
              'Contact_No','Contact_Yes']

هرکدام از این ویژگی‌ها در کنار ویژگی هدفی که قرار است پیش‌بینی شود (یعنی Severity_Severe) یک خروجی کمکی متمایز خواهد بود. هنگام ساخت دیتاست در تنسورفلو (TensorFlow)، باید این ‌ویژگی‌ها را نیز به‌عنوان ویژگی‌های خروجی تعریف کرد. شایان ذکر است که نام این ویژگی‌ها تغییر داده شده و پسوند «_out» به نام هرکدام از آنها اضافه شده است تا تنسورفلو به‌خاطر وجود نام‌های تکراری و مشابه سردرگم نشود. همچنین، توجه کنید که برای خروجی هدف یک ستون اضافی با نام «_aux_out» ایجاد شده است. بدین ترتیب می‌توان با ویژگی هدفی که به مدل نهایی داده خواهد شد یک مدلِ ویژگی را به طور مجزا آموزش داد. این فرآیند «skip connection» نام دارد و به مدل امکان می‌دهد تعاملات عمیق و سطحی را از مجموعه ویژگی‌های یکسان یاد بگیرد.

Y_train_df= X_train[model_cols].copy()
Y_train_df.columns = Y_train_df.columns + "_out"
Y_train_df['Severity_Severe_out'] = y_train['Severity_Severe']
Y_train_df['Severity_Severe_aux_out'] = y_train['Severity_Severe']
trainset = tf.data.Dataset.from_tensor_slices((
    dict(X_train),dict(Y_train_df))).batch(256)Y_val_df = X_val[model_cols].copy()
Y_val_df.columns = Y_val_df.columns + "_out"
Y_val_df['Severity_Severe_out'] = y_val['Severity_Severe']
Y_val_df['Severity_Severe_aux_out'] = y_val['Severity_Severe']
valset = tf.data.Dataset.from_tensor_slices((
    dict(X_val),dict(Y_val_df))).batch(256)Y_test_df = X_test[model_cols].copy()
Y_test_df.columns = Y_test_df.columns + "_out"
Y_test_df['Severity_Severe_out'] = y_test['Severity_Severe']
Y_val_df['Severity_Severe_aux_out'] = y_val['Severity_Severe']
testset = tf.data.Dataset.from_tensor_slices((
    dict(X_test),dict(Y_test_df))).batch(256)

اولین تابعی که تعریف می‌شود تابع add_model است. نام ویژگی‌ها به این تابع خورانده می‌شود، تعداد و اندازه لایه‌ها در آن تعریف می‌شود، سپس مشخص می‌شود که آیا قرار است نرمال‌سازی بسته‌های داده‌ای انجام شود یا خیر، در ادامه نام مدل تعریف می‌شود و نوع تابع فعال‌سازی خروجی مشخص می‌گردد. متغیر hidden_layers برای هر لایه فهرستی مجزا خواهد داشت که درآن عدد اول، تعداد نورون‌ها و عدد دوم نرخ دراپ اوت است. خروجی این تابع، لایه خروجی و آخرین لایه پنهان (و دربرگیرنده ویژگی‌های مهندسی‌شده) خواهد بود که به مدل نهایی خورانده می‌شود. این تابع امکان تنظیم آسان هایپرپارامترها را هنگام استفاده از ابزارهایی مانند hyperopt فراهم می‌کند.

def add_model(
    feature_outputs=None,hidden_layers=[[512,0],[64,0]],
    batch_norm=False,model_name=None,activation='sigmoid'):
    
    if batch_norm == True:
        layer = layers.BatchNormalization()(feature_outputs)
    else:
        layer = feature_outputs
    
    for i in range(len(hidden_layers)):
        layer = layers.Dense(hidden_layers[i][0], activation='relu',
                             name=model_name+'_L'+str(i))(layer)
        last_layer = layer
        
        if batch_norm == True:
            layer = layers.BatchNormalization()(layer)
        if hidden_layers[i][1] > 0:
            layer = layers.Dropout(hidden_layers[i][1])(layer)
        
    output_layer = layers.Dense(1, activation=activation,
                                name=model_name+'_out')(layer)
        
    return last_layer, output_layer

تابع بعدی لایه تعبیه‌شده را ایجاد می‌کند. به دلیل اینکه country یک ویژگی دسته‌ای تنک است، ایجاد لایه تعبیه‌شده کارساز خواهد بود. این تابع یک دیکشنری‌ از ویژگی‌ها می‌گیرد که هماهنگ با فهرستی از مقادیر ممکن و منحصربه‌فرد ویژگی مذکور تبدیل به تعبیه‌ساز می‌شوند:

[irp posts=”۱۹۳۴۰″]
emb_layers = {'Country':list(X_train['Country'].unique())}

ورودی‌ها نیز به مدل خورانده می‌شوند. این ورودی‌ها بعداً تعریف می‌شوند. برای پارامتر ابعاد تصمیم گرفتم از روش پیش‌فرض قاعده سرانگشتی (Rule-of-thumb) یعنی ریشه چهارم طول ویژگی‌های منحصربه‌فرد استفاده کنم.

def add_emb(emb_layers={},model_inputs={}):
    emb_inputs = {}
    emb_features = []
    
    for key,value in emb_layers.items():
        emb_inputs[key] = model_inputs[key]
        catg_col = feature_column
            .categorical_column_with_vocabulary_list(key, value)
        emb_col = feature_column.embedding_column(
            catg_col,dimension=int(len(value)**0.25))
        emb_features.append(emb_col)
    
    emb_layer = layers.DenseFeatures(emb_features)
    emb_outputs = emb_layer(emb_inputs)
    
    return emb_outputs

پیش از ایجاد تابع بعدی، لازم است مشخص شود کدام ویژگی‌ها باید از مدل‌های‌ ویژگی‌ حذف شوند. اصولاً باید هم ویژگی‌هایی را حذف کرد که زودتر پیش‌بینی می‌شوند (داده‌های نشتی) و هم ویژگی‌هایی که برای تعبیه‌سازی استفاده شده‌اند. توجه داشته باشید که باید ویژگی‌هایی که به طور مستقیم در محاسبه ویژگی خروجی استفاده می‌شوند را نیز حذف کنید. مثلاً، مدل به‌سرعت و صرفاً با مشاهده مقادیر سایر ستون‌های جنسیت و نادیده‌گرفتن سایر ویژگی‌ها متوجه می‌شود که می‌تواند ویژگی Gender_Female را با دقت۱۰۰% پیش‌بینی کند، بنابراین سایر ویژگی‌ها را نادیده می‌گیرد. اما چنین مدلی چندان کارساز نیست. به منظور اصلاح این مسئله، سایر جنسیت‌ها، سن و اطلاعات تماس را از مدل ویژگی مربوطه حذف می‌کنیم.

feature_layers = {col:[col,'Country'] for col in model_cols}feature_layers['Gender_Female'] += ['Gender_Male',
                                    'Gender_Transgender']
feature_layers['Gender_Male'] += ['Gender_Female',
                                  'Gender_Transgender']
feature_layers['Gender_Transgender'] += ['Gender_Female',
                                         'Gender_Male']feature_layers['Age_0-9'] += ['Age_10-19','Age_20-24',
                              'Age_25-59','Age_60_']
feature_layers['Age_10-19'] += ['Age_0-9','Age_20-24',
                                'Age_25-59','Age_60_']
feature_layers['Age_20-24'] += ['Age_0-9','Age_10-19',
                                'Age_25-59','Age_60_']
feature_layers['Age_25-59'] += ['Age_0-9','Age_10-19',
                                'Age_20-24','Age_60_']
feature_layers['Age_60_'] += ['Age_0-9','Age_10-19',
                              'Age_20-24','Age_25-59']feature_layers['Contact_Dont-Know'] += ['Contact_No','Contact_Yes']
feature_layers['Contact_No'] += ['Contact_Dont-Know','Contact_Yes']
feature_layers['Contact_Yes'] += ['Contact_Dont-Know','Contact_No']

علاوه‌براین، قصد داریم یک feature_layer به مدلِ کمکی skip connection اضافه کنیم:

feature_layers['Severity_Severe_aux'] = ['Country']

اکنون هر آنچه برای ساخت مدلِ ویژگی لازم است مهیاست. این تابع از فهرستی از تمام ویژگی‌های ورودی، دیکشنری‌های ویژگی‌های حذف‌شده و تعبیه‌شده که قبلاً مطرح شد، ساختار hidden_layer که در تابع add_model تعریف شد، و شاخصی برای مواقعی که نرمال‌سازی بسته‌های داده‌ انجام می‌شود استفاده می‌کند.

تابع ابتدا ویژگی‌های ورودی را تعریف می‌کند، به‌نحو‌ی که تنسورفلو به‌راحتی آنها را بخواند. بزرگ‌ترین مزیت استفاده از ورودی‌های تنسورفلو این است که کافی است یک بار ویژگی‌ها تعریف شوند و بارها و بارها در مدل‌های ویژگی استفاده شوند. پس از آن معلوم می‌‌شود که آیا ستون تعبیه‌شده‌ ایجاد شده است یا خیر و یک لایه تعبیه‌شده ایجاد می‌شود (اختیاری). در ازای هر مدل ویژگی یک لایه ورودی DenseFeatures ساخته می‌شود (ویژگی‌های تعریف‌شده مذکور حذف می‌شوند) و با استفاده از تابع add_model یک مدل مجزا ایجاد می‌شود.

پیش از خروجی‌گرفتن، بررسی می‌کنیم که آیا حلقه روی مدل skip connection اجرا می‌شود یا نه. در صورت اجرای حلقه روی skip connection، ویژگی‌های ورودی به مدل افزوده می‌شود تا مدل نهایی با ویژگی‌های اصلی نیز آموزش ببیند. در نهایت خروجی تابع شامل دیکشنری‌ای از ورودی‌های مدل، فهرستی از لایه‌های خروجی مدل‌ ویژگی و فهرستی از تمام لایه‌های پنهان نهایی (یا به عبارتی ویژگی‌های  مهندسی‌شده جدید) خواهد بود.

def feature_models(
    output_feature=None,all_features=[],feature_layers={},
    emb_layers={},hidden_layers=[],batch_norm=False):
    
    model_inputs = {}
    for feature in all_features:
        if feature in [k for k,v in emb_layers.items()]:
            model_inputs[feature] = tf.keras.Input(shape=(1,),
                                                   name=feature,
                                                   dtype='string')
        else:
            model_inputs[feature] = tf.keras.Input(shape=(1,),
                                                   name=feature)
            
    if len(emb_layers) > 0:
        emb_outputs = add_emb(emb_layers,model_inputs)
        
    output_layers = []
    eng_layers = []
    for key,value in feature_layers.items():
        feature_columns = [feature_column.numeric_column(f)
                           for f in all_features if f not in value]
        
        feature_layer = layers.DenseFeatures(feature_columns)
        feature_outputs = feature_layer({k:v for k,v in
                                         model_inputs.items()
                                         if k not in value})
        
        if len(emb_layers) > 0:
            feature_outputs = layers.concatenate([feature_outputs,
                                                  emb_outputs])
    
        last_layer, output_layer = add_model(
            feature_outputs=feature_outputs,
            hidden_layers=hidden_layers,
            batch_norm=batch_norm,
            model_name=key)
        
        output_layers.append(output_layer)
        eng_layers.append(last_layer)
        
        if key == output_feature + '_aux':
            eng_layers.append(feature_outputs)
    
    return model_inputs, output_layers, eng_layers

دقت داشته باشید که در صورت استفاده از لایه تعبیه‌شده، این لایه با تمام ورودی‌های مدل‌های ویژگی تلفیق خواهد شد. به عبارت دیگر لایه‌های تعبیه‌شده علاوه بر اینکه برای بیشینه‌کردن دقت کلی مدل آموزش می‌بینند، روی تمام مدل‌های ویژگی نیز آموزش می‌بینند. به این خاطر تعبیه‌سازی بسیار مقاوم می‌شود.

قبل از نوشتن آخرین تابع باید پارامترهایی که قرار است به آن خورانده شوند تعریف کرد. بیشتر این پارامترها یا در بخش‌های قبلی توضیح داده شده‌اند یا از پارامترهای متداول مدل‌های تنسورفلو هستند. چنانچه با پارامتر patience آشنا نیستید: وقتی دقت اعتبارسنجی در دوره‌های تعیین‌شده بهبود نیابد از پارامتر patience برای توقف آموزش مدل استفاده می‌شود.

params = {'all_features': list(X_train.columns),
          'output_feature':y_train.columns[0],
          'emb_layers':emb_layers,
          'feature_layers':feature_layers,
          'hidden_layers':[[256,0],[128,0.1],[64,0.2]],
          'batch_norm': True,
          'learning_rate':0.001,
          'patience':3,
          'epochs':20
        }

برای ایجاد مدل نهایی، ابتدا تابع قبلی برای تولید ورودی‌ها، خروجی‌ها و ویژگی‌های مهندسی‌شده اجرا می‌شود. سپس هریک این لایه‌ها/ ویژگی‌ها به یکدیگر الحاق می‌شود و به مدل نهایی خورانده می‌شود. در پایان مدل ساخته می‌شود، کامپایل می‌شود، آموزش داده می‌شود و آزمون می‌شود.

def final_model(params,test=True):
   
    print(params['batch_norm'],params['hidden_layers'])
    
    model_inputs, output_layers, eng_layers = feature_models(
        all_features=params['all_features'],
        feature_layers=params['feature_layers'],
        emb_layers=params['emb_layers'],
        hidden_layers=params['hidden_layers'],
        batch_norm=params['batch_norm'],
        output_feature=params['output_feature'])
    
    concat_layer = layers.concatenate(eng_layers)
    last_layer, output_layer = add_model(
        feature_outputs=concat_layer,
        hidden_layers=params['hidden_layers'],
        batch_norm=params['batch_norm'],
        model_name=params['output_feature'])
    
    output_layers.append(output_layer)
    
    model = tf.keras.Model(
        inputs=[model_inputs],
        outputs=output_layers)
        
    aux_loss_wgt = 0.5 / len(params['feature_layers'])
    loss_wgts = [aux_loss_wgt for i in 
                 range(len(params['feature_layers']))
    loss_wgts.append(0.5)
    
    model.compile(loss='binary_crossentropy',
                  optimizer=tf.keras.optimizers.Adam(
                      lr=params["learning_rate"]),
                  loss_weights=loss_wgts,
                  metrics=['accuracy'])
    
    es = tf.keras.callbacks.EarlyStopping(
        monitor='val_loss',mode='min',verbose=1,
        patience=params['patience'],restore_best_weights=True)
                 
    history = model.fit(
        trainset,validation_data=valset,
        epochs=params['epochs'], verbose=0, callbacks=[es])
    
    yhat = model.predict(testset)
    loss = log_loss(
        np.array(y_test[params['output_feature']]),
        yhat[-1])**.5
    
    print('Binary Crossentropy:',loss)
    
    if test==True:
        sys.stdout.flush()
        return {'loss': loss, 'status': STATUS_OK}
    else:
        return history, model

همان‌طور که مشاهده می‌کنید یکی از وروردی‌های این تابع test نام دارد. test این امکان را در اختیار شما می‌گذارد که یا از hyperopt برای پیداکردن بهترین پارامترها استفاده کنید (test = True) یا مدل را آموزش داده و به مدل نهایی بازگردید (test = False). احتمالاً با پارامتر loss_weights نیز در حین کامپایل‌کردن مدل آشنا نیستید.

چون چندین خروجی کمکی وجود دارد، لازم است هنگام تنظیم مدل و بهبود دقت آن برای تنسورفلو مشخص کنیم که به هریک چه وزنی اختصاص دهد. شخصاً ترجیح می‌دهم ۵۰% به پیش‌بینی‌های کمکی (در مجموع) و ۵۰% به پیش‌بینی‌های هدف وزن بدهم. ممکن است از نظر برخی تخصیص وزن به پیش‌بینی‌های کمکی عجیب باشد زیرا این پیش‌بینی‌ها در مرحله محاسبه loss کنار گذاشته می‌شوند. مسئله این است که اگر وزنی به آنها اختصاص ندهیم مدل اغلب آنها را نادیده می‌گیرد و درنتیجه ویژگی‌های سودمند را یاد نمی‌گیرد.

اکنون کافی است تابع final_model با استفاده از پارامترهایی که قبلاً تعریف شد اجرا شود.

history, model = final_model(params,test=False)

اکنون که یک مدل آموزش‌یافته در اختیار داریم، می‌توانیم ویژگی‌های جدید را با استفاده از تابع کراسِ get_layer() استخراج کرده و در مدل‌های دیگر استفاده کنیم.

[irp posts=”۱۲۲۴۹″]

نتایج

قابل تصور است که آموزش این مدل به‌لحاظ محاسباتی گران است. خبر خوب این است که این روش اغلب در مقایسه با «پرسپترون چندلایه» معمولی با تعداد آزمایش‌های بسیار کمتر به پاسخ‌ دقیق‌تری می‌رسد.

با در نظر گرفتن مدت زمانی که برای انجام مهندسی ویژگی (که امری بسیار خسته‌کننده است) صرف می‌شود متوجه خواهید شد که این روش بسیار سریع‌تر است. افزون‌براین، تأخیر پیش‌بینی به‌قدری کم هست که این مدل (برخلاف فرامدل معمولی Kaggle 50+) می‌تواند یک مدل تولید باشد. اگر ویژگی‌ها را استخراج نموده‌ و شبکه عصبی را دوباره با آنها آموزش دهید، سرعت شبکه عصبی افزایش خواهد یافت.

البته همچنان مسئله دقت مدل بی‌پاسخ مانده است. این مدل در هر آزمایشی که استفاده شده، از سایر روش‌ها دقیق‌تر بوده است. با وجود این باور عمومی که مدل‌های گرادیان ارتقایافته برای دیتاست‌های ساختاریافته بر دیگر مدل‌ها ترجیح دارند، این روش همواره عملکرد بهتری از XGBoost داشته است. عملکرد مدل در این مسئله از قرار ادامه است.

روش‌شناسی و دقت

به این منظور سه مدل مختلف آزمایش شده است:

  • XGBoost
  • مدل استاندارد پرسپترون چندلایه با تعبیه‌سازی
  • مدلی آموزش‌یافته فوق با مهندسی ویژگی خودکار

برای آزمایش مدل با ویژگی خودکار، آزمایش۲۰ مرتبه با استفاده از hyperopt اجرا شده است تا مدل با شبکه‌های با اندازه‌های مختلف آزمایش شود. برای آزمایش دو مدل رقیب، به‌خاطر زمان کمتری که این دو مدل برای آموزش صرف می‌کنند؛ آزمایش۴۰ بار اجرا شده است. نتایج را در جدول زیر مشاهده می‌کنید:

نمره دقت هر مدل
نمره دقت هر مدل

همان‌طور که انتظار می‌رفت، مدل آموزش‌یافته با مهندسی ویژگی خودکار بهترین عملکرد را دارد. شایان ذکر است که اطلاعات مفید این دیتاست ساده به‌اندازه‌ای نبود که تفاوت چشم‌گیری بین عملکرد این روش‌ها ایجاد کند. وقتی این مدل را با دیتاست‌های کلانی که صدها ویژگی دارند آزمودم، عملکردی بین ۵% تا ۱۰% بهتر از عملکرد XGBoost داشت.

میانگین امتیاز / ۵. تعداد ارا :

مطالب پیشنهادی مرتبط

اشتراک در
اطلاع از
0 نظرات
بازخورد (Feedback) های اینلاین
مشاهده همه دیدگاه ها
[wpforms id="48325"]