بهار 1401
آموزش کامل در :
برای ساخت مدل در Keras از دو روش می توان استفاده کرد:
1- روش اول استفاده از مدل Sequential
این روش که رایج ترین روش می باشد یک مدل Sequential ایجاد کرده و بعد به ترتیت لایه ها را به مدل اضافه می کنیم.
2- روش دوم به کارگیری Keras Functional API در این حالت ما لایه ها را به صورت جداگانه و دلخواه می سازیم و تنها مسیری را که این لایه ها باید بهم متصل باشند را به یک مدل تبدیل می کنیم.
در این نوشتار از با استفاده از مدل Sequential برای شناسایی اعداد دست نویس خواهیم پرداخت.
سعی شده است که مطالب خلاصه و کاربردی بیان شده است.
فرض بر این است که شما عزیزان با زبان پایتون و مفاهیم یادگیری ماشین آشنا می باشید.
**زبان مورد استفاده : پایتون
**بستر استفاده شده : colab
from keras.datasets import mnist
(train_images,train_labels) ,(test_images,test_labels)= mnist.load_data()
print("tarin:",train_images.shape,"test_images:",test_images.shape)
Downloading data from
https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step 11501568/11490434 [==============================] - 0s 0us/step tarin: (60000, 28, 28) test_images: (10000, 28, 28)
همانطور که مشاهده می کنید دیتا ست مورد نظر به داده های آموزش و تست تقسیم شده که شامل تصاویر به ابعاد 28*28 می باشد.
حال اگر بخواهیم دیتاست را به صورت محلی (یعنی ابتدا دیتاست را دانلود کنیم و سپس آن را از فضای گوگل درایو فراخوانی کنیم) می بایست از دستورات زیر استفاده نمود :
from google.colab import drive
drive.mount('/content/drive')
لینک دانلود دیتا ست Mnist:
بعد از دادن دسترسی های مورد نیاز به colab جهت دسترسی به فضای شخصی شما در گوگل درایو خروجی زیر را می بایست مشاهده کنید:
Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).
data=np.load('/content/drive/My Drive/Colab Notebooks/Keras/mnist.npz')# مسیر را معرفی می کنیم
نکته : در ابتدا سعی کنید هر کتابخانه ای که نیاز دارید فراخوانی کنید.
import numpy as np # استفاده از این کتابخانه در ادامه توضیح داده خواهد شد
import matplotlib.pyplot as plt # از این کتابخانه جهن نمایش تصاویر و نمودارها استفاده خواهیم کرد
from keras.utils import np_utils # ؟؟؟؟؟
بعد از فراخوانی دیتاست بدلیل این که دیتاست به دارای دو قسمت x_train و y_train می باشد آنها را در train_images,train_labels قرار می دهیم تا در روند آموزش به کارگیری گردند همچنین برای داده های تست نیز همین کار را انجا می دهیم.
train_images,train_labels=data['x_train'],np.array(data['y_train'])
test_images,test_labels=data['x_test'],np.array(data['y_test'])
print("tarin:",train_images.shape,"test_images:",test_images.shape)
tarin: (60000, 28, 28) test_images: (10000, 28, 28)
برای نمایش یکی از داده های train یا tset جهت صحت داده های فراخوانی شده با استفاده از کتابخانه matplotlib که قبلا فراخوانی کرده تصویر را مشاهده می کنیم:
digit = train_images[24]# ابتدا تصویر مورد نظررا در یک متغییر تعریف می کنیم
plt.imshow(digit , cmap= 'binary')# cmap انتخاب رنگ پس زمینه
<matplotlib.image.AxesImage at 0x7fc4dd8f2ed0>
پیش پردازش داده در اینجا شامل دو مرحله می باشد :
1- داده های آموزش(train) به صورت تصاویر 28*28 هستند که این تصاویر می بایست به یک ردیف از داده ها تبدیل یعنی به بردار تبدیل شوند.که این کار با استفاده از دستور ()reshape انجام می شود . همین مراحل را برای داده آزمایش (test) نیز انجام می گردد.
2- نرمال سازی داده (مقادیر عکس می بایست بین 0 و 1 باشد )
می توان در دستور reshape(60000,784) مستقیما اندازه بردار راوارد نمود یا به صورت زیر کدها را نوشت تا به صورت اتواتیک تعداد و اندازه بردارها را از داده های آموزش دریافت کند.
# X_train=train_images.reshape(60000,784)
X_train=train_images.reshape(train_images.shape[0],(train_images.shape[1]*train_images.shape[2]))#
X_train.shape
(60000, 784)
# X_test=test_images.reshape(10000,784)
X_test=test_images.reshape(test_images.shape[0],(test_images.shape[1]*test_images.shape[2]))
X_test.shape
(10000, 784)
همانطور که در خروجی مشاهده می کنید داده ها به یک بردار با بعد 784 تبدیل شده است.
مرسوم این است که مقادیر پیکسل تصاویر را بین 0 و 1 کنیم اگر 255 بیشترین مقدار پیکسل هست همه را تقسیم بر 255 بکنیم و اگر بیشترین مقدار پیکسل را نمی دانیم ازکتابخانه نامپای استفاده می کنیم .
#image = image /255
# برای نرمالیزه کردن حتما باید از حالت اینتیجر به فلوت تغییر بدهیم و گرنه ارور دریافت می کنیم
# می خواهیم تایپ های تصاویر را هم مانند هم کنیم مثلا اگر بعضی انوع اینتجر و یا فلوت باشند همه را فلوت می کنیم
X_train=X_train.astype('float32') #(np.float32)
X_test=X_test.astype('float32') #(np.float32)
X_train=X_train/np.max(X_train)#X_train /=255
X_test=X_test/np.max(X_test)#X_test /=255
خوب اکنون باید لیبل ها را به شکل One Hot Encoding تبدیل کنیم زیرا نمی توان از خود عدد در مدل استفاده نمود و چون 10 تا کلاس داریم یک بردار که دارای 10 بعد که همه درایه ها صفر می باشد و تنها در درایه مرتبط یک
یعنی اگر لیبل 5 باشد به صورت : 0000100000
print('train_labels: ',train_labels.shape[0],np.unique(train_labels))
print('test_labels: ',test_labels.shape[0],np.unique(test_labels))
train_labels: 60000 [0 1 2 3 4 5 6 7 8 9]
test_labels: 10000 [0 1 2 3 4 5 6 7 8 9]
از keras.utils برای تبدیل لیبل ها به One Hot Encoding استفاده می کنیم.
from keras.utils import np_utils#
Y_train = np_utils.to_categorical(train_labels)
Y_test = np_utils.to_categorical(test_labels)
print('train_labels[2]:',train_labels[2],'\n','Y_train[2]:',Y_train[2],'\n','\n')
print('test_labels[2]:','\n',test_labels[2],'Y_test[2]:',Y_test[2])
train_labels[2]: 4 Y_train[2]: [0. 0. 0. 0. 1. 0. 0. 0. 0. 0.] test_labels[2]: 1 Y_test[2]: [0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
ما یک مدل Fully Connected Layer (Dense) فراهم می کنیم که ورودیش X-train باشد که با Y_train آموزش می بیند و دست آخر با داده های test مورد ارزیابی قرار می گیرد.
یعنی ورودی ما داری 784 نورن می باشد ما می خواهیم در لایه بعدی 500 نورن و در لایه بعد مثلا 100 نورون و در پایان با 10 نورون خروجی داشته باشیم.
from keras.models import Sequential
from keras.layers import Dense
from tensorflow.keras.optimizers import SGD
from keras.losses import categorical_crossentropy
myModle= Sequential()
myModle.add(Dense(500,activation='relu',input_shape=(784,)))
myModle.add(Dense(100,activation='relu'))
myModle.add(Dense(10,activation='softmax'))
myModle.summary()# نمایش اطلاعات مدل
معمولا از تابع relu به عنوان تابع فعال ساز و در خروجی از تابع softmax استفاده می کنند.
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense (Dense) (None, 500) 392500 dense_1 (Dense) (None, 100) 50100 dense_2 (Dense) (None, 10) 1010 ================================================================= Total params: 443,610 Trainable params: 443,610 Non-trainable params: 0 _________________________________________________________________
تنطیم پارامترهای (optimizer و loss و...) را که مدل برای کامپایل نیاز دارد.
دقت یا accuracy باید به سمت یک یا همان 100% و خطا یا loss به سمت صفر حرکت کند.
myModle.compile(optimizer=SGD(lr=0.001),loss=categorical_crossentropy,metrics=['accuracy'])
/usr/local/lib/python3.7/dist-packages/keras/optimizer_v2/gradient_descent.py:102: UserWarning: The `lr` argument is deprecated, use `learning_rate` instead. super(SGD, self).__init__(name, **kwargs)
پایان مرحله ساخت مدل و شروع آموزش مدل:
nertwork_history = myModle.fit(x=X_train,y=Y_train,batch_size=128, epochs=20)
# بچ سایز تعداد دادهای که در هر دور آموزش وارد مدل می شود که هر چقدر بیشتر باشد دقتش بیشتر می شود و چون تعداد داده های ما زیاد است پس 128 می گیریم.
Epoch 1/20 469/469 [==============================] - 3s 6ms/step - loss: 2.1683 - accuracy: 0.3051 Epoch 2/20 469/469 [==============================] - 3s 6ms/step - loss: 1.8379 - accuracy: 0.6263 Epoch 3/20 469/469 [==============================] - 3s 6ms/step - loss: 1.5086 - accuracy: 0.7388 Epoch 4/20 469/469 [==============================] - 3s 6ms/step - loss: 1.2206 - accuracy: 0.7870 Epoch 5/20 469/469 [==============================] - 3s 6ms/step - loss: 1.0009 - accuracy: 0.8144 Epoch 6/20 469/469 [==============================] - 3s 6ms/step - loss: 0.8459 - accuracy: 0.8321 Epoch 7/20 469/469 [==============================] - 3s 6ms/step - loss: 0.7379 - accuracy: 0.8444 Epoch 8/20 469/469 [==============================] - 3s 6ms/step - loss: 0.6612 - accuracy: 0.8540 Epoch 9/20 469/469 [==============================] - 3s 6ms/step - loss: 0.6046 - accuracy: 0.8611 Epoch 10/20 469/469 [==============================] - 3s 6ms/step - loss: 0.5615 - accuracy: 0.8670 Epoch 11/20 469/469 [==============================] - 3s 7ms/step - loss: 0.5275 - accuracy: 0.8715 Epoch 12/20 469/469 [==============================] - 3s 6ms/step - loss: 0.5000 - accuracy: 0.8752 Epoch 13/20 469/469 [==============================] - 3s 6ms/step - loss: 0.4775 - accuracy: 0.8790 Epoch 14/20 469/469 [==============================] - 3s 6ms/step - loss: 0.4585 - accuracy: 0.8824 Epoch 15/20 469/469 [==============================] - 3s 6ms/step - loss: 0.4424 - accuracy: 0.8851 Epoch 16/20 469/469 [==============================] - 3s 6ms/step - loss: 0.4284 - accuracy: 0.8875 Epoch 17/20 469/469 [==============================] - 3s 6ms/step - loss: 0.4162 - accuracy: 0.8903 Epoch 18/20 469/469 [==============================] - 3s 6ms/step - loss: 0.4053 - accuracy: 0.8920 Epoch 19/20 469/469 [==============================] - 3s 6ms/step - loss: 0.3957 - accuracy: 0.8936 Epoch 20/20 469/469 [==============================] - 3s 6ms/step - loss: 0.3870 - accuracy: 0.8956
نکنته: انتخاب تعداد اپکوک ها کاملا تجربی هست و باید مراقب بود که مدل گرفتار Overfitting و Underfitting نشود.
از متغیر history برای رسم نمودار loss و accuracy برای بررسی آموزش استفاده می گردد.
history = nertwork_history.history# جهت تبدیل به دیکشنری
print('type_nertwork_history :',type(nertwork_history),'\n')
print('type_history :',type(history))
print(history.keys())
type_nertwork_history : <class 'keras.callbacks.History'>
type_history : <class 'dict'>
dict_keys(['loss', 'accuracy'])
جهت نمایش نمودار به شیوه زیر عمل می کنیم:
losses =history['loss']
accuracy =history ['accuracy']
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.plot(losses)
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.plot(accuracy)
حال اگر بخواهیم در نمودار رنگ ها را معرفی کنیم:
fig, ax = plt.subplots()
losses =history['loss']
accuracy =history ['accuracy']
line_up, = ax.plot(losses, label='loss')
line_down, = ax.plot(accuracy, label='accuracy')
ax.legend(handles=[line_up, line_down])
برای نمایش نمودار ها به صورت مستقل:
losses =history['loss']
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.plot(losses)
plt.figure()# جهت نمایش نمودارها به صورت مجزا
accuracy =history ['accuracy']
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.plot(accuracy)
حال بهتر می باشد تمام دستورات نمایش را در یک تابع قرار دهیم تا در هرجایی که دلمان خواست استفاده کنیم
def plot_history(net_history):
history = net_history.history# برای ساخت دیکشنری
accuracy =history ['accuracy']
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.plot(accuracy)
plt.figure()
losses =history['loss']
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.plot(losses)
فراخوانی تابع ایجاد شده:
plot_history(nertwork_history)
می توان داده train را به Valadation نیز تقسیم کنیم و دقت را ارزیابی کنیم و بعد پارامترها را آنقدر تغییر بدهیم تا بهینه ترین آموزش را داشته باشیم. مدل ساخته شده این کار را در ابتدا می توان انجام داد در هنگام فیت کردن مدل به شکل زیر:
nertwork_history2 = myModle.fit(X_train,Y_train,batch_size=128, epochs=20,validation_split=0.2)
Epoch 1/20 375/375 [==============================] - 3s 8ms/step - loss: 2.1928 - accuracy: 0.2387 - val_loss: 2.0489 - val_accuracy: 0.4732 Epoch 2/20 375/375 [==============================] - 3s 9ms/step - loss: 1.9121 - accuracy: 0.5769 - val_loss: 1.7581 - val_accuracy: 0.6754 Epoch 3/20 375/375 [==============================] - 3s 7ms/step - loss: 1.6232 - accuracy: 0.6979 - val_loss: 1.4630 - val_accuracy: 0.7575 Epoch 4/20 375/375 [==============================] - 3s 8ms/step - loss: 1.3513 - accuracy: 0.7565 - val_loss: 1.2078 - val_accuracy: 0.7959 Epoch 5/20 375/375 [==============================] - 3s 7ms/step - loss: 1.1332 - accuracy: 0.7880 - val_loss: 1.0140 - val_accuracy: 0.8188 Epoch 6/20 375/375 [==============================] - 3s 7ms/step - loss: 0.9707 - accuracy: 0.8092 - val_loss: 0.8720 - val_accuracy: 0.8352 Epoch 7/20 375/375 [==============================] - 3s 7ms/step - loss: 0.8511 - accuracy: 0.8231 - val_loss: 0.7671 - val_accuracy: 0.8472 Epoch 8/20 375/375 [==============================] - 3s 8ms/step - loss: 0.7617 - accuracy: 0.8357 - val_loss: 0.6889 - val_accuracy: 0.8560 Epoch 9/20 375/375 [==============================] - 3s 8ms/step - loss: 0.6937 - accuracy: 0.8452 - val_loss: 0.6291 - val_accuracy: 0.8633 Epoch 10/20 375/375 [==============================] - 3s 7ms/step - loss: 0.6407 - accuracy: 0.8521 - val_loss: 0.5824 - val_accuracy: 0.8688 Epoch 11/20 375/375 [==============================] - 3s 7ms/step - loss: 0.5987 - accuracy: 0.8581 - val_loss: 0.5452 - val_accuracy: 0.8726 Epoch 12/20 375/375 [==============================] - 3s 7ms/step - loss: 0.5645 - accuracy: 0.8636 - val_loss: 0.5150 - val_accuracy: 0.8773 Epoch 13/20 375/375 [==============================] - 3s 8ms/step - loss: 0.5362 - accuracy: 0.8676 - val_loss: 0.4900 - val_accuracy: 0.8803 Epoch 14/20 375/375 [==============================] - 3s 7ms/step - loss: 0.5123 - accuracy: 0.8721 - val_loss: 0.4688 - val_accuracy: 0.8836 Epoch 15/20 375/375 [==============================] - 3s 8ms/step - loss: 0.4919 - accuracy: 0.8754 - val_loss: 0.4507 - val_accuracy: 0.8873 Epoch 16/20 375/375 [==============================] - 3s 7ms/step - loss: 0.4743 - accuracy: 0.8784 - val_loss: 0.4351 - val_accuracy: 0.8899 Epoch 17/20 375/375 [==============================] - 3s 7ms/step - loss: 0.4589 - accuracy: 0.8813 - val_loss: 0.4215 - val_accuracy: 0.8928 Epoch 18/20 375/375 [==============================] - 3s 7ms/step - loss: 0.4453 - accuracy: 0.8838 - val_loss: 0.4096 - val_accuracy: 0.8939 Epoch 19/20 375/375 [==============================] - 3s 7ms/step - loss: 0.4332 - accuracy: 0.8864 - val_loss: 0.3989 - val_accuracy: 0.8957 Epoch 20/20 375/375 [==============================] - 3s 8ms/step - loss: 0.4223 - accuracy: 0.8881 - val_loss: 0.3894 - val_accuracy: 0.8970
print(nertwork_history2.history.keys())
dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])
برای نشاند دادن نمودارهای 'val_loss', 'val_accuracy' تابع را به شکل زیر تعریف می کنیم:
def plot_history2(net_history):
history = net_history.history# برای ساخت دیکشنری
#********************
#*****************
fig, ax = plt.subplots()
accuracy =history ['accuracy']
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
line_up, = ax.plot(accuracy, label='accuracy')
if len(history.keys()) > 2 :
accuracy_val =history ['val_accuracy']
line_down, = ax.plot(accuracy_val, label='accuracy_val')
ax.legend(handles=[line_up, line_down])
plt.figure()
fig, ax = plt.subplots()
losses =history['loss']
plt.xlabel('Epochs')
plt.ylabel('Loss')
line_up, = ax.plot(losses , label='loss')
if len(history.keys()) > 2 :
losses_val =history['val_loss']
line_down, = ax.plot(losses_val, label='losses_val')
ax.legend(handles=[line_up, line_down])
plot_history2(nertwork_history2)
OutPut:
ارزیابی مدل ساخته شده با داده tset:
test_loss, test_acc =myModle2.evaluate(X_test, Y_test)
313/313 [==============================] - 1s 2ms/step - loss: 0.4273 - accuracy: 0.8899
test_lable_p = myModle2.predict(X_test)
خروجی 10*1000 هست که بیشترین مقدار از اعداد اعشاری به عنوان کلاس استفاده می شود و حال برای تبدیل کردن لیبل به یک عدد از کتابخانه نامپای استفاده می کنیم:
import numpy as np
test_lable_p = np.argmax(test_lable_p , axis=1,)#
اگر axisرا مساوی با یک قرار می دهیم یعنی فقط اندیکیس (مکان) ماکسیمم مقدار در هر ردیف افقی را بگیر
test_lable_p
array([7, 2, 1, ..., 4, 5, 6])
منابع:
deep learning with python book,FRANÇOIS CHOLLET,
©2018 by Manning Publications Co.,ISBN 9781617294433,
Printed in the United States of America
آموزش یادگیری عمیق : سعید محققی