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

يخلق هذا الاستخدام المفرط للبقايا، إشرافًا عميقًا، لأن كل طبقة تتلقى مزيدًا من الإشراف من وظيفة الفقد بفضل التوصيلات الأقصر.
كتلة كثيفة (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) من:
- تطبيع الدفعة (Batch Normalization)
- 1×1 التفاف (Convolution)
- متوسط التجميع (Average pooling)
معدل النمو (Growth rate)
إن لتسلسل المخلفات بدلاً من جمعها، جانب سلبي عندما يكون النموذج عميقًا جدًا: فهو يولد الكثير من قنوات الإدخال!
قد تتساءل الآن كيف يمكنني القول في المقدمة أن في DenseNet معلمات أقل من شبكات SotA المعتادة. وهناك سببان:
- قبل أي شيئ، ينشئ التفاف DenseNet عددًا منخفضًا من خرائط الميزات. يوصي المؤلفون بـ 32 للحصول على الأداء الأمثل لكنهم أظهروا نتائج SotA مع 12 قناة إخراج (output channels) فقط!
- يتم تعريف عدد خرائط الخصائص المخرجات للطبقة على أنها معدل النمو.
DenseNet بحاجة أقل إلى الطبقات العريضة، لأن في الطبقات متصلة بكثافة يكون هناك القليل من التكرار في الخصائص المكتسبة. تشرك جميع طبقات الكتلة الكثيفة نفسها في معرفة جماعية.
ملاحظة: ينظم معدل النمو مقدار المعلومات الجديدة التي تساهم فيها كل طبقة في الحالة العالمية.
Bottleneck
السبب الثاني لامتلاك DenseNet لمعلمات قليلة على الرغم من ربط العديد من المخلفات معًا، هو أنه يمكن ترقية كل التفاف 3×3 مع bottleneck.
ستكون طبقة الكتلة الكثيفة ذات bottleneck:
- تطبيع الدفعة (Batch Normalization)
- تفعيل ReLU
- إنتاج bottleneck التفاف 1×1: معدل النمو ∗ 4 خرائط خصائص.
- تطبيع الدفعة (Batch Normalization)
- تفعيل ReLU
- 3×3 التفاف (Convolution)
بمعدل نمو 32، سيكون للطبقة العاشرة 288 خريطة خصیصة (feature map)! بفضل bottleneck، سيتم تغذية طبقة على الأكثر من 128 خريطة خصیصة. يساعد هذا الشبكة في الحصول على مئات الطبقات، إن لم يكن ألف طبقة.
ضغط (Compression)
يعمل المؤلفون أيضًا على تحسين انضغاط (compactness) النموذج عن طريق الضغط. يحدث هذا الضغط في الطبقة الانتقالية (transition layer).
عادةً لا يؤدي التفاف الطبقة الانتقالية (transition layer) إلى تغيير عدد خرائط المعالم. في حالة الضغط، يكون عدد خرائط الخصائص المخرجات θ ∗ m. باستخدام m عدد خرائط خصائص الإدخال ويتراوح عامل ضغط (compression factor) بين 0 و 1.
البنیة النهائية لـ DenseNet هي كما يلي:

باختصار، تستخدم بنية 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).

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))

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 بدقة تصل إلى 98٪. يقلل DenseNet من مشكلة التدرج المتلاشي (vanishing gradient)، ويتطلب عددًا أقل من المعلمات لتدريب النموذج. يعتني الانتشار الديناميكي للخصائص بالتدفق السلس للمعلومات.
المصادر
This article is useful for me
1+ 6 People like this post