In [ ]:
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

In [ ]:
#@title MIT License
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

أساسيّات التّصنيف: تصنيف صور الملابس

Note: قامت مجموعة المتطوعين في مشروع Tensorflow بترجمة هذا المحتوى. نظرًا لأن هذه الترجمات تعتمد على قاعدة أقصى الجهد (best-effort) ، فلا نضمن أنها انعكاس دقيق وحديث [للمحتوى الرسمي باللغة الإنجليزية](https://www.tensorflow.org/?hl=en). إذا كانت لديك اقتراحات لتحسين هذه الترجمة ، يرجى إرسال "Pull request" إلى مشروع [tensorflow/docs-l10n](https://github.com/tensorflow/docs-l10n). للتطوع أو مراجعة ترجمات المجموعة يرجى ارسال ايميل إلى docs@tensorflow.org.
نقوم في هذا الدّليل بتدريب نموذج شبكة عصبيّة لتصنيف الملابس، مثل الأحذية الرياضية و القمصان. لابأس إن لم تفهم كلّ التّفاصيل، فهذا درس تفاعليّ ذو نسق سريع يعطي نظرة عامّة عن كيفية اِستعمال Tensorflow في برنامج كامل و ستتوضّح التفاصيل أثناء تقدّمك. يستخدم هذا الدليل واجهة برمجة التطبيقات [tf.keras](https://www.tensorflow.org/guide/keras)، و هي واجهة برمجة (API) عالية المستوى تمكّن من بناء و تدريب النماذج في Tensorflow بسهولة.

In [ ]:
# TensorFlow and tf.keras
import tensorflow as tf
from tensorflow import keras

# Helper libraries
import numpy as np
import matplotlib.pyplot as plt

print(tf.__version__)

حمّل مجموعة بيانات Fashion MNIST

يستخدم هذا الدّليل مجموعة بيانات [Fashion MNIST](https://github.com/zalandoresearch/fashion-mnist) (أي MNIST الموضة). و هي مجموعة بيانات تحتوى على 70000 صورة ذات تدرّج رمادي (greyscale images). تنقسم الصّور إلى 10 أنواع من الملابس، سننظر فيها لاحقا. تظهر كل صورة نوعا واحدًا من الملابس بدقّة منخفضة (28 × 28 بكسل)، كما هو موضّح هنا:
Figure 1. Fashion-MNIST أمثلة من (by Zalando, MIT License).
 
تمّ تصميم Fashion MNIST لتكون بديلا مباشرا لمجموعة البيانات الكلاسيكية [MNIST](http://yann.lecun.com/exdb/mnist/) و التّي تعتبر المثال الأوّل، أو مثال "مرحبا يا عالم" ("Hello, word") لبرامج تعلّم الآلة في مجال رؤية الكمبيوتر. و تحتوى مجموعة بيانات MNIST على صور للأعداد من 0 إلى 9 مكتوبة بخط اليد من قِبَلِ العديد من الأشخاص حيث أنّ تنسيق الصور فيها مماثل لتنسيق الصور الموجودة في Fashion MNIST و التّي سنستخدمها في هذا الدّرس. يستخدم هذا الدّليل Fashion MNIST لتنويع الأمثلة للمتعلّم، و لأنّ تصنيف الملابس هي مشكلة أكثر تحدّيا قليلا من مشكلة تصنيف الأرقام الموجودة في مجموعة بيانات MNIST الكلاسيكية. كِلتا مجموعتي البيانات صغيرتان نسبيًّا و يتمّ اِستخدمهما في الغالب للتحقّق من أنّ أيّ خوارزميّة بصدد التطوير تعمل كما هو متوقّع. فهما إذن نقطتا إنطلاق جيّدتان لاختبار البرامج و تصحيحها. في التّالي، سنستخدم 60000 صورة لتدريب الشبكة العصبيّة و 10000 صورة لتقييم مدى دقّة الشبكة في تصنيف الصّور. يمكنك الوصول الى مجموعة بيانات Fashion MNIST مباشرة من Tensorflow. يمكنك القيام بذلك عن طريق استيراد و تحميل بيانات Fashion MNIST من Tensorflow كالتّالي:

In [ ]:
fashion_mnist = keras.datasets.fashion_mnist

(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
عمليّة تحميل البيانات السّابقة تُرجع أربعة صفائف NumPy: * تُكوِّن الصفيفتان `train_images` و `train_labels` مجموعة بيانات التّدريب (training set). أي البيانات التّي سيستخدمها النّموذج للتعلّم. * بعد التّدريب، يتمّ اختبار النموذج باستعمال **مجموعة الاختبار** (test set) و هي تتكوّن من الصفيفتان `test_images` و `test_labels`. بعد تحميلها في الذّاكرة، ستكون الصّور متمثّلة في صفائف NumPy، أي NumPy arrays، ذات أبعاد 28x28، حيث ستكون قيمة كل بكسل عدَدًا طبيعيّا بين 0 و 255. بينما تكون التسميات (labels) متمثلة في صفيفة متكوّنة من أعداد صحيحة طبيعية تكون قيمة كل منها بين 0 و 9. يتوافق كلّ عدد مع *فئة* الملابس التّي تمثّلها الصورة:
Label Class Arabic Class
0 T-shirt/top تي شيرت
1 Trouser سِرْوال
2 Pullover كنزة صوفية
3 Dress فستان
4 Coat معطف
5 Sandal صندل
6 Shirt قميص
7 Sneaker حذاء رياضي
8 Bag حقيبة
9 Ankle boot حذاء الكاحل
يتمّ تعيين تسمية واحدة لكلّ صورة. بما أنّ *أسماء الفئات* (class names) لن تُضَمّنَ في مجموعة البيانات، سنقوم بتخزينها في المتغيّر (variable) المسمّى `class_names` حتّى نتمكّن من إستخدامها لاحقا عند رسم النتائج أو البيانات أو الصّور:

In [ ]:
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

استكشف البيانات

لنبدأ أوّلا باستكشاف شكل البيانات قبل القيام بتدريب النّموذج. في التّالي يمكننا أنّ نرى أنّ مجموعة بيانات التّدريب الموجودة في المتغيّر `train_images` تحتوى على 60000 صورة، حيث أنّ كلّ صورة متمثّلة في 28 × 28 بكسل:

In [ ]:
train_images.shape
و بطريقة مماثلة، يبلغ عدد التّسميات (labels) في مجموعة التّدريب 60000 و هي موجودة في المتغيّر `train_labels` :

In [ ]:
len(train_labels)
كل تسمية هي عدد صحيح طبيعي قيمته بين 0 و 9:

In [ ]:
train_labels
هناك 10000 صورة في مجموعة الإختبار (test set). هنا أيضا، كلّ صورة متمثّلة في 28 × 28 بكسل:

In [ ]:
test_images.shape
و تحتوى مجموعة الإختبار، أيضا، على 10000 تسمية:

In [ ]:
len(test_labels)

معالجة البيانات

يجب معالجة البيانات مسبقًا قبل القيام بتدريب نموذج الشبكة العصبيّة. إذا قمنا بفحص الصّورة الأولى في مجموعة التّدريب، سنرى أنّ قيمة كلّ بكسل هي بين 0 و 255:

In [ ]:
plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
plt.show()
خفّض قيمة البكسلات من نطاقها الحاليّ من 0 إلى 255 إلي النّطاق من 0 إلى 1 قبل استخدمها لتدريب النّموذج. للقيام بذلك، قم بقسمة كلّ القيم على أكبر عدد في النّطاق الأوّل وهو 255. من المهمّ معالجة *مجموعة التّدريب* و *مجموعة الإختبار* بنفس الطّريقة:

In [ ]:
train_images = train_images / 255.0

test_images = test_images / 255.0
للتأكّد من أنّ البيانات بالتّنسيق الصحيح و أنّنا جاهزون للبدء ببناء و تدريب الشبكة العصبيّة، فلنعرض أوّل 25 صورة من *مجموعة التّدريب* و نعرض إسم كلّ فئة تحت الصورة.

In [ ]:
plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(train_images[i], cmap=plt.cm.binary)
    plt.xlabel(class_names[train_labels[i]])
plt.show()

بناء النّموذج

يتطلّب بناء الشبكة العصبيّة تعديل معلمات (parameters) طبقات النموذج، ثمّ تجميعه (compile the model).
### تعديل طبقات النّموذج تمثّل *الطّبقة* (layer) اللّبنة الأساسية لبناء الشبكة العصبيّة. تقوم الطبقات باستخراج التمثيلات (representations) من البيانات التّي يتمّ إدخالها فيها. مع أمل أن تكون هذه التمثيلات ذات معنى مساعد على حلّ المشكلة المطروحة. معظم التعلّم العميق (deep learning) يتمثّل في ربط طبقات بسيطة معا. معظم هذه الطبقات، مثل `tf.keras.layers.Dense`، لديها معلمات (parameters) تُتَعلَّمُ أثناء عمليّة تدريب النّموذج.

In [ ]:
model = keras.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(128, activation='relu'),
    keras.layers.Dense(10)
])
تُحوّل الطبقة الأولى من الشبكة، `tf.keras.layers.Flatten`، تنسيق الصور من صفيفة (array) ثنائية الأبعاد (28 × 28 بكسل) إلى صفيفة أحاديّة البعد (28 * 28 = 784 بكسل). فكّر في هذه الطبقة على أنّها تقوم بعمليّة تفريق الخطوط الأفقيّة للبكسلات في صورة ما، بعضها عن بعض ،ثمّ تقوم بتصفيفها في خطّ واحد. لا نحتاج لتعلّم أيّ معلمات (parameters) لضبط هذه الطبقة، فهدفها الوحيد هو إعادة تنسيق البيانات. بعد تحويل صفيفة البكسلات، ذات البعدين، المكوّنة للصورة للحصول على صفيفة ذات بعد واحد، يتكوّن باقي الشبكة من تَسلسُل لطبقتين من نوع `tf.keras.layers.Dense`. و هي طبقات عصبيّة متّصلة بكثافة (densely connected) أو تسمّى أيضا متّصلة بالكامل (fully connected). أولّ طبقة متّصلة بالكامل (`Dense` layer) تتكوّن من 128 عقدة (خليّة عصبيّة). ثاني (و آخر) طبقة متّصلة بالكامل تُخرج صفيفة لوجيت ([logits](https://en.wikipedia.org/wiki/Logit) array) تتكوّن من 10 عناصر. بما أنّ كُلّ عقدة من الطبقة الأخيرة تهتمّ بفئة معيّنة من الملابس فإنّ كل قيمة من القيم الموجودة في صفيفة اللّوجيت تشير إلى احتمال أنّ الصورة الحاليّة تحتوى على الفئة التّي تُركّز عليها العقدة.

جمع النّموذج

قبل أن يصبح النموذج جاهزًا للتدريب، يحتاج إلى بعض الإعدادات الإضافية و التّي تتمّ إضافتها في خطوة تجميع النّموذج (model compiling) و التّي تقوم بها الدّالة `model.compile`. و هذه الإعدادات هي: * *دالّة الخسارة* (Loss function) - تقيس مدى دقّة النموذج أثناء التدريب. هدفك هو أن تبنِيَ نموذجا يقوم بتقليل قيمة هذه الدّالة في كُلّ خطوة من عمليّة التدريب حتى تقوم "بتوجيه" النموذج في الاتجاه الصحيح. * *مُحسِّن* (Optimizer) - هذه هي الطريقة التي يتم بها تحديث النموذج بناءً على البيانات التي يراها و دالّة الخسارة الخاصة به. * *المقاييس* (Metrics) - تُستخدم لمراقبة أداء النموذج عند التّدريب و الاختبار. يستخدم المثال التّالى مقياس *الدّقة* ، وهي تتمثّل في نسبة الصور المصنّفة بشكل صحيح.

In [ ]:
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

تدريب النموذج

تتطلّب عمليّة تدريب نموذج الشبكة العصبيّة الخطوات التّالية: 1. لقّم بيانات التّدريب للنموذج. في هذا المثال، بيانات التدريب موجودة في الصفيفتان `train_images` و `train_labels`. 2. يتعلّم النموذج العلاقة بين الصّور و التسميات (labels) و يربط بينهما. 3. أطلب من النموذج القيام بالتنبؤ على مجموعة بيانات الاختبار. و التي هي موجودة في الصفيفة `test_images`. 4. تحقّق إلى أيّ مدى تُطابق تنبؤات النموذج التسميات الحقيقية الموجودة في الصفيفة `test_labels`.

لقّم النموذج

لبدء عمليّة التدريب، نادي الدّالة `model.fit` و هي تسمّى كذلك (fit) لأنّها تقوم بتعديل معلمات النموذج حتّى يتناسب (fits) مع البيانات:

In [ ]:
model.fit(train_images, train_labels, epochs=10)
أثناء تدريب النموذج، يتم عرض مقاييس الخسارة والدقة. بعد إتمام التدريب، يصل هذا النموذج إلى دقة تبلغ حوالي 0.91 (أو 91%) في بيانات التدريب.

تقييم الدقة

بعد ذلك، قارن أداء النموذج في مجموعة بيانات الاختبار:

In [ ]:
test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)

print('\nTest accuracy:', test_acc)
اِتّضح أنّ دقّة النموذج على مجموعة الاختبار أقلّ بقليل من دقّته على بيانات التدريب. هذه الفجوة بين دقّة التدريب و دقّة الاختبار تمثّل ما يسمّى ب overfitting، أي الإفراط في تعلّم كل ما في البيانات، حتّى الأخطاء و الشواذ الموجودة فيها. نقول بأنّ هناك *إفراطًا في التعلّم* عندما يكون أداء نموذج تعلّم آليّ (machine learning model) ما على بيانات لم يرها من قبل أثناء تعلّمه أسوء من أدائه على البيانات التّي رآها. النموذج المفرط في التعلّم يقوم بحفظ و تذكّر (memorizes) الضجيج و التفاصيل الموجودة في مجموعة بيانات التدريب إلى درجة تُضرّ بأداءه على بيانات جديدة. للإطلاع على المزيد من المعلومات عن هذا الموضوع، راجع المصادر التّالية: * [إثبات وجود الإفراط في التعلّم](https://www.tensorflow.org/tutorials/keras/overfit_and_underfit#demonstrate_overfitting?hl=ar) * [استراتجيات الوقاية من الإفراط في التعلّم](https://www.tensorflow.org/tutorials/keras/overfit_and_underfit#strategies_to_prevent_overfitting?hl=ar)

القيام بالتنبؤات

يمكنك الآن القيام بتجربة النموذج على بعض الصور. تتمثّل مخرجات النموذج في صفيفة لوجيت ([logits](https://developers.google.com/machine-learning/glossary#logits)). أضف طبقة softmax لتحويل صفيفة اللوجيت إلى احتمالات يسهل تفسيرها.

In [ ]:
probability_model = tf.keras.Sequential([model, 
                                         tf.keras.layers.Softmax()])

In [ ]:
predictions = probability_model.predict(test_images)
هنا، قام النموذج بتنبّؤ التسمية المناسبة لكلّ صورة في مجموعة الاختبار. لنلقي نظرة على أوّل تنبؤ:

In [ ]:
predictions[0]
كُلّ تنبؤ هو عبارة عن صفيف متكوّن من 10 أرقام. و هي تمثّل مدى "ثقة" النموذج بأنّ الصورة تتوافق مع كل فئة من فئات الملابس العشر المختلفة. يمكنك معرفة أي تسمية تحتوى على أعلى قيمة ثقة هكذا:

In [ ]:
np.argmax(predictions[0])
إذا، حسب النتيجة السابقة، فإنّ النموذج أكثر ثقة بأنّ هذه الصورة هي لحذاء كاحل، أي التمسية الموجودة في `class_names[9]`. و يأكّد فحص صفيفة تسميات الاختبار الموجود في `test_labels` بأنّ تصنيف النموذج صحيح:

In [ ]:
test_labels[0]
ارسم الصورة مع توقّعات النموذج العشرة لتتوضح النتائج بشكل أفضل.

In [ ]:
def plot_image(i, predictions_array, true_label, img):
  predictions_array, true_label, img = predictions_array, true_label[i], img[i]
  plt.grid(False)
  plt.xticks([])
  plt.yticks([])

  plt.imshow(img, cmap=plt.cm.binary)

  predicted_label = np.argmax(predictions_array)
  if predicted_label == true_label:
    color = 'blue'
  else:
    color = 'red'

  plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
                                100*np.max(predictions_array),
                                class_names[true_label]),
                                color=color)

def plot_value_array(i, predictions_array, true_label):
  predictions_array, true_label = predictions_array, true_label[i]
  plt.grid(False)
  plt.xticks(range(10))
  plt.yticks([])
  thisplot = plt.bar(range(10), predictions_array, color="#777777")
  plt.ylim([0, 1])
  predicted_label = np.argmax(predictions_array)

  thisplot[predicted_label].set_color('red')
  thisplot[true_label].set_color('blue')

تحقّق من التنبؤات

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

In [ ]:
i = 0
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions[i],  test_labels)
plt.show()

In [ ]:
i = 12
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions[i],  test_labels)
plt.show()
لنقم برسم عدّة صور مع تنبؤاتها. لاحظ أنّ النموذج يمكن أن يكون على خطأ حتّى و إن كانت ثقته كبيرة في تنبؤه.

In [ ]:
# Plot the first X test images, their predicted labels, and the true labels.
# Color correct predictions in blue and incorrect predictions in red.
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
  plt.subplot(num_rows, 2*num_cols, 2*i+1)
  plot_image(i, predictions[i], test_labels, test_images)
  plt.subplot(num_rows, 2*num_cols, 2*i+2)
  plot_value_array(i, predictions[i], test_labels)
plt.tight_layout()
plt.show()

استعمل النموذج المدرّب

أخيرًا، استخدم النموذج المدرّب للتنبؤ بصورة واحدة.

In [ ]:
# Grab an image from the test dataset.
img = test_images[1]

print(img.shape)
تمّ تطوير حزمة `tf.keras` لتقوم بالتنبؤ بشكل فعّال على دفعة من البيانات في آن واحد. وفقا لذلك، رغم أنّك ستستعمل صورة واحدة في المثال التّالي، فأنت بحاجة إلى إضافتها إلى قائمة (list):

In [ ]:
# Add the image to a batch where it's the only member.
img = (np.expand_dims(img,0))

print(img.shape)
الآن قم باستخدام النموذج للتنبؤ بالتسمية المناسبة لهذه الصورة:

In [ ]:
predictions_single = probability_model.predict(img)

print(predictions_single)

In [ ]:
plot_value_array(1, predictions_single[0], test_labels)
_ = plt.xticks(range(10), class_names, rotation=45)
تقوم الوظيفة `keras.Model.predict` بإرجاع قائمة قوائم (a list of lists) حيث أن كُلّ صورة في الدفعة سيكون لها قائمتها الخاصّة. استخرج التنبؤات للصورة الوحيدة في الدفعة السابقة:

In [ ]:
np.argmax(predictions_single[0])
و كما نرى يتنبأ النموذج بالتسمية كما هو متوقّع.