Logo

مقدمة في TensorFlow 2.x

11 دقيقة قراءة
شرائح الدرس
1 / 14

مقدمة في TensorFlow 2.x

البنى الأساسية للبيانات، العمليات الحسابية، الرسوم البيانية الحسابية، والاشتقاق التلقائي

مقدمة في TensorFlow 2.x

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

لماذا TensorFlow 2.x؟

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

  • التنفيذ الفوري (Eager Execution): ينفّذ العمليات فور كتابتها، مما يسهّل عملية تصحيح الأخطاء (Debugging).
  • Keras كواجهة برمجية أساسية: أصبحت tf.keras الآن الواجهة عالية المستوى الموصى بها لبناء النماذج.
  • مسار عمل متكامل لتعلّم الآلة: يدعم المعالجة المسبقة للبيانات، وتدريب النماذج، وتقييمها، ونشرها.
  • يعمل على أي عتاد: متوافق مع CPU وGPU وTPU، بل وحتى الأجهزة المحمولة.
  • التدريب الموزَّع (Distributed Training): تدريب عبر وحدات 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) عمليات وهياكل بيانات منخفضة المستوى. ⚙️ العمل مع الـCore API يساعدك على فهم كيفية تفاعل الـtensors والمتغيرات (Variables) والعمليات في الخلفية. 🧠

🔢 2.1 هياكل البيانات في TensorFlow

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

2.1.1 tf.Tensor

الـtf.Tensor هو هيكل البيانات الأساسي في TensorFlow. 🔢 يمثّل مصفوفة ثابتة (Immutable) متعددة الأبعاد. 📊

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

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

🎯 الأساسيات

أولًا، لنُنشئ بعض الـtensors الأساسية! 🔢✨

هذا مثال على قيمة عددية مفردة (Scalar) أو tensor من الرتبة 0 (Rank-0). 🎯

الـ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) أو tensor من الرتبة 1 (Rank-1) أشبه بـقائمة من القيم. 📋

الـ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) أو tensor من الرتبة 2 (Rank-2) لها محوران: 🏗️📊

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

يمكن أن يكون للـtensors محاور أكثر؛ إليك tensor بثلاثة محاور: 📐🔢

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

هناك طرق كثيرة لتصوّر (Visualize) الـtensor الذي له أكثر من محورين. 🎨🖼️

يمكنك تحويل الـtensor إلى مصفوفة 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 على طول كل محور من محاوره.
  • Tensor.dtype 🔡: تخبرك بـنوع البيانات لجميع عناصر الـtensor.
# 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 هو tensor قابل للتعديل، يُستخدَم عادةً لتخزين معاملات (Parameters) النموذج وتحديثها أثناء التدريب. 🔄📊

كائنات الـtf.Tensor العادية ثابتة (Immutable). 🚫 لتخزين أوزان (Weights) النموذج (أو أي حالة أخرى قابلة للتغيير) في 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 مجموعة من عمليات الرياضيات والجبر الخطي، بالإضافة إلى أدوات توليد الأرقام العشوائية. 🎯📊

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

✨ 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 عمليات جبر خطي فعّالة، وهي أساسية لكل من التعلّم العميق والحوسبة العلمية. 🔢🧮

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

  • ضرب المصفوفات (tf.matmul) ➗
  • المحدِّدات (Determinants) والمصفوفات المعكوسة (Inverses) (tf.linalg.det, tf.linalg.inv) 📏
  • القيم الذاتية والمتجهات الذاتية (Eigenvalues and 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)، وإنشاء نماذج عشوائية (Stochastic). 🔢🎯

من أهم الدوال:

  • tf.random.normal 📊 – يولّد أرقامًا من التوزيع الطبيعي (Normal Distribution).
  • tf.random.uniform 📏 – يولّد أرقامًا من التوزيع المنتظم (Uniform Distribution).
  • tf.random.shuffle 🔀 – يخلط ترتيب عناصر الـtensor.
  • 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 المتوسط الحسابي (Arithmetic Mean) للعناصر عبر أبعاد (محاور) محدَّدة من الـtensor. 📊🔢

  • إذا لم يُحدَّد أي محور، تحسب الدالة متوسط جميع عناصر الـtensor. 🔄⚡
# 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 بشكل فوري (Eagerly) افتراضيًا. ⚡ هذا يعني أن العمليات تُنفَّذ مباشرةً في بايثون بدلًا من بناء مخطط ثابت أولًا.

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

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

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

🔄 4.2 tf.function()

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

🔥 بدون @tf.function

  • يُنفَّذ TensorFlow بشكل فوري (Eagerly)، فينفّذ عملية واحدة في كل مرة (كما في بايثون العادية). 🐍
  • رائع لتصحيح الأخطاء لكنه قد يكون أبطأ في المهام المتكررة. 🛠️🐢

🚀 مع @tf.function

  • يتتبّع TensorFlow دالة بايثون الخاصة بك ويبني مخطط حوسبة قابلًا لإعادة الاستخدام (يُعرَف بـ"تنفيذ المخطط" - 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 عملية التتبّع (Tracing) لأن print() هي دالة بايثون، وليست دالة 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). 🔄📈 يمكنك تسجيل العمليات على الـtensors داخل سياق tf.GradientTape()، ثم طلب التدرّجات بالنسبة لأي متغيرات أو tensors قابلة للتدريب. 🛠️

🔢 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. بناء مخططات الحوسبة (Computation Graphs) في TF 2.x باستخدام tf.function.
  5. 🔄 الاشتقاق التلقائي (Automatic Differentiation) باستخدام tf.GradientTape().

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