Logo

مقدمة في TensorFlow 2.x

12 دقيقة قراءة
شرائح الدرس
1 / 15

مقدمة إلى TensorFlow 2.x

التنفيذ الفوري (Eager Execution)، المصفوفات الموترة (Tensors)، والاشتقاق التلقائي

مقدمة إلى TensorFlow 2.x

TensorFlow 2.x هو إطار عمل مفتوح المصدر للتعلم العميق (Deep Learning) طوّرته شركة Google، ويجعل بناء نماذج تعلّم الآلة وتدريبها أمرًا سهلاً. يُستخدم على نطاق واسع في مهام مثل تصنيف الصور، ومعالجة اللغة الطبيعية (NLP)، والتنبؤ بالسلاسل الزمنية، والتعلم المعزز. ومع تفعيل التنفيذ الفوري (Eager Execution) افتراضيًا، يقدّم TensorFlow 2.x أسلوبًا أكثر بداهة وأقرب إلى طبيعة لغة Python مقارنةً بسابقه TensorFlow 1.x.

لماذا نستخدم TensorFlow 2.x؟

يقدّم TensorFlow 2.x مجموعة من التحسينات التي تجعل التعلم العميق أبسط وأكثر كفاءة:

  • التنفيذ الفوري (Eager Execution): ينفّذ العمليات فور كتابتها، ما يجعل تتبّع الأخطاء وإصلاحها أسهل بكثير.
  • Keras كواجهة برمجية أساسية: أصبحت tf.keras الآن الواجهة البرمجية عالية المستوى الموصى بها لبناء النماذج.
  • سير عمل متكامل لتعلم الآلة: يدعم معالجة البيانات المسبقة، وتدريب النماذج، وتقييمها، ونشرها.
  • يعمل على أي عتاد: متوافق مع المعالج (CPU)، ومعالج الرسوميات (GPU)، ووحدة معالجة الموتّرات (TPU)، بل وحتى الأجهزة المحمولة.
  • التدريب الموزّع: درّب نماذجك عبر عدة وحدات GPU/TPU بسهولة تامة.
  • جاهز للإنتاج: انشر النماذج على الخدمات السحابية، وتطبيقات الجوال، وتطبيقات الويب.
# Use this to load your data from Google Drive
# from google.colab import drive
# drive.mount('/content/drive')
Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).

🚀 1. استيراد TensorFlow والتحقق من الإصدار

لنبدأ باستيراد TensorFlow والتحقق من أننا نملك الإصدار المطلوب. ✅
كما سنجري فحصًا سريعًا للتأكد من توفر وحدة معالجة الرسوميات (GPU). 🔍💻

import tensorflow as tf
print("TensorFlow Version:", tf.__version__)
 
import numpy as np
# Check for GPU
print("Is GPU available?:", tf.config.list_physical_devices('GPU'))
TensorFlow Version: 2.18.0
Is GPU available?: []

🔹 2. واجهة TensorFlow الأساسية (Core API)

توفر واجهة TensorFlow الأساسية (Core API) عمليات منخفضة المستوى وبُنى بيانات أساسية. ⚙️
العمل مع الواجهة الأساسية يساعدك على فهم كيفية تفاعل التنسورات (tensors) والمتغيرات والعمليات في الخلفية. 🧠

🔢 2.1 بُنى البيانات في TensorFlow

  • tf.Tensor 🏗️: كائنات غير قابلة للتعديل (Immutable) تمثّل مصفوفات متعددة الأبعاد.
  • tf.Variable 🔄: نسخة قابلة للتعديل من التنسورات (مفيدة لتخزين المعاملات/الأوزان).
  • tf.TensorArray 📦: مصفوفة من التنسورات ذات حجم ديناميكي، تُستخدم غالبًا في الشبكات العصبية المتكررة (RNNs) المعقدة.
  • tf.RaggedTensor 📏: تنسورات ذات صفوف متفاوتة الطول.
  • tf.SparseTensor 🧩: تنسورات لتمثيل البيانات المتناثرة (Sparse Data).

2.1.1 tf.Tensor

يُعدّ tf.Tensor بنية البيانات الأساسية في TensorFlow. 🔢
وهو يمثّل مصفوفة متعددة الأبعاد غير قابلة للتعديل. 📊

فيما يلي مثال على إنشاء تنسور ثابت (constant tensor) واستكشاف خصائصه. 🛠️

عدم القابلية للتعديل (Immutability):
جميع التنسورات غير قابلة للتعديل، تمامًا مثل الأرقام والسلاسل النصية في Python. 🔒
لا يمكنك تعديل محتوى تنسور موجود؛ بل يمكنك فقط إنشاء تنسور جديد. 🔄

