مقدمة إلى 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

يخلق هذا الاستخدام المفرط للبقايا إشرافًا عميقًا لأن كل طبقة تتلقى مزيدًا تحت الإشراف من دالة التکلفة (loss function) بفضل التوصيلات الأقصر.

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

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

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

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

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

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

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

سيكون من غير العملي تجميع خرائط الخصائص بأحجام مختلفة (على الرغم من أن بعض عمليات تغيير الحجم قد تعمل). وبالتالي، في كل كتلة كثيفة (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 بتنفيذ زيادة البيانات في الوقت الفعلي على مجموعات بيانات صورة الموتر التي تم إنشاؤها في حلقة.

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)، ويتطلب عددًا أقل من المعلمات لتدريب النموذج. يعتني الانتشار الديناميكي للخصائص بالتدفق السلس للمعلومات.

المصادر

الأول
الثاني

منشور ذات صلة
التعلم العميق 10 Minutes

شرح التعلم العميق (Deep Learning) وأهم الخوارزميات الشائعة

حسن خنفري

التعلم العميق هو تقنية أساسية وراء السيارات ذاتية القيادة، مما يمكّنها من التعرف على علامة التوقف، أو تمييز المشاة عن عمود الإنارة. إنه مفتاح التحكم الصوتي في الأجهزة الاستهلاكية مثل الهواتف والأجهزة اللوحية والخ

السلة