مقدمة إلى DenseNet وتنفيذه في Keras

DenseNet وتنفيذه في Keras

DenseNet واحدة من الاكتشافات الجديدة في الشبكات العصبية للتعرف البصري على الأشياء (visual object recognition). يشبه DenseNet إلى حد بعيد ResNet مع بعض الاختلافات الأساسية. تستخدم ResNet طريقة مضافة (+) تدمج الطبقة السابقة (الهوية (identity)) مع الطبقة المستقبلية، بينما تقوم DenseNet بربط (.) إخراج الطبقة السابقة مع الطبقة المستقبلية. تم تطوير DenseNet خصيصًا لتحسين الدقة المرفوضة الناتجة عن التدرج المتلاشي (vanishing gradient) في الشبكات العصبية عالية المستوى (high-level neural networks). بعبارات أبسط، نظرًا لطول المسار بين طبقة الإدخال وطبقة الإخراج، تختفي المعلومات قبل الوصول إلى وجهتها.

بنیة العامة لخوارزمیة DenseNet

يتكون DenseNet من كتل كثيفة (Dense blocks). ترتبط الطبقات في هذه الكتل، معاً بكثافة: تتلقى كل طبقة في الإدخال جميع خرائط خصائص الإخراج السابقة للطبقات.

خوارزمیة DenseNet

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

كتلة كثيفة (Dense block)

الكتلة الكثيفة (dense block)، هي مجموعة من الطبقات المتصلة بجميع طبقاتها السابقة. تبدو طبقة واحدة كما يلي:

  • تطبيع الدفعة (Batch Normalization)
  • تفعيل ReLU (ReLU activation)
  • التفاف (Convolution) 3×3

وجد المؤلفون أن وضع التفعیل المسبق (pre-activation) (BN و ReLU قبل Conv) كان أكثر كفاءة من وضع التفعیل اللاحق (post-activation).

لاحظ أن المؤلفون يوصون بحشو صفري (zero padding) قبل الالتفاف (convolution) من أجل الحصول على حجم ثابت.

الطبقة الانتقالية (Transition layer)

تقوم DenseNet بتجميع جميع خرائط الخصائص (feature maps)، بدلاً من جمع المتبقي كما هو الحال في ResNet.

سيكون غير قابل للتنفيذ تجميع خرائط الخصائص بأحجام مختلفة (على الرغم من أن بعض عمليات تغيير الحجم قد تنفّذ). وبالتالي، في كل كتلة كثيفة (dense block)، يكون لخرائط الخصائص نفس الحجم لكل طبقة.

ومع ذلك، فإن down-sampling يعد أمرا ضروريا لشبكة CNN. إذ تضمن الطبقات الانتقالية (Transition layers) بين كتلتين كثيفتين هذا الدور.

تتكون الطبقة الانتقالية (transition layer) من:

  1. تطبيع الدفعة (Batch Normalization)
  2. 1×1 التفاف (Convolution)
  3. متوسط التجميع (Average pooling)

معدل النمو (Growth rate)

إن لتسلسل المخلفات بدلاً من جمعها، جانب سلبي عندما يكون النموذج عميقًا جدًا: فهو يولد الكثير من قنوات الإدخال!

قد تتساءل الآن كيف يمكنني القول في المقدمة أن في DenseNet معلمات أقل من شبكات SotA المعتادة. وهناك سببان:

  1. قبل أي شيئ، ينشئ التفاف DenseNet عددًا منخفضًا من خرائط الميزات. يوصي المؤلفون بـ 32 للحصول على الأداء الأمثل لكنهم أظهروا نتائج SotA مع 12 قناة إخراج (output channels) فقط!
  2. يتم تعريف عدد خرائط الخصائص المخرجات للطبقة على أنها معدل النمو.

DenseNet بحاجة أقل إلى الطبقات العريضة، لأن في الطبقات متصلة بكثافة يكون هناك القليل من التكرار في الخصائص المكتسبة. تشرك جميع طبقات الكتلة الكثيفة نفسها في معرفة جماعية.

ملاحظة: ينظم معدل النمو مقدار المعلومات الجديدة التي تساهم فيها كل طبقة في الحالة العالمية.

Bottleneck

السبب الثاني لامتلاك DenseNet لمعلمات قليلة على الرغم من ربط العديد من المخلفات معًا، هو أنه يمكن ترقية كل التفاف 3×3 مع bottleneck.

