ارزیابی مدل یادگیری عمیق — به زبان ساده

هنگامی که یک مدل «شبکه عصبی یادگیری عمیق» (Deep Learning Neural Network) برازش میشود، باید کارایی آن روی مجموعه دادههای تست ارزیابی شود. این کار از آن رو ضروری است که کارایی گزارش شده به کاربر امکان انتخاب بین مدلهای کاندید و همچنین، مذاکره با ذینفعان پیرامون خوب بودن مدل در حل مسائل را میدهد. مدل «رابط برنامهنویسی کاربردی» (Application Programming Interface) یادگیری عمیق کتابخانه «کرس» (Keras)، بسیار محدود به سنجههایی است که میتوان از آنها برای گزارش کردن کارایی مدل استفاده کرد. افراد زیادی که مدلهای یادگیری عمیق استفاده میکنند، معمولا این پرسش را مطرح میکنند که «چگونه میتوان دقت و صحت مدل را اندازهگیری کرد؟» و «چطور میتوان امتیاز «اف ۱» (F1 Score) یا ماتریس درهم ریختگی را برای مدل محاسبه کرد». در این مطلب، ضمن تشریح روشهای ارزیابی مدل یادگیری عمیق، موارد زیر مورد بررسی قرار خواهند گرفت.
- چگونه میتوان از API سنجههای کتابخانه «سایکیتلرن» (Scikit-Learn) برای ارزیابی مدل یادگیری عمیق استفاده کرد.
- چگونه میتوان پیشبینی دستهها و احتمال را با یک مدل خوب مورد نیاز با API سایکیتلرن انجام داد.
- چگونه میتوان «دقت» (Precision)، «صحت» (Recall)، «امتیاز اف ۱» (F1-Score)، «منحنی مشخصه عملکرد سیستم» (Receiver Operating Characteristic | ROC) و دیگر موارد را با استفاده از API سایکیتلِرن، برای مدل محاسبه کرد.
در این مطلب در سه بخش کلی، به مساله دستهبندی دودویی، مدل «پرسپترون چند لایه» (Multilayer Perceptron) و چگونگی محاسبه سنجههای مدل پرداخته خواهد شد.
مساله دستهبندی دودویی
در اینجا، از یک مساله استاندارد دستهبندی دودویی استفاده میشود که مساله «Two Circles» نام دارد. به این مساله، بدین دلیل مساله دو دایره گفته میشود که در بردارنده نقاطی است که پس از ترسیم، دو دایره هممرکز را نشان میدهند؛ هر یک از این دایرهها برای یک دسته (از مجموع دو دسته) هستند. بدین شکل، این مثالی از یک مساله دستهبندی دودویی است. مساله دارای دو ورودی است که در نمودار به عنوان محورهای x و y قابل تفسیر هستند. هر نقطه داده به دایره داخلی یا خارجی تعلق دارد.
تابع ()make_circles در کتابخانه سایکیتلرن به کاربر امکان تولید نمونههایی از مساله دو دایره را میدهد. آرگومان «n_samples» به کاربر امکان تعیین تعداد نمونهها را برای تولید میدهد که به طور مساوی بین دو کلاس تقسیم شدهاند. آرگومان «noise» به کاربر این امکان را میدهد که مشخص کند چه میزان نویز آماری تصادفی به ورودیها یا مختصات هر نقطه داده میشود؛ این کار، دستهبندی را چالش برانگیزتر میکند. آرگومان «random_state» «بذر» (seed) برای مولد اعداد تصادفی را تعیین میکند تا اطمینان حاصل کند که نمونههای مشابهی هر بار که کد اجرا میشود تولید میشوند. مثال زیر، ۱۰۰۰ نمونه با نویز آماری ۰.۱ و بذر ۱ تولید میکند.
# generate 2d classification dataset X, y = make_circles(n_samples=1000, noise=0.1, random_state=1)
هنگامی که نمونهها تولید میشوند، میتوان یک نمودار از مجموعه داده را برای به دست آوردن ایدهای از اینکه کار دستهبندی چقدر چالش برانگیزتر است را ترسیم کرد. مثال زیر، نمونههایی را تولید و آنها را ترسیم میکند، هر نقطه مطابق با دستهای که به آن تعلق دارد رنگ میشود؛ نقاط متعلق به دسته ۰ (دایره بیرونی) به رنگ آبی و نقاط متعلق به دسته ۱ (دایره درونی) نارنجی رنگ میشوند.
# Example of generating samples from the two circle problem from sklearn.datasets import make_circles from matplotlib import pyplot from numpy import where # generate 2d classification dataset X, y = make_circles(n_samples=1000, noise=0.1, random_state=1) # scatter plot, dots colored by class value for i in range(2): samples_ix = where(y == i) pyplot.scatter(X[samples_ix, 0], X[samples_ix, 1]) pyplot.show()
اجرای مثال بالا، منجر به تولید مجموعه داده میشود و نقاط را روی نمودار ترسیم میکند؛ این نقاط به طور واضح نشانگر دو دایره هممرکز از نقاط متعلق به دستههای ۰ و ۱ هستند.

