معاينة مختبر آمنة
Cart Pole-RL-TF
هذي معاينة منقّحة للقراءة فقط؛ ما فيه أي شيء يشتغل داخل الصفحة.
قراءة فقط
معاينة الدفتر
Cart Pole-RL-TF
> **ملاحظة بيئة التشغيل المدمجة:** هالمعاينة تستخدم عيّنة صغيرة وثابتة وآمنة من ناحية الحقوق عشان تكون النتايج قابلة للتكرار. النتايج بالحجم الكامل تحتاج مجموعة البيانات أو النموذج الموثّق بالدرس داخل بيئة خارجية معتمدة.
# تدريب التعلم المعزز على موازنة CartPole
هالدفتر جزء من AI for Beginners، واستُلهم من [هالتدوينة](https://keras.io/examples/rl/actor_critic_cartpole/) ومن [توثيق TensorFlow الرسمي](https://www.tensorflow.org/tutorials/reinforcement_learning/actor_critic) ومن [مثال التعلم المعزز في Keras](https://keras.io/examples/rl/actor_critic_cartpole/).
في هالمثال بنستخدم التعلم المعزز (Reinforcement Learning, RL) عشان ندرّب نموذجًا يوازن عمودًا فوق عربة تتحرك أفقيًا يمين ويسار. وبنستخدم بيئة [Gymnasium](https://gymnasium.farama.org/) لمحاكاة العمود.
> **ملاحظة**: تستخدم هالنسخة واجهة Gymnasium الحديثة. في البيئات السحابية اختاروا إخراج `rgb_array` بدل الاعتماد على نافذة رسومية محلية.
بنبدأ ونتأكد إن Gym مثبّت:
import sys
# Dependencies are provisioned by this course edition's pinned runtime profile.الحين خلونا ننشئ بيئة CartPole ونشوف كيف نتعامل معها. لكل بيئة هالخاصيتين:
* **مساحة الإجراءات**: مجموعة الإجراءات اللي نقدر ننفذها في كل خطوة من المحاكاة.
* **مساحة الملاحظات**: نطاق الملاحظات اللي نقدر نستقبلها.
import gymnasium as gym
import pygame
import tqdm
env = gym.make("CartPole-v1", render_mode="rgb_array")
print(f"Action space: {env.action_space}")
print(f"Observation space: {env.observation_space}")خلونا نشوف كيف تشتغل المحاكاة. الحلقة الجاية تشغّلها لين ترجع `env.step` علامة الانتهاء `done`. بنختار الإجراءات عشوائيًا باستخدام `env.action_space.sample`؛ وعشان كذا غالبًا بتفشل التجربة بسرعة، لأن بيئة CartPole تنهي التجربة إذا طلعت سرعة العربة أو موقعها أو زاوية العمود عن حدود معيّنة.
> بتنفتح المحاكاة في نافذة جديدة. تقدرون تشغّلون الكود أكثر من مرة وتلاحظون كيف يتغيّر سلوكها.
env.reset()
done = False
total_reward = 0
while not done:
env.render()
obs, rew, terminated, truncated, info = env.step(env.action_space.sample())
done = terminated or truncated
total_reward += rew
print(f"{obs} -> {rew}")
print(f"Total reward: {total_reward}")بتلاحظون إن الملاحظة تحتوي على 4 أرقام، وهي:
- موقع العربة
- سرعة العربة
- زاوية العمود
- معدل دوران العمود
`rew` هي المكافأة اللي نستقبلها في كل خطوة. في بيئة CartPole نحصل على 1 نقطة مقابل كل خطوة محاكاة، وهدفنا نرفع مجموع المكافآت لأكبر قيمة؛ يعني نخلي CartPole يحافظ على توازنه أطول مدة من دون ما يطيح.
في التعلم المعزز، هدفنا ندرّب **سياسة** $\pi$ تختار لنا الإجراء $a$ المناسب لكل حالة $s$؛ وباختصار: $a = \pi(s)$.
ولو نبغى حلًا احتماليًا، نقدر نفكر في السياسة على إنها ترجع مجموعة احتمالات، احتمال لكل إجراء. يعني $\pi(a|s)$ تمثّل احتمال إننا نختار الإجراء $a$ وإحنا في الحالة $s$.
## طريقة تدرّج السياسة
في أبسط خوارزمية للتعلم المعزز، واسمها **تدرّج السياسة** (Policy Gradient)، بندرّب الشبكة العصبية تتوقع الإجراء الجاي.
import numpy as np
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
num_inputs = 4
num_actions = 2
model = keras.Sequential([
keras.layers.Dense(128, activation="relu",input_shape=(num_inputs,)),
keras.layers.Dense(num_actions, activation="softmax")
])
model.compile(loss='categorical_crossentropy', optimizer=keras.optimizers.Adam(learning_rate=0.01))
np.random.seed(2026)
tf.random.set_seed(2026)بندرّب الشبكة عن طريق تشغيل تجارب كثيرة وتحديثها عقب كل تشغيل. خلونا نعرّف دالة تشغّل التجربة وترجع نتائجها، أو ما يسمّى **الأثر** (trace): كل الحالات والإجراءات واحتمالاتها المقترحة والمكافآت.
def run_episode(max_steps_per_episode = 10000,render=False):
states, actions, probs, rewards = [],[],[],[]
state, _ = env.reset()
for _ in range(max_steps_per_episode):
if render:
env.render()
action_probs = model(np.expand_dims(state,0))[0]
action = np.random.choice(num_actions, p=np.squeeze(action_probs))
nstate, reward, terminated, truncated, info = env.step(action)
done = terminated or truncated
if done:
break
states.append(state)
actions.append(action)
probs.append(action_probs)
rewards.append(reward)
state = nstate
return np.vstack(states), np.vstack(actions), np.vstack(probs), np.vstack(rewards)تقدرون تشغّلون حلقة واحدة (episode) بشبكة ما تدربت للحين، وبتلاحظون إن مجموع المكافآت، وهو نفسه طول الحلقة، منخفض مرة:
s,a,p,r = run_episode()
print(f"Total reward: {np.sum(r)}")من الجوانب اللي تحتاج انتباه في خوارزمية تدرّج السياسة استخدام **المكافآت المخصومة**. الفكرة إننا نحسب متجه مجموع المكافآت عند كل خطوة من اللعبة، وأثناء الحساب نخصم المكافآت المبكرة باستخدام معامل $gamma$. وبعدها نطبّع المتجه الناتج، لأننا بنستخدمه وزنًا يؤثر في التدريب:
eps = 0.0001
def discounted_rewards(rewards,gamma=0.99,normalize=True):
ret = []
s = 0
for r in rewards[::-1]:
s = r + gamma * s
ret.insert(0, s)
if normalize:
ret = (ret-np.mean(ret))/(np.std(ret)+eps)
return retالحين نبدأ التدريب الفعلي! بنشغّل 300 حلقة، وفي كل حلقة نسوي الخطوات الجاية:
1. نشغّل التجربة ونجمع الأثر.
1. نحسب الفرق (`gradients`) بين الإجراءات اللي اتخذناها والاحتمالات اللي توقعها النموذج. كل ما صغر الفرق، زادت ثقتنا إن الإجراء كان مناسبًا.
1. نحسب المكافآت المخصومة ونضرب التدرجات فيها؛ وبكذا يكون أثر الخطوات ذات المكافآت الأعلى في النتيجة النهائية أكبر من أثر الخطوات ذات المكافآت الأقل.
1. نكوّن الإجراءات المستهدفة اللي تتوقعها الشبكة العصبية من جزأين: الاحتمالات اللي توقعتها أثناء التشغيل، والتدرجات اللي حسبناها. نستخدم المعامل `alpha` عشان نحدد مقدار تأثير التدرجات والمكافآت؛ وهذا يسمّى *معدل التعلم* في خوارزمية التعلم المعزز.
1. وأخيرًا، ندرّب الشبكة على الحالات والإجراءات المتوقعة، ثم نكرر العملية.
alpha = 1e-4
history = []
for epoch in range(300):
states, actions, probs, rewards = run_episode()
one_hot_actions = np.eye(2)[actions.T][0]
gradients = one_hot_actions-probs
dr = discounted_rewards(rewards)
gradients *= dr
target = alpha*np.vstack([gradients])+probs
model.train_on_batch(states,target)
history.append(np.sum(rewards))
if epoch%100==0:
print(f"{epoch} -> {np.sum(rewards)}")
plt.plot(history)الحين خلونا نشغّل الحلقة مع العرض ونشوف النتيجة:
_ = run_episode(render=True)المفروض تشوفون الحين إن العمود صار يوازن بشكل زين!
## نموذج الممثل والناقد
نموذج الممثل والناقد (Actor-Critic) تطوير إضافي لتدرّج السياسة. فيه نبني الشبكة العصبية وهي تتعلم السياسة والمكافآت المقدّرة مع بعض. للشبكة مخرجان، أو تقدرون تتعاملون معها على إنها شبكتان منفصلتان:
* **الممثل** يقترح الإجراء اللي نتخذه عن طريق إعطائنا توزيع احتمالات الإجراءات في الحالة الحالية، مثل نموذج تدرّج السياسة.
* **الناقد** يقدّر المكافأة اللي بتنتج عن هالإجراءات، ويرجع مجموع المكافآت المستقبلية المقدّرة عند الحالة المعطاة.
خلونا نعرّف هالنموذج:
num_inputs = 4
num_actions = 2
num_hidden = 128
inputs = keras.layers.Input(shape=(num_inputs,))
common = keras.layers.Dense(num_hidden, activation="relu")(inputs)
action = keras.layers.Dense(num_actions, activation="softmax")(common)
critic = keras.layers.Dense(1)(common)
model = keras.Model(inputs=inputs, outputs=[action, critic])نحتاج نعدّل الدالة `run_episode` شوي عشان ترجع نتائج الناقد بعد:
def run_episode(max_steps_per_episode = 10000,render=False):
states, actions, probs, rewards, critic = [],[],[],[],[]
state, _ = env.reset()
for _ in range(max_steps_per_episode):
if render:
env.render()
action_probs, est_rew = model(np.expand_dims(state,0))
action = np.random.choice(num_actions, p=np.squeeze(action_probs[0]))
nstate, reward, terminated, truncated, info = env.step(action)
done = terminated or truncated
if done:
break
states.append(state)
actions.append(action)
probs.append(tf.math.log(action_probs[0,action]))
rewards.append(reward)
critic.append(est_rew[0,0])
state = nstate
return states, actions, probs, rewards, criticالحين بنشغّل حلقة التدريب الرئيسية. بنستخدم تدريبًا يدويًا للشبكة: نحسب دوال الخسارة المناسبة، وبعدها نحدّث معاملات الشبكة:
optimizer = keras.optimizers.Adam(learning_rate=0.01)
huber_loss = keras.losses.Huber()
episode_count = 0
running_reward = 0
max_episodes = 25
while episode_count < max_episodes: # bounded course run
state, _ = env.reset()
episode_reward = 0
with tf.GradientTape() as tape:
_,_,action_probs, rewards, critic_values = run_episode()
episode_reward = np.sum(rewards)
# Update running reward to check condition for solving
running_reward = 0.05 * episode_reward + (1 - 0.05) * running_reward
# Calculate discounted rewards that will be labels for our critic
dr = discounted_rewards(rewards)
# Calculating loss values to update our network
actor_losses = []
critic_losses = []
for log_prob, value, rew in zip(action_probs, critic_values, dr):
# When we took the action with probability `log_prob`, we received discounted reward of `rew`,
# while critic predicted it to be `value`
# First we calculate actor loss, to make actor predict actions that lead to higher rewards
diff = rew - value
actor_losses.append(-log_prob * diff)
# The critic loss is to minimize the difference between predicted reward `value` and actual
# discounted reward `rew`
critic_losses.append(
huber_loss(tf.expand_dims(value, 0), tf.expand_dims(rew, 0))
)
# Backpropagation
loss_value = sum(actor_losses) + sum(critic_losses)
grads = tape.gradient(loss_value, model.trainable_variables)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
# Log details
episode_count += 1
if episode_count % 10 == 0:
template = "running reward: {:.2f} at episode {}"
print(template.format(running_reward, episode_count))
if running_reward > 195: # Condition to consider the task solved
print("Solved at episode {}!".format(episode_count))
breakخلونا نشغّل الحلقة ونشوف وش كثر صار نموذجنا زين:
_ = run_episode(render=True)وأخيرًا، خلونا نقفل البيئة.
env.close()## الزبدة
شفنا في هالعرض خوارزميتين للتعلم المعزز: تدرّج السياسة البسيطة، والممثل والناقد الأكثر تطورًا. هالخوارزميات تتعامل مع مفاهيم مجردة مثل الحالة والإجراء والمكافأة؛ وعشان كذا نقدر نطبقها على بيئات مختلفة جدًا.
يخلينا التعلم المعزز نتعلم أفضل استراتيجية لحل المسألة بمجرد مراقبة المكافأة النهائية. وبما إننا ما نحتاج مجموعات بيانات عليها تسميات، نقدر نكرر المحاكاة مرات كثيرة ونحسّن نماذجنا. ومع هذا، ما زالت فيه تحديات كثيرة في التعلم المعزز، وبتتعرفون عليها أكثر لو قررتوا تتخصصون في هالمجال الممتع من الذكاء الاصطناعي.
حذفنا المخرجات وعدّادات التشغيل والودجات والمحتوى النشط وقت الاستيراد. شغّل الدفاتر بس في بيئة خارجية تثق فيها.
سجّل تطبيقك
التسجيل اختياري، يفيدك تتذكر وش طبّقت، ولا يمنع إكمال الدورة.