ستكون طبقة الكتلة الكثيفة ذات bottleneck:

  1. تطبيع الدفعة (Batch Normalization)
  2. تفعيل ReLU
  3. إنتاج bottleneck التفاف 1×1: معدل النمو ∗ 4 خرائط خصائص.
  4. تطبيع الدفعة (Batch Normalization)
  5. تفعيل ReLU
  6. 3×3 التفاف (Convolution)

بمعدل نمو 32، سيكون للطبقة العاشرة 288 خريطة خصیصة (feature map)! بفضل bottleneck، سيتم تغذية طبقة على الأكثر من 128 خريطة خصیصة. يساعد هذا الشبكة في الحصول على مئات الطبقات، إن لم يكن ألف طبقة.

ضغط (Compression)

يعمل المؤلفون أيضًا على تحسين انضغاط (compactness) النموذج عن طريق الضغط. يحدث هذا الضغط في الطبقة الانتقالية (transition layer).

عادةً لا يؤدي التفاف الطبقة الانتقالية (transition layer) إلى تغيير عدد خرائط المعالم. في حالة الضغط، يكون عدد خرائط الخصائص المخرجات θ ∗ m. باستخدام m عدد خرائط خصائص الإدخال ويتراوح عامل ضغط (compression factor) بين 0 و 1.

البنیة النهائية لـ DenseNet هي كما يلي:

DenseNet وتنفيذه في Keras

باختصار، تستخدم بنية DenseNet الآلية المتبقية إلى أقصى حد لها عن طريق جعل كل طبقة (من نفس الكتلة الكثيفة) تتصل بطبقاتها اللاحقة.

يجعل تماسك هذا النموذج الخصائص المكتسبة غير زائدة عن الحاجة، إذ يتم مشاركتها جميعًا من خلال معرفة عامة.

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

تنفيذ DenseNet في keras

قبل البدء، من الضروري استيراد جميع المكتبات ذات الصلة. الدوافع الرئيسية هنا هي tensorflow.keras.applications لاستيراد DenseNet121 و tensorflow.keras.layer لاستيراد الطبقات المشاركة في بناء الشبكة.

import tensorflow 

import pandas as pd
import numpy as np
import os
import keras
import random
import cv2
import math
import seaborn as sns

from sklearn.metrics import confusion_matrix
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split

import matplotlib.pyplot as plt

from tensorflow.keras.layers import Dense,GlobalAveragePooling2D,Convolution2D,BatchNormalization
from tensorflow.keras.layers import Flatten,MaxPooling2D,Dropout

from tensorflow.keras.applications import DenseNet121
from tensorflow.keras.applications.densenet import preprocess_input

from tensorflow.keras.preprocessing import image
from tensorflow.keras.preprocessing.image import ImageDataGenerator,img_to_array

from tensorflow.keras.models import Model

from tensorflow.keras.optimizers import Adam

from tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau

import warnings
warnings.filterwarnings("ignore")
print("Tensorflow-version:", tensorflow.__version__)

الإخراج:

Tensorflow-version: 2.0.0
model_d=DenseNet121(weights='imagenet',include_top=False, input_shape=(128, 128, 3)) 

x=model_d.output

x= GlobalAveragePooling2D()(x)
x= BatchNormalization()(x)
x= Dropout(0.5)(x)
x= Dense(1024,activation='relu')(x) 
x= Dense(512,activation='relu')(x) 
x= BatchNormalization()(x)
x= Dropout(0.5)(x)

preds=Dense(8,activation='softmax')(x) #FC-layer
model=Model(inputs=base_model.input,outputs=preds)
model.summary()

الإخراج:

لتجنب مشكلة overfitting، تجنب تدريب الشبكة تماماً. سيؤدي layer.trainable = False إلى تجميد كل الطبقات، مع الاحتفاظ فقط بالطبقات الثمانية الأخيرة (FC) لاكتشاف الحواف والنقط في الصورة. بمجرد أن يتم تركيب النموذج جيدًا، يمكن ضبطه باستخدام layer.trainable = True.

for layer in model.layers[:-8]:
    layer.trainable=False
    
for layer in model.layers[-8:]:
    layer.trainable=True
model.compile(optimizer='Adam',loss='categorical_crossentropy',metrics=['accuracy'])
model.summary()

لاحظ الانخفاض في المعلمات (parameters).

DenseNet وتنفيذه في Keras
data=[]
labels=[]
random.seed(42)
imagePaths = sorted(list(os.listdir("../input/natural-images/")))
random.shuffle(imagePaths)
print(imagePaths)