ارزیابی مدل پرسپترون چند لایه
یک مدل پرسپترون چند لایه یا MLP برای ارجاع به مساله دستهبندی دودویی مورد استفاده قرار میگیرد. این مدل، برای این مساله بهینه نشده، اما دارای توانمندی خوبی در حل آن است (بهتر از مدل تصادفی محسوب میشود). پس از آنکه نمونهها برای مجموعه داده تولید شدند، آنها به دو بخش مساوی تقسیم میشوند؛ یک بخش برای آموزش مدل و بخش دیگر برای ارزیابی مدل آموزش دیده.
# split into train and test n_test = 500 trainX, testX = X[:n_test, :], X[n_test:, :] trainy, testy = y[:n_test], y[n_test:]
سپس، میتوان مدل MLP را تعریف کرد. مدل ساده است؛ نیاز به دو متغیر ورودی از مجموعه داده، یک لایه پنهان با ۱۰۰ گره و یک تابع فعالسازی ReLU و در نهایت، یک گره مجرد و «تابع فعالسازی سیگموئید» (Sigmoid Activation Function) دارد. مدل یک مقدار بین ۰ و ۱ را پیشبینی میکند که تفسیر آن مشخص میکند نمونه ورودی متعلق به دسته ۰ یا ۱ است.
# define model model = Sequential() model.add(Dense(100, input_dim=2, activation='relu')) model.add(Dense(1, activation='sigmoid'))
مدل با استفاده از «تابع زیان آنتروپی متقاطع دودویی» (Binary Cross Entropy Loss Function) برازش میشود و در اینجا، از نسخه «آدام» (Adam) روش «گرادیان کاهشی تصادفی» (Stochastic Gradient Descent) استفاده خواهد شد. همچنین، مدل سنجه صحت دستهبندی را مورد نظارت قرار میدهد.
# compile model model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
مدل برای ۳۰۰ «دوره» (epoch) با اندازه دسته ۳۲ نمونه برازش میشود و کارایی مدل در پایان هر دوره روی مجموعه داده تست ارزیابی میشود.
# fit model history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=300, verbose=0)
در پایان آموزش، مدل نهایی یک بار دیگر روی مجموعه دادههای آموزش و تست ارزیابی میشود و صحت دستهبندی گزارش میشود.
# evaluate the model _, train_acc = model.evaluate(trainX, trainy, verbose=0) _, test_acc = model.evaluate(testX, testy, verbose=0)
در نهایت، کارایی مدل روی مجموعه دادههای آموزش و تست در طول آموزش، با استفاده از نمودار خطی ترسیم میشوند؛ یک نمودار برای زیان و یک نمودار برای صحت ترسیم خواهد شد.
# plot loss during training pyplot.subplot(211) pyplot.title('Loss') pyplot.plot(history.history['loss'], label='train') pyplot.plot(history.history['val_loss'], label='test') pyplot.legend() # plot accuracy during training pyplot.subplot(212) pyplot.title('Accuracy') pyplot.plot(history.history['acc'], label='train') pyplot.plot(history.history['val_acc'], label='test') pyplot.legend() pyplot.show()
با آزمودن همه این عناصر به صورت همزمان، کد مربوط به لیست کردن آموزش و ارزیابی یک MLP روی مساله دو دایره، در زیر نمایش داده شده است.
# multilayer perceptron model for the two circles problem from sklearn.datasets import make_circles from keras.models import Sequential from keras.layers import Dense from matplotlib import pyplot # generate dataset X, y = make_circles(n_samples=1000, noise=0.1, random_state=1) # split into train and test n_test = 500 trainX, testX = X[:n_test, :], X[n_test:, :] trainy, testy = y[:n_test], y[n_test:] # define model model = Sequential() model.add(Dense(100, input_dim=2, activation='relu')) model.add(Dense(1, activation='sigmoid')) # compile model model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) # fit model history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=300, verbose=0) # evaluate the model _, train_acc = model.evaluate(trainX, trainy, verbose=0) _, test_acc = model.evaluate(testX, testy, verbose=0) print('Train: %.3f, Test: %.3f' % (train_acc, test_acc)) # plot loss during training pyplot.subplot(211) pyplot.title('Loss') pyplot.plot(history.history['loss'], label='train') pyplot.plot(history.history['val_loss'], label='test') pyplot.legend() # plot accuracy during training pyplot.subplot(212) pyplot.title('Accuracy') pyplot.plot(history.history['acc'], label='train') pyplot.plot(history.history['val_acc'], label='test') pyplot.legend() pyplot.show()
با اجرای کد بالا، برازش مدل به سرعت روی CPU انجام میشود (نیاز به GPU نیست). ارزیابی مدل انجام و صحت دستهبندی روی مجموعههای آموزش و تست به ترتیب برابر با ٪۸۳ و ٪۸۵ گزارش میشود. شایان توجه است که نتایج ممکن است در اجراهای مختلف به دلیل ماهیت تصادفی الگوریتم آموزش، تغییر کنند.
Train: 0.838, Test: 0.850
شکل ساخته شده توسط دو نمودار خطی نمایش داده شده است. یک نمودار برای منحنی یادگیری زیان روی مجموعه آموزش و تست، و دیگری برای دستهبندی مجموعههای آموزش و تست است. نمودار حاکی از آن است که مدل برازش خوبی روی این مساله دارد.

