كيفية بناء الشبكة العصبية Neural Networks في أبسط صورة بلغة Python

227

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

تتكون الشبكات العصبية من:

  • طبقة المدخلات، x: هذه هي الطبقة الأولى في الشبكة العصبية. تأخذ المدخلات وتمررها إلى الطبقة التالية. لا يتم تطبيق أي عمليات على المدخلات في هذه الطبقة وليس لها قيم الأوزان والتحيزات. في شبكتنا لدينا 3 من المدخلات x1، x2،x3.
  • الطبقات المخفية: تحتوي الطبقات المخفية على خلايا عصبية (nodes) تقوم بتطبيق تحويلات مختلفة على المدخلات.
  • طبقة مخرجات، ŷ: هذه الطبقة هي الطبقة الأخيرة في الشبكة وتتلقى الناتج من الطبقة المخفية الأخيرة. مع هذه الطبقة، يمكننا الحصول الناتج النهائي. في هذه الشبكة لدينا ناتج واحد فقط ŷ.
  • الأوزان والتحيزات بين كل طبقة، W وb: الأوزان تمثل مدى قوة تأثير الخلايا العصبية على بعضها البعض. إذا كان الوزن من الخلية 1 إلى الخلية 2 كبير، فهذا يعني أن الخلية العصبية 1 لها تأثير أكبر على الخلية العصبية 2. أما التحيزات هي مدخل إضافي للخلايا العصبية وهو دائمًا 1، وله تأثير مباشر على الأوزان.
  • وظيفة التنشيط، σ: يتم استخدام وظائف التنشيط لإدخال مبدأ انعدام الخطية إلى الشبكات العصبية. تقوم وظيفة التنشيط السيني-التي سنستخدمها في هذا المقال- بضبط القيم في نطاق من 0 إلى 1. هناك العديد من وظائف التنشيط المستخدمة في الشبكات العصبية مثل ReLU وSeLU وTanH. للمعرفة أكثر عن وظيفة التنشيط من هنا.

يوضح الرسم البياني أدناه بنية شبكة عصبية من طبقتين (لاحظ أن طبقة المدخلات عادة ما يتم استبعادها عند حساب عدد الطبقات في الشبكة العصبية)

إنشاء شبكة العصبية في الواقع أمر سهل.

class NeuralNetwork:
    def __init__(self, x, y):
        self.input      = x
        self.weights1   = np.random.rand(self.input.shape[1],4) 
        self.weights2   = np.random.rand(4,1)                 
        self.y          = y
        self.output     = np.zeros(y.shape)

 

تدريب الشبكة العصبية

إن الناتج عن شبكة عصبية بسيطة من طبقتين ŷ هو:

في المعادلة أعلاه، الأوزان W والتحيزات b هي المتغيرات التي تؤثر على الناتج ŷ بشكل قاطع.

بطبيعة الحال، تحديد القيم الصحيحة للأوزان W والتحيزات b يزيد من القدرة على القيام بالتنبؤات الدقيقة. وتعرف هذه عملية بتدريب الشبكة العصبية.

تتمحور عملية التدريب حول تكرار الخطوات التالية:

  • حساب الناتج المتوقع ŷ، والمعروف باسم feedforward “الانتشار للأمام”
  • تحديث الأوزان والتحيزات، والمعروفة باسم backpropagation ” الانتشار العكسي”

يوضح الرسم التتابعي أدناه عملية الاخذ والرد.

 

Feedforward “الانتشار للأمام”

كما رأينا في الرسم البياني أعلاه، فإن feedforward هو مجرد حساب الناتج لكل خلية عصبية في الشبكة عصبية في كل مرة، وبما أن ناتج الشبكة العصبية هو:

لذلك دعنا نضيف وظيفة feedforward، مع افتراض أن التحيز b=0 للتبسيط في البداية.

 

class NeuralNetwork:
    def __init__(self, x, y):
        self.input      = x
        self.weights1   = np.random.rand(self.input.shape[1],4) 
        self.weights2   = np.random.rand(4,1)                 
        self.y          = y
        self.output     = np.zeros(self.y.shape)

    def feedforward(self):
        self.layer1 = sigmoid(np.dot(self.input, self.weights1))
        self.output = sigmoid(np.dot(self.layer1, self.weights2))