for img in imagePaths:
    path=sorted(list(os.listdir("../input/natural-images/"+img)))
    for i in path:
        image = cv2.imread("../input/natural-images/"+img+'/'+i)
        image = cv2.resize(image, (128,128))
        image = img_to_array(image)
        data.append(image)
        l = label = img
        labels.append(l)

data = np.array(data, dtype="float32") / 255.0
labels = np.array(labels)
mlb = LabelBinarizer()
labels = mlb.fit_transform(labels)
print(labels[0])

الإخراج:

(xtrain,xtest,ytrain,ytest)=train_test_split(data,labels,test_size=0.4,random_state=42)
print(xtrain.shape, xtest.shape)

إذا لم يلاحظ النموذج أي تغيير في تکلفة التحقق (validation loss)، فإن دالة ReduceLROnPlateau ستقلل من معدل التعلم (learning rate)، الذي غالبًا ما يفيد النموذج. تقوم وظيفة ImageDataGenerator بتنفيذ زيادة البيانات في الوقت الحالي على مجموعات بيانات صورة المُوَتِّر (tensor) التي تم إنشاؤها في حلقة.

anne = ReduceLROnPlateau(monitor='val_accuracy', factor=0.5, patience=5, verbose=1, min_lr=1e-3)
checkpoint = ModelCheckpoint('model.h5', verbose=1, save_best_only=True)

datagen = ImageDataGenerator(zoom_range = 0.2, horizontal_flip=True, shear_range=0.2)


datagen.fit(xtrain)
# Fits-the-model
history = model.fit_generator(datagen.flow(xtrain, ytrain, batch_size=128),
               steps_per_epoch=xtrain.shape[0] //128,
               epochs=50,
               verbose=2,
               callbacks=[anne, checkpoint],
               validation_data=(xtrain, ytrain))
DenseNet وتنفيذه في Keras
ypred = model.predict(xtest)

total = 0
accurate = 0
accurateindex = []
wrongindex = []

for i in range(len(ypred)):
    if np.argmax(ypred[i]) == np.argmax(ytest[i]):
        accurate += 1
        accurateindex.append(i)
    else:
        wrongindex.append(i)
        
    total += 1
    
print('Total-test-data;', total, '\taccurately-predicted-data:', accurate, '\t wrongly-predicted-data: ', total - accurate)
print('Accuracy:', round(accurate/total*100, 3), '%')

label=['dog', 'flower', 'motorbike', 'person', 'cat', 'fruit', 'airplane', 'car']
imidx = random.sample(accurateindex, k=9)# replace with 'wrongindex'

nrows = 3
ncols = 3
fig, ax = plt.subplots(nrows,ncols,sharex=True,sharey=True,figsize=(15, 12))

n = 0
for row in range(nrows):
    for col in range(ncols):
            ax[row,col].imshow(xtest[imidx[n]])
            ax[row,col].set_title("Predicted label :{}\nTrue label :{}".format(label[np.argmax(ypred[imidx[n]])], label[np.argmax(ytest[imidx[n]])]))
            n += 1
Ypred = model.predict(xtest)

Ypred = np.argmax(Ypred, axis=1)
Ytrue = np.argmax(ytest, axis=1)

cm = confusion_matrix(Ytrue, Ypred)
plt.figure(figsize=(12, 12))
ax = sns.heatmap(cm, cmap="rocket_r", fmt=".01f",annot_kws={'size':16}, annot=True, square=True, xticklabels=label, yticklabels=label)
ax.set_ylabel('Actual', fontsize=20)
ax.set_xlabel('Predicted', fontsize=20)
DenseNet وتنفيذه في Keras

الاستنتاج

لقد قمنا ببناء نموذج DenseNet بدقة تصل إلى 98٪. يقلل DenseNet من مشكلة التدرج المتلاشي (vanishing gradient)، ويتطلب عددًا أقل من المعلمات لتدريب النموذج. يعتني الانتشار الديناميكي للخصائص بالتدفق السلس للمعلومات.

المصادر

الأول
الثاني

منشور ذات صلة
مزايا وعيوب Web 3 5 Minutes

مزايا وعيوب Web 3

هدى عكرش

ويب 3، على الرغم من كل المزايا، لا يزال يواجه العديد من العيوب. يمكن اعتبار معظم هذه المشكلات مشابهة للمشكلات العامة للعملات الرقمية.

المصنف بایز الساذج 4 Minutes

المصنف بایز الساذج

حسن خنفري

يعتمد المصنف بايز الساذج (Naive Bayes classifier) على نظرية بايز مع افتراضات الاستقلال بين المتنبئين. […]

السلة