🎯 الأساسيات

بدايةً، لننشئ بعض التنسورات الأساسية! 🔢✨

إليك العددي (scalar) أو التنسور من الرتبة صفر (rank-0 tensor). 🎯

يحتوي العددي (scalar) على قيمة واحدة فقط وليس له أي محاور (axes). ⚡🔢

# This will be an int32 tensor by default; see "dtypes" below.
rank_0_tensor = tf.constant(4)
print(rank_0_tensor)
tf.Tensor(4, shape=(), dtype=int32)

المتجه (vector) أو التنسور من الرتبة الأولى (rank-1 tensor) أشبه بـ قائمة من القيم. 📋

لدى المتجه (vector) محور واحد: 📏

# Let's make this a float tensor.
rank_1_tensor = tf.constant([2.0, 3.0, 4.0])
print(rank_1_tensor)
tf.Tensor([2. 3. 4.], shape=(3,), dtype=float32)

لدى المصفوفة (matrix) أو التنسور من الرتبة الثانية (rank-2 tensor) محوران: 🏗️📊

# If you want to be specific, you can set the dtype (see below) at creation time
rank_2_tensor = tf.constant([[1, 2],
                             [3, 4],
                             [5, 6]], dtype=tf.float16)
print(rank_2_tensor)
tf.Tensor(
[[1. 2.]
 [3. 4.]
 [5. 6.]], shape=(3, 2), dtype=float16)

قد يكون للتنسورات محاور أكثر؛ إليك تنسورًا بثلاثة محاور: 📐🔢

# There can be an arbitrary number of
# axes (sometimes called "dimensions")
rank_3_tensor = tf.constant([
  [[0, 1, 2, 3, 4],
   [5, 6, 7, 8, 9]],
  [[10, 11, 12, 13, 14],
   [15, 16, 17, 18, 19]],
  [[20, 21, 22, 23, 24],
   [25, 26, 27, 28, 29]],])
 
print(rank_3_tensor)
tf.Tensor(
[[[ 0  1  2  3  4]
  [ 5  6  7  8  9]]
 
 [[10 11 12 13 14]
  [15 16 17 18 19]]
 
 [[20 21 22 23 24]
  [25 26 27 28 29]]], shape=(3, 2, 5), dtype=int32)

توجد طرق عديدة لتصوير تنسور يحتوي على أكثر من محورين. 🎨🖼️

يمكنك تحويل تنسور إلى مصفوفة NumPy باستخدام إحدى الطريقتين التاليتين: 🔄📊

  • np.array(tensor) 🐍
  • tensor.numpy()
np.array(rank_2_tensor)
array([[1., 2.],
       [3., 4.],
       [5., 6.]], dtype=float16)
rank_2_tensor.numpy()
array([[1., 2.],
       [3., 4.],
       [5., 6.]], dtype=float16)

أهم خاصيتين في tf.Tensor هما shape (الشكل) وdtype (نوع البيانات): 🏗️📊

  • Tensor.shape 📏: تخبرك بـ حجم التنسور على طول كل محور من محاوره.
  • Tensor.dtype 🔡: تخبرك بـ نوع البيانات لجميع عناصر التنسور.
# Creating a constant tensor
tensor = tf.constant([[1, 2], [3, 4]], dtype=tf.float32)
print("Tensor:", tensor)
print("Shape:", tensor.shape)
print("Data Type:", tensor.dtype)
 
# Accessing elements in a tensor
element_0_0 = tensor[0, 0]
print("Element at [0,0]:", element_0_0.numpy())
 
# Performing slicing
slice_of_tensor = tensor[:, 0]
print("Sliced Tensor (all rows, col 0):", slice_of_tensor.numpy())
Tensor: tf.Tensor(
[[1. 2.]
 [3. 4.]], shape=(2, 2), dtype=float32)
Shape: (2, 2)
Data Type: <dtype: 'float32'>
Element at [0,0]: 1.0
Sliced Tensor (all rows, col 0): [1. 3.]

🔹 2.1.2 tf.Variable

tf.Variable هو تنسور قابل للتعديل، يُستخدم عادةً لتخزين معاملات (أوزان) النموذج وتحديثها أثناء التدريب. 🔄📊

كائنات tf.Tensor العادية غير قابلة للتعديل. 🚫
لتخزين أوزان النموذج (أو أي حالة أخرى قابلة للتغيير) في TensorFlow، استخدم tf.Variable. ✅

# Creating a tf.Variable
var = tf.Variable([[5.0, 6.0], [7.0, 8.0]])
print("Initial Value:\n", var.numpy())
 
