طريقة عرض النتائج
لكل صورة في مجموعة البيانات، هناك ثلاث صور:
- الصورة الأولية
- الصورة الناتجة عن إضافة ضوضاء للصورة الأصلية
- خرج شبكة التشفير الذاتي بعد تلقي صورة مشوشة
يمكن أن توضح لنا مقارنة هذه الصور الثلاث جنبًا إلى جنب أداء النموذج إلى حد كبير. لذلك، نقوم بإنشاء طريقة أخرى تتلقى مجموعة بيانات الاختبار في نهاية التدريب وترسم هذه الصور الثلاث جنبًا إلى جنب لجميع البيانات:
1. def PlotResults(self, 2. X:np.ndarray, 3. Y:np.ndarray):
في الخطوة الأولى، نحسب ناتج النموذج للمدخلات:
1. def PlotResults(self, 2. X:np.ndarray, 3. Y:np.ndarray): 4. P = self.Predict(X)
لخلط البيانات وإفساد ترتيبها، نحسب أولاً عددهم، ثم ننشئ فهرسهم من 0 إلى رقم البيانات الأخيرة، وأخيرًا نقطعه باستخدام الدالة numpy.random.shuffle:
1. def PlotResults(self, 2. X:np.ndarray, 3. Y:np.ndarray): 4. P = self.Predict(X) 5. nD = X.shape[0] 6. I = np.arange(start=0, stop=nD, step=1) 7. np.random.shuffle(I)
الآن نقوم بإنشاء حلقة فوق المصفوفة I:
1. def PlotResults(self, 2. X:np.ndarray, 3. Y:np.ndarray): 4. P = self.Predict(X) 5. nD = X.shape[0] 6. I = np.arange(start=0, stop=nD, step=1) 7. np.random.shuffle(I) 8. for i in I:
قد لا ينقل رسم الصور فقط معدل التحسين جيدًا، ولهذا السبب نحسب أيضًا الجذر التربيعي للخطأ الطبيعي لكل من الصورة الصاخبة وإخراج الشبكة العصبية فيما يتعلق بالصورة الأصلية:
1. def PlotResults(self, 2. X:np.ndarray, 3. Y:np.ndarray): 4. P = self.Predict(X) 5. nD = X.shape[0] 6. I = np.arange(start=0, stop=nD, step=1) 7. np.random.shuffle(I) 8. for i in I: 9. e1 = 100 * np.power(Y[i] - X[i], 2).mean() ** 0.5 10. e2 = 100 * np.power(Y[i] - P[i], 2).mean() ** 0.5
لاحظ أن قيمة e1 تتأثر فقط بالضوضاء المضافة الأولية وهي مقياسنا لقياس أداء النموذج. يمكن تحسين قيمة e2 وفي أفضل الأحوال ستكون مساوية للصفر، وهو أمر بعيد المنال. لذلك، يمكن أن تظهر e2 أقل من e1 كفاءة الشبكة العصبية ذاتية التشفير، ولكن للحصول على نتائج مقبولة ، يجب أن تكون e2 أقل بكثير من e1.
يمكننا الآن تقسيم الشاشة إلى ثلاثة أجزاء باستخدام matplotlib.pyplot.subplot ورسم صورة في كل جزء:
1. def PlotResults(self, 2. X:np.ndarray, 3. Y:np.ndarray): 4. P = self.Predict(X) 5. nD = X.shape[0] 6. I = np.arange(start=0, stop=nD, step=1) 7. np.random.shuffle(I) 8. for i in I: 9. e1 = 100 * np.power(Y[i] - X[i], 2).mean() ** 0.5 10. e2 = 100 * np.power(Y[i] - P[i], 2).mean() ** 0.5 11. plt.subplot(1, 3, 1) 12. plt.imshow(Y[i], cmap='gray') 13. plt.title('Main Image') 14. plt.xlabel('NRSE: 0 %') 15. plt.subplot(1, 3, 2) 16. plt.imshow(X[i], cmap='gray') 17. plt.xlabel(f'NRSE: {e1:.2f} %') 18. plt.title('Noised Image') 19. plt.subplot(1, 3, 3) 20. plt.imshow(P[i], cmap='gray') 21. plt.xlabel(f'NRSE: {e2:.2f} %') 22. plt.title('Denoised Image') 23. plt.show()
لاحظ أن وصف كل صورة معروض أعلاه باستخدام matplotlib.pyplot.title، حتى نتمكن من عرض خطأ كل صورة بالنسبة للصورة المستهدفة باستخدام matplotlib.pyplot.xlabel. بهذه الطريقة، ستكون هذه الطريقة قادرة على عرض أداء الشبكة العصبية ذات التشفير الذاتي بصريًا وعدديًا.
بهذه الطريقة، ينتهي تنفيذ فئة AEDN وطرقها.
إعدادات البرنامج
ستكون هناك حاجة لمتغيرات أثناء تنفيذ البرنامج، والتي نحددها في بداية استخدام الكود المكتوب:
1. sVa = 0.2 2. nConvolution = [64, 32] 3. RandomState = 0 4. Optimizer = opt.Adam() 5. Loss = los.BinaryCrossentropy() 6. nEpoch = 10 7. sBatch = 128
تحدد هذه المتغيرات ما يلي على التوالي:
- يمثل المتغير sVa مساهمة بيانات التحقق في بيانات التدريب. تعني القيمة 0.2 من هذا المتغير أنه سيتم فصل 20٪ من بيانات التدريب للتحقق من صحتها.
- المتغير nConvolution هو قائمة من الأعداد الصحيحة التي تحدد عدد المرشحات أو نوى الطبقات التلافيفية. سيكون عدد مرشحات طبقة الصورة الملتفة بترتيب الصورة في هذه القائمة.
- المتغير RandomState هو جعل النتائج قابلة للتكرار. إذا كان هذا المتغير بلا، فستكون النتائج مختلفة في كل مرة يتم تنفيذها، ولا يمكن إعادة إنتاج النتائج السابقة؛ ولكن إذا تم تحديد عدد صحيح ، فستكون النتائج قابلة للتكرار.
- متغير Optimizer هو خوارزمية المحسن المستخدمة في تدريب الشبكة العصبية. خوارزميات مختلفة مثل SGD ، RMSprop ، Adadelta ، … توجد أيضًا في مكتبة Keras التي يمكن استخدامها وفقًا لطبيعة المشكلة. تحتوي خوارزمية آدم على المعلمات الثلاثة المهمة التالية التي تحدد سلوكها:
- معدل التعلم، الذي تم تعيينه بواسطة إدخال معدل التعلم وله قيمة افتراضية 0.001.
- معلمة تقدير الزخم الأولية التي يتم تحديدها بواسطة إدخال beta_1 ولها قيمة افتراضية 0.9.
- معلمة تقدير الزخم الثانوية التي يتم تحديدها بواسطة إدخال beta_2 ولها قيمة افتراضية 0.999.
- يحدد متغير loss دالة التكلفة المستخدمة لتدريب النموذج. في هذه المشكلة، نظرًا لأن تشغيل أو إيقاف تشغيل كل بكسل أكثر أهمية من قيمته العددية الدقيقة، فقد تم استخدام دالة تكلفة Binary Crossentropy. لاحظ أنه يتم قياس قيم البكسل بين 0 و 1، ويتم الحصول على ناتج الشبكة العصبية من طبقة تنشيط Sigmoid، والتي ستكون دائمًا بين 0 و 1. إذا كانت هذه الشروط لا تحكم المشكلة، فيمكن استخدام وظائف التكلفة الأخرى مثل متوسط الخطأ التربيعي ومتوسط الخطأ المطلق و Huber.
- سيحدد المتغير nEpoch عدد الخطوات لتدريب النموذج. وفقًا للتجربة والخطأ وتعقيد المشكلة، يمكن تحديد قيمة هذا المتغير.
- يحدد متغير sBatch حجم الدُفعات لتدريب النموذج. عادة ما تستخدم قوى 2 كأحجام دفعات. القيم بين 32 و 256 مقبولة لهذا المتغير.
اتصال بمجموعة البيانات
بعد ضبط الإعدادات، نتصل بمجموعة بيانات MNIST:
1. (trvaY, _), (teY, _) = dt.mnist.load_data()
لاحظ أنه بالنسبة لمشاكل التصنيف العادية، يتم إجراء هذا الاستدعاء على النحو التالي:
1. (trvaX, trvaY), (teX, teY) = dt.mnist.load_data()
في هذا الاستدعاء، يرتبط المتغيران teY و trvaY بتسمية الصور، وهو ما لا نحتاج إليه في هذه المشكلة.
تعديل أبعاد مجموعة البيانات
الهدف من الشبكة هو توقع صور الواقع، حتى نعرف الصور كهدف أو Y. يمكن رؤية أبعاد هاتين المصفوفتين على النحو التالي:
1. print(f'trvaY: {trvaY.shape}') 2. print(f'teY: {teY.shape}')
التي سنحصل عليها بعد الإعدام:
1. trvaY: (60000, 28, 28) 2. teY: (10000, 28, 28)
بهذه الطريقة، نرى أن لدينا صورة 28 × 28. نظرًا لأن الصور بتدرج الرمادي، سيكون لها قناة واحدة فقط، وبالتالي فإن البعد الرابع لهذه المصفوفة هو 1، والذي تم حذفه. تحتوي مجموعة بيانات التدريب والتحقق من الصحة على إجمالي 60.000 صورة وتحتوي مجموعة بيانات الاختبار على 10000 صورة. لإضافة بُعد رابع إلى مجموعة البيانات، نستخدم الدالة numpy.expand_dims:
1. trvaY = np.expand_dims(trvaY, axis=-1) 2. teY = np.expand_dims(teY, axis=-1)
بعد هذا الرمز، ستكون أبعاد مجموعة البيانات كما يلي:
1. trvaY: (60000, 28, 28, 1) 2. teY: (10000, 28, 28, 1)
لذلك، تصل مجموعة البيانات إلى الأبعاد المطلوبة.
تعديل مقياس مجموعة البيانات
قيم البكسل هي أرقام بين 0 و 255. للتحقق من هذه القيم، يمكنك القيام بما يلي:
1. print(f'Min: {trvaY.min()}') 2. print(f'Max: {trvaY.max()}')
ستكون النتائج على النحو التالي:
1. Min: 0 2. Max: 255
لقياس هذه القيم بين 0 و 1، نقسمها على 255:
1. trvaY = trvaY / 255 2. teY = teY / 255
بعد تطبيق الكود أعلاه، ستكون القيم القصوى والدنيا كما يلي:
1. Min: 0.0 2. Max: 1.0
لذلك، يتم نقل القيم إلى النطاق المطلوب.
تعديل نوع قيم مجموعة البيانات
قيم مجموعة البيانات هي من النوع float64. يمكن فهم هذا كالتالي:
print(f'dtype: {trvaY.dtype}')
الذي سيكون لدينا:
dtype: float64
لا تعتبر هذه الحالة وحدها مشكلة خاصة، ولكن نظرًا لأننا نستخدم مجموعة بيانات الصورة ، فإن النوع float64 يشغل مساحة أكبر في ذاكرة الوصول العشوائي أو ذاكرة الوصول العشوائي. يمكننا خفض الحجم المشغول إلى النصف عن طريق تغيير نوع مجموعة البيانات من float64 إلى float32 ورؤية تغييرات طفيفة جدًا في قيم البكسل. لهذا الغرض، نطبق الكود التالي:
trvaY = trvaY.astype('float32') teY = teY.astype('float32')
بعد تنفيذ الكود أعلاه، نتحقق من نوع مجموعة البيانات مرة أخرى، سيكون لدينا:
dtype: float32
للتحقق من التغييرات في حجم مجموعة البيانات نتيجة لهذه التغييرات، يمكن تنفيذ مقتطف الشفرة التالي قبل تغيير الجنس وبعده:
print(f'trvaY Size: {trvaY.size * trvaY.itemsize}')
يوضح هذا الرمز قيمة 376320000 بايت قبل تغيير الجنس. بعد تغيير الجنس، ينخفض هذا الرقم إلى النصف ويتغير إلى 188160000 بايت. لاحظ أن هذه العملية توفر 188.16 ميغا بايت. لاحظ أن حجم السمة المسماة لمصفوفات Numpy يُظهر عدد الأعضاء والأدلة الخاصة بتلك المصفوفة. تُظهر السمة التالية المسماة itemsize حجم المساحة التي يشغلها كل دليل من المصفوفة. من الواضح أن حاصل ضرب هذين الرقمين سيُظهر المساحة الإجمالية التي تشغلها المصفوفة بأكملها.
This article is useful for me
1+ 0 People like this post