روش محاسبه سنجههای مدل
ممکن است نیاز به ارزیابی مدل شبکه عصبی یادگیری عمیق با استفاده از سنجههایی باشد که در API سنجههای کرس پشتیبانی نمیشوند. API سنجههای کرس، محدودیت دارد و میتوان از آن برای محاسبه سنجههایی مانند دقت، صحت، امتیاز اف۱ (F1 Score) و دیگر موارد استفاده کرد. یک رویکرد برای محاسبه سنجههای جدید، پیادهسازی آنها توسط کاربر در API کرس است و محاسبه آنها را در طول آموزش و ارزیابی مدل است.
این کار ممکن است به لحاظ فنی، چالش برانگیز باشد. یک راهکار جایگزین سادهتر استفاده از مدل نهایی برای انجام پیشبینی برای مجموعه داده تست و سپس محاسبه هر سنجهای که کاربر تمایل دارد با استفاده از API سنجههای سایکیتلرن است. دقت، صحت، امتیاز اف۱ سه سنجه متداولی هستند که علاوه بر صحت دستهبندی برای مسائل دستهبندی دودویی یک مدل شبکه عصبی مورد استفاده قرار میگیرند.
در این بخش، این سه سنجه همراه با صحت دستهبندی با استفاده از API سنجههای سایکیتلرن و همچنین، سه سنجه اضافه دیگری که کمتر متداول اما محبوب هستند نیز محاسبه میشوند. این سه سنجه عبارتند از: ضریب «کاپای کوهن» (Cohen’s Kappa)، «منحنی مشخصه عملکرد سیستم» (ROC AUC)، «ماتریس درهم ریختگی» (Confusion Matrix).
لیست ارائه شده، یک لیست کامل از ماتریسهای موجود برای مدلهای دستهبندی پشتیبانی شده توسط سایکیتلرن نیست. این سنجهها صرفا به کاربر نشان میدهند که چگونه هر سنجهای را که ممکن است به آن نیاز پیدا کند، با استفاده از API سایکیتلرن مورد محاسبه قرار دهد. مثال ارائه شده در این بخش، سنجههایی برای یک مدل MLP را محاسبه میکند، اما کد مشابهی برای محاسبه سنجهها برای دیگر مدلها مانند «شبکههای عصبی بازگشتی» (Recurrent Neural Network) و «شبکههای عصبی پیچشی» (Convolutional Neural Network) نیز قابل استفاده است. میتوان از کد مشابهی از بخش پیشین برای آمادهسازی مجموعه داده، تعریف و برازش مدل استفاده کرد. برای سادهتر کردن مثال، کدهای لازم برای این گامها در یک تابع سادهتر قرار داده میشوند.
ابتدا، میتوان یک تابع با عنوان ()get_data اضافه کرد که مجموعه داده را تولید و آن را به بخشهای آموزش و آزمون تقسیم میکند.
# generate and prepare the dataset def get_data(): # generate dataset X, y = make_circles(n_samples=1000, noise=0.1, random_state=1) # split into train and test n_test = 500 trainX, testX = X[:n_test, :], X[n_test:, :] trainy, testy = y[:n_test], y[n_test:] return trainX, trainy, testX, testy
سپس، تابعی با عنوان ()get_model تعریف میشود که مدل MLP را تعریف کرده و آن را روی مجموعه داده آموزش برازش میکند.
# define and fit the model def get_model(trainX, trainy): # define model model = Sequential() model.add(Dense(100, input_dim=2, activation='relu')) model.add(Dense(1, activation='sigmoid')) # compile model model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) # fit model model.fit(trainX, trainy, epochs=300, verbose=0) return model
میتوان تابع ()get_data را برای آمادهسازی مجموعه داده و تابع ()get_model را برای برازش و بازگرداندن مدل استفاده کرد.
# generate data trainX, trainy, testX, testy = get_data() # fit model model = get_model(trainX, trainy)
اکنون که مدل روی مجموعه داده آموزش برازش داده شد، میتوان آن را با استفاده از سنجههایی از API سنجههای سایکیتلرن ارزیابی کرد. در حال حاضر، ابتدا باید از مدل برای انجام پیشبینی استفاده کرد. بیشتر توابع سنجهها نیاز به مقایسه بین مقادیر صحیح کلاس (برای مثال testy) و مقادیر کلاس پیشبینی شده (yhat_classes) دارند. میتوان مقادیر کلاس را به طور مستقیم با استفاده از تابع ()predict_classes روی مدل، پیشبینی کرد. برخی از سنجهها، مانند ROC AUC، نیاز به پیشبینی احتمالهای کلاس دارند (yhat_probs). این موارد را میتوان با فراخوانی تابع ()predict روی مدل پیشبینی کرد. میتوان کلاس و پیشبینیهای احتمالات را با مدل انجام داد.
# predict probabilities for test set yhat_probs = model.predict(testX, verbose=0) # predict crisp classes for test set yhat_classes = model.predict_classes(testX, verbose=0)
پیشبینیها در یک آرایه دوبعدی بازگردانده میشوند، با یک سطر برای هر مثال در مجموعه داده تست و یک ستون برای هر پیشبینی. API سنجههای سایکیتلرن نیاز به یک آرایه یکبُعدی از مقادیر واقعی و پیشبینی شده برای مقایسه دارد؛ بنابراین، باید آرایه دوبعدی را به یک بعدی کاهش داد.
# reduce to 1d array yhat_probs = yhat_probs[:, 0] yhat_classes = yhat_classes[:, 0]
اکنون، آمادگی لازم برای محاسبه سنجهها برای مدل شبکه عصبی یادگیری عمیق وجود دارد. میتوان کار را با محاسبه «درستی» (Accuracy)، «صحت» (Precision)، «دقت» (recall) و «امتیاز اف ۱» (F1 scores) آغاز کرد.
# accuracy: (tp + tn) / (p + n) accuracy = accuracy_score(testy, yhat_classes) print('Accuracy: %f' % accuracy) # precision tp / (tp + fp) precision = precision_score(testy, yhat_classes) print('Precision: %f' % precision) # recall: tp / (tp + fn) recall = recall_score(testy, yhat_classes) print('Recall: %f' % recall) # f1: 2 tp / (2 tp + fp + fn) f1 = f1_score(testy, yhat_classes) print('F1 score: %f' % f1)
محاسبه یک سنجه خاص، بسیار آسان و تنها کافی است کاربر سنجه مورد نظر خود را انتخاب کند. سپس، تابع مربوط به آن سنجه را فراخوانی کرده و آرگومانهای لازم را به آن پاس دهد. اکنون، میتوان برخی از سنجههای اضافی مانند «کوهن کاپا» (Cohen’s kappa)، «منحنی مشخصه عملکرد سیستم» (ROC AUC) و «ماتریس درهم ریختگی» (Confusion Matrix) را محاسبه کرد. توجه به این نکته لازم است که ROC AUC نیاز به احتمالات دسته پیشبینی شده (yhat_probs) به عنوان آرگومان دارد؛ به جای آنکه دسته پیشبینی شده (yhat_classes) را به عنوان آرگومان دریافت کند.
# kappa kappa = cohen_kappa_score(testy, yhat_classes) print('Cohens kappa: %f' % kappa) # ROC AUC auc = roc_auc_score(testy, yhat_probs) print('ROC AUC: %f' % auc) # confusion matrix matrix = confusion_matrix(testy, yhat_classes) print(matrix)
اکنون که چگونگی محاسبه سنجهها برای شبکههای عصبی یادگیری عمیق با استفاده از API سایکیتلرن مشخص شد، میتوان همه این عناصر را در کنار هم در یک مثال کامل قرار داد که کد آن در زیر ارائه شده است.
# demonstration of calculating metrics for a neural network model using sklearn from sklearn.datasets import make_circles from sklearn.metrics import accuracy_score from sklearn.metrics import precision_score from sklearn.metrics import recall_score from sklearn.metrics import f1_score from sklearn.metrics import cohen_kappa_score from sklearn.metrics import roc_auc_score from sklearn.metrics import confusion_matrix from keras.models import Sequential from keras.layers import Dense # generate and prepare the dataset def get_data(): # generate dataset X, y = make_circles(n_samples=1000, noise=0.1, random_state=1) # split into train and test n_test = 500 trainX, testX = X[:n_test, :], X[n_test:, :] trainy, testy = y[:n_test], y[n_test:] return trainX, trainy, testX, testy # define and fit the model def get_model(trainX, trainy): # define model model = Sequential() model.add(Dense(100, input_dim=2, activation='relu')) model.add(Dense(1, activation='sigmoid')) # compile model model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) # fit model model.fit(trainX, trainy, epochs=300, verbose=0) return model # generate data trainX, trainy, testX, testy = get_data() # fit model model = get_model(trainX, trainy) # predict probabilities for test set yhat_probs = model.predict(testX, verbose=0) # predict crisp classes for test set yhat_classes = model.predict_classes(testX, verbose=0) # reduce to 1d array yhat_probs = yhat_probs[:, 0] yhat_classes = yhat_classes[:, 0] # accuracy: (tp + tn) / (p + n) accuracy = accuracy_score(testy, yhat_classes) print('Accuracy: %f' % accuracy) # precision tp / (tp + fp) precision = precision_score(testy, yhat_classes) print('Precision: %f' % precision) # recall: tp / (tp + fn) recall = recall_score(testy, yhat_classes) print('Recall: %f' % recall) # f1: 2 tp / (2 tp + fp + fn) f1 = f1_score(testy, yhat_classes) print('F1 score: %f' % f1) # kappa kappa = cohen_kappa_score(testy, yhat_classes) print('Cohens kappa: %f' % kappa) # ROC AUC auc = roc_auc_score(testy, yhat_probs) print('ROC AUC: %f' % auc) # confusion matrix matrix = confusion_matrix(testy, yhat_classes) print(matrix)
اجرای قطعه کد بالا، مجموعه داده را آماده میکند، مدل را برازش میدهد و سپس، سنجهها را برای مدل ارزیابی شده روی مجموعه داده تست محاسبه کرده و گزارش میدهد. نتایج ممکن است در اجراهای مختلف با توجه به ماهیت تصادفی الگوریتمها، متفاوت باشند.
Accuracy: 0.842000 Precision: 0.836576 Recall: 0.853175 F1 score: 0.844794 Cohens kappa: 0.683929 ROC AUC: 0.923739 [[206 42] [ 37 215]]
جمعبندی
در این مطلب، چگونگی محاسبه سنجههایی برای ارزیابی مدل شکبه عصبی یادگیری عمیق به صورت گام به گام آموزش داده شد. همچنین، چگونگی استفاده از API سنجههای سایکیتلرن برای ارزیابی مدل یادگیری عمیق مورد بررسی قرار گرفت. روش محاسبه دقت، صحت، امتیاز اف وان و منحنی مسخصه عملکرد سیستم از دیگر مواردی بودند که در این مطلب به آنها پرداخته شد.
اگر مطلب بالا برای شما مفید بوده، آموزشهای زیر نیز به شما پیشنهاد میشود:
- مجموعه آموزشهای دادهکاوی و یادگیری ماشین
- مجموعه آموزشهای دادهکاوی یا Data Mining در متلب
- مجموعه آموزشهای هوش مصنوعی
- زبان برنامهنویسی پایتون (Python) — از صفر تا صد
- یادگیری عمیق (Deep Learning) با پایتون — به زبان ساده
- یادگیری ماشین با پایتون — به زبان ساده
- آموزش یادگیری ماشین با مثالهای کاربردی — مجموعه مقالات جامع وبلاگ فرادرس