# Assigning new values
var.assign([[1, 2], [3, 4]])
print("Re-assigned Value:\n", var.numpy())
 
# Incrementing values
var.assign_add([[1, 1], [1, 1]])
print("Incremented Value:\n", var.numpy())
Initial Value:
 [[5. 6.]
 [7. 8.]]
Re-assigned Value:
 [[1. 2.]
 [3. 4.]]
Incremented Value:
 [[2. 3.]
 [4. 5.]]

🔹 2.1.3 tf.RaggedTensor

إذا احتجت للتعامل مع بيانات متغيرة الطول (كالجُمل ذات الأطوال المختلفة مثلًا)،
يمكنك استخدام tf.RaggedTensor لـ تخزين هذه القيم بكفاءة. 📏🗂️

ragged = tf.ragged.constant([[1, 2], [3, 4, 5], [6]])
print("Ragged Tensor:", ragged)
print("Ragged Tensor rows:", [row.numpy() for row in ragged])
Ragged Tensor: <tf.RaggedTensor [[1, 2], [3, 4, 5], [6]]>
Ragged Tensor rows: [array([1, 2], dtype=int32), array([3, 4, 5], dtype=int32), array([6], dtype=int32)]

🔹 2.1.4 tf.SparseTensor

يُستخدم tf.SparseTensor لـ تمثيل البيانات بكفاءة عندما تحتوي على نسبة كبيرة من القيم الصفرية. 🧩⚡

indices = [[0, 3], [2, 4]]
values = [10, 20]
dense_shape = [3, 10]
 
sparse = tf.SparseTensor(indices=indices, values=values, dense_shape=dense_shape)
print("Sparse Tensor:", sparse)
 
dense_from_sparse = tf.sparse.to_dense(sparse)
print("\n Converted to Dense:\n", dense_from_sparse.numpy())
Sparse Tensor: SparseTensor(indices=tf.Tensor(
[[0 3]
 [2 4]], shape=(2, 2), dtype=int64), values=tf.Tensor([10 20], shape=(2,), dtype=int32), dense_shape=tf.Tensor([ 3 10], shape=(2,), dtype=int64))
 
 Converted to Dense:
 [[ 0  0  0 10  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0 20  0  0  0  0  0]]

🔢 3. الواجهات البرمجية العددية: الرياضيات، الجبر الخطي، والعشوائية

يوفر TensorFlow مجموعة من عمليات الرياضيات والجبر الخطي، بالإضافة إلى أدوات توليد الأرقام العشوائية. 🎯📊

وهذه الأدوات ضرورية لبناء النماذج، إذ تشمل كل شيء بدءًا من العمليات الحسابية البسيطة ➕ وصولًا إلى عمليات الجبر الخطي المتقدمة (كتحليل المصفوفات). 🔢📏

✨ 3.1 العمليات الحسابية الأساسية

# Basic arithmetic
x = tf.constant([2.0, 4.0, 6.0])
y = tf.constant([1.0, 2.0, 3.0])
 
add_result = tf.add(x, y)
sub_result = tf.subtract(x, y)
mul_result = tf.multiply(x, y)
div_result = tf.divide(x, y)
 
print("x + y =", add_result.numpy())
print("x - y =", sub_result.numpy())
print("x * y =", mul_result.numpy())
print("x / y =", div_result.numpy())
x + y = [3. 6. 9.]
x - y = [1. 2. 3.]
x * y = [ 2.  8. 18.]
x / y = [2. 2. 2.]

📐 3.2 عمليات الجبر الخطي

يوفر TensorFlow عمليات جبر خطي فعّالة، وهي ضرورية لـ التعلم العميق والحوسبة العلمية. 🔢🧮

وتشمل هذه العمليات:

  • ضرب المصفوفات (Matrix Multiplication) (tf.matmul) ➗
  • المحدّدات (Determinants) والمصفوفات المعكوسة (Inverses) (tf.linalg.det، tf.linalg.inv) 📏
  • القيم الذاتية والمتجهات الذاتية (Eigenvalues & Eigenvectors) (tf.linalg.eig) 🔄
  • تحليل القيمة المفردة (Singular Value Decomposition - SVD) (tf.linalg.svd) 📊

تُشغّل هذه العمليات كل شيء بدءًا من الشبكات العصبية وصولًا إلى النمذجة الإحصائية! 🚀💡

# Matrix multiplication
A = tf.constant([[2.0, 3.0], [1.0, 4.0]])
B = tf.constant([[1.0, 2.0], [3.0, 4.0]])
matmul_result = tf.linalg.matmul(A, B)
print("Matrix Multiplication (A @ B):\n", matmul_result.numpy())
Matrix Multiplication (A @ B):
 [[11. 16.]
 [13. 18.]]