ومع ذلك، ما زلنا بحاجة إلى طريقة لتقييم “جودة” تنبؤاتنا وهذا ما ستسمح لنا وظيفة حساب التكلفة بفعله.

 

وظيفة حساب التكلفة

هناك العديد من وظائف حساب التكلفة المتاحة، من اجل اختيار وظيفة حساب التكلفة المناسبة يجب أن تحدد طبيعة مشكلتك. في هذا المقال، سنستخدم جمع تربيع الأخطاء “SSE” كوظيفة حساب التكلفة.

SSE هو ببساطة مجموع الفارق بين كل من القيمة المتوقعة والقيمة الفعلية. ونحصل على تربيع الفارق حتى نقيس القيمة المطلقة لهذا الفارق. هدفنا في التدريب هو العثور على أفضل مجموعة من الأوزان والتحيزات التي تعطي أقل تكلفة.

 

Backpropagation ” الانتشار العكسي”

الآن بعد أن أدركنا مدى الخطأ في تنبؤنا (التكلفة)، نحتاج إلى إيجاد طريقة لتصحيح هذا الخطأ، وذلك عن طريق تحديث الأوزان والتحيزات. ولكن من أجل معرفة القيمة المناسبة لضبط الأوزان والتحيزات، نحتاج إلى معرفة المشتق من وظيفة حساب التكلفة فيما يتعلق بالأوزان والتحيزات.

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

إذا كان لدينا المشتق، يمكننا ببساطة تحديث الأوزان والتحيزات من خلال زيادتها / تقليلها. هذا هو المعروف باسم الانحدار المتدرج.

ومع ذلك، لا يمكننا حساب مشتق دالة التكلفة مباشرة فيما يتعلق بالأوزان والتحيزات لأن معادلة وظيفة حساب التكلفة لا تحتوي على أي من الأوزان والتحيزات. لذلك، نحتاج إلى قاعدة متسلسلة لتساعدنا في حسابها.

قاعدة متسلسلة لحساب مشتق من وظيفة حساب التكلفة فيما يتعلق الأوزان. لاحظ أنه قمنا بعرض المشتق الجزئي فقط بافتراض شبكة عصبية من طبقة واحدة للتبسيط.

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

والآن بعد أن أصبح لدينا ذلك، نقوم بإضافة وظيفة backpropagation.

class NeuralNetwork:
    def __init__(self, x, y):
        self.input      = x
        self.weights1   = np.random.rand(self.input.shape[1],4) 
        self.weights2   = np.random.rand(4,1)                 
        self.y          = y
        self.output     = np.zeros(self.y.shape)

    def feedforward(self):
        self.layer1 = sigmoid(np.dot(self.input, self.weights1))
        self.output = sigmoid(np.dot(self.layer1, self.weights2))

    def backprop(self):
        # application of the chain rule to find derivative of the loss function with respect to weights2 and weights1
        d_weights2 = np.dot(self.layer1.T, (2*(self.y - self.output) * sigmoid_derivative(self.output)))
        d_weights1 = np.dot(self.input.T,  (np.dot(2*(self.y - self.output) * sigmoid_derivative(self.output), self.weights2.T) * sigmoid_derivative(self.layer1)))

        # update the weights with the derivative (slope) of the loss function
        self.weights1 += d_weights1
        self.weights2 += d_weights2

 

وضع كل ذلك معا

دعنا نطبق شبكتنا العصبية على مثال ونرى مدى نجاحه.

يجب أن تتعلم شبكتنا العصبية كيفية الوصول الى المجموعة المثالية من الأوزان. لاحظ أنه ليس من الأمور السهلة أن نحدد الأوزان من خلال الفحص البيانات فقط.

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

دعونا ننظر إلى التنبؤ النهائي (المخرجات).

لقد فعلناها! قامت خوارزمياتنا بتدريب الشبكة العصبية بنجاح وتراوحت التقديرات حول القيم الحقيقية.

لاحظ أن هناك اختلافًا طفيفًا بين التوقعات والقيم الفعلية. هذا أمر مرغوب فيه، لأنه يمنع overfitting ويسمح للشبكة العصبية بالتعميم بشكل أفضل.

 

المصدر:(How to build your own Neural Network from scratch)

تعليقات