🎲 3.3 توليد الأرقام العشوائية

يوفر TensorFlow أدوات لتوليد الأرقام العشوائية (RNG) تُستخدم في تهيئة الأوزان، وزيادة البيانات (Data Augmentation)، وبناء النماذج العشوائية. 🔢🎯

من أبرز الدوال المستخدمة لهذا الغرض:

  • tf.random.normal 📊 – يولّد أرقامًا من التوزيع الطبيعي (Normal Distribution).
  • tf.random.uniform 📏 – يولّد أرقامًا من التوزيع المنتظم (Uniform Distribution).
  • tf.random.shuffle 🔀 – يعيد ترتيب عناصر التنسور عشوائيًا.
  • tf.random.set_seed 🔒 – يضبط بذرة عشوائية (Seed) لضمان إمكانية إعادة إنتاج النتائج.

يُعدّ توليد الأرقام العشوائية أمرًا أساسيًا في تجارب تعلم الآلة ولـ ضمان إمكانية إعادة إنتاج النتائج! 🚀

# Normal distribution
normal_dist = tf.random.normal([3, 3], mean=0.0, stddev=1.0)
print("Random Normal:", normal_dist.numpy())
 
# Uniform distribution
uniform_dist = tf.random.uniform([2, 2], minval=0, maxval=10)
print("Random Uniform:", uniform_dist.numpy())
 
# Setting a seed for reproducibility
tf.random.set_seed(42)
seeded_normal = tf.random.normal([2, 2])
print("Seeded Random Normal:", seeded_normal.numpy())

📉 3.4 tf.reduce_mean

تحسب الدالة tf.reduce_mean المتوسط (الوسط الحسابي) لعناصر التنسور على طول الأبعاد (المحاور) المحددة. 📊🔢

  • إذا لم يُحدَّد أي محور، فإنها تحسب متوسط جميع عناصر التنسور. 🔄⚡
# Suppose we have a 2D tensor
x = tf.constant([[1, 2, 3],
                 [4, 5, 6]], dtype=tf.float32)
 
# 1) Mean of all elements
mean_all = tf.reduce_mean(x)
print("mean_all:", mean_all.numpy())
# Output: 3.5  (average of [1,2,3,4,5,6])
 
# 2) Mean along axis=0 (columns)
mean_cols = tf.reduce_mean(x, axis=0)
print("mean_cols:", mean_cols.numpy())
# Output: [2.5 3.5 4.5]  (col-wise means)
 
# 3) Mean along axis=1 (rows)
mean_rows = tf.reduce_mean(x, axis=1)
print("mean_rows:", mean_rows.numpy())
# Output: [2. 5.]  (row-wise means)
mean_all: 3.5
mean_cols: [2.5 3.5 4.5]
mean_rows: [2. 5.]

🔗 4. الرسوم البيانية الحسابية (Computation Graphs) في TensorFlow 2.x

ينفّذ TensorFlow 2.x العمليات بشكل فوري (Eager) افتراضيًا. ⚡
وهذا يعني أن العمليات تُنفَّذ مباشرةً داخل Python بدلًا من بناء رسم بياني ثابت أولًا.

ومع ذلك، ولتحقيق أداء أفضل، يمكنك إنشاء رسوم بيانية حسابية باستخدام tf.function(). 📈
إذ تُحوِّل هذه الدالة كود Python الخاص بك إلى رسوم بيانية ثابتة لتحقيق تنفيذ أسرع. 🚀

⚡ 4.1 التنفيذ الفوري (Eager Execution)

  • افتراضيًا، تُنفَّذ كل عملية فور كتابتها. 🏃‍♂️
  • سهل في تتبّع الأخطاء والاستكشاف التفاعلي. 🛠️

🔄 4.2 tf.function()

  • زخرِف (decorate) دالة Python بـ @tf.function لـ تتبّعها وإنشاء رسم بياني منها. 🔍
  • يحسّن الأداء بشكل ملحوظ، خصوصًا عند استدعاء الدالة بشكل متكرر. ⚡📊

🔥 بدون @tf.function

  • يعمل TensorFlow بشكل فوري (Eager)، منفّذًا عملية واحدة في كل مرة (تمامًا كما في Python العادي). 🐍
  • ممتاز لتتبّع الأخطاء لكنه قد يكون أبطأ في المهام المتكررة. 🛠️🐢

🚀 مع @tf.function

  • يقوم TensorFlow بتتبّع دالة Python الخاصة بك ويبني رسمًا بيانيًا حسابيًا قابلًا لإعادة الاستخدام (وهو ما يُعرف بـ"تنفيذ الرسم البياني" أو graph execution). 📈
  • يعمل بشكل أسرع بفضل التحسينات، لكنه يفرض بعض القيود (مثل ضرورة توافق تراكيب التحكم في التدفق مع TensorFlow). ⚠️

🏗️ مثال: إنشاء رسم بياني حسابي

فيما يلي مثال على رسم بياني حسابي في TensorFlow:

Computation Graph

@tf.function  # Convert to a computation graph
def computation_graph(x1, x2):
    add_op = x1 + x2
    mul_op = x1 * x2
    sub_op = add_op - mul_op
    print('Tracing.\n')
    return sub_op
 
# Inputs
x1 = tf.constant(7, dtype=tf.float32)
x2 = tf.constant(3, dtype=tf.float32)
 
computation_graph(x1, x2)
Tracing.
 
<tf.Tensor: shape=(), dtype=int32, numpy=-11>

في الاستدعاءات اللاحقة، يكتفي TensorFlow بتنفيذ الرسم البياني المُحسَّن فقط،
متجاوزًا أي خطوات لا تخص TensorFlow لتحقيق تنفيذ أسرع. ⚡📈🚀

⚠️ ملاحظة: لا تطبع الدالة computation_graph عبارة التتبّع لأن print() هي دالة Python عادية،
وليست دالة TensorFlow. 🐍❌🔄

x1 = tf.constant(2, dtype=tf.float32)
x2 = tf.constant(1, dtype=tf.float32)
computation_graph(x1, x2)
Tracing.
 
<tf.Tensor: shape=(), dtype=int32, numpy=1>

🎯 5. الاشتقاق التلقائي (Automatic Differentiation) باستخدام tf.GradientTape()

يستخدم TensorFlow خوارزمية الاشتقاق التلقائي العكسي (reverse-mode autodiff) لحساب المشتقات (Gradients). 🔄📈
يمكنك تسجيل العمليات المُجراة على التنسورات داخل سياق tf.GradientTape()،
ثم طلب المشتقات (gradients) بالنسبة لأي متغيرات أو تنسورات قابلة للتدريب. 🛠️

🔢 5.1 مثال بمتغير واحد

x = tf.Variable(2.0)
with tf.GradientTape() as tape:
    y = x ** 3  # y = x^3
 
dy_dx = tape.gradient(y, x)
print("If y = x^3 and x = 2.0, dy/dx should be 3*x^2 = 12.0.")
print("Computed Gradient:", dy_dx.numpy())
If y = x^3 and x = 2.0, dy/dx should be 3*x^2 = 12.0.
Computed Gradient: 12.0

🔢 5.2 مثال بعدة متغيرات

في الشبكات العصبية، عادةً ما تحتاج لتتبّع عدة متغيرات قابلة للتدريب في آن واحد. 🤖🧠
إليك عرضًا مبسّطًا باستخدام متغيرين اثنين. 🎯📊

w = tf.Variable(1.0)
b = tf.Variable(2.0)
x_vals = tf.constant([1.0, 2.0, 3.0])
 
with tf.GradientTape() as tape:
    # A simple linear function: y = w * x + b
    y_vals = w * x_vals + b
    loss = tf.reduce_mean((y_vals - tf.constant([2.0, 4.0, 6.0]))**2)
 
gradients = tape.gradient(loss, [w, b])
print("Loss:", loss.numpy())
print("dLoss/dw:", gradients[0].numpy())
print("dLoss/db:", gradients[1].numpy())
Loss: 0.6666667
dLoss/dw: -1.3333333
dLoss/db: 0.0

🎯 الخاتمة

في هذا الدرس (notebook)، تعلمت عن:

  1. استيراد TensorFlow والتحقق من الإصدارات/الأجهزة المتاحة.
  2. 🏗️ واجهة TensorFlow الأساسية (Core API)، بما في ذلك بُنى البيانات الأساسية (tf.Tensor، tf.Variable، وغيرها).
  3. 🔢 الواجهات البرمجية العددية (الرياضيات، الجبر الخطي، العمليات العشوائية).
  4. بناء الرسوم البيانية الحسابية في TF 2.x باستخدام tf.function.
  5. 🔄 الاشتقاق التلقائي (Automatic Differentiation) باستخدام tf.GradientTape().

سيساعدك هذا الأساس على بناء نماذج TensorFlow أكثر تعقيدًا
وفهم استراتيجيات ضبط الأداء، وتتبّع الأخطاء، والنشر. 🚀📊