نماینده REINFORCE

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHub دانلود دفترچه یادداشت

معرفی

این مثال نشان می دهد که چگونه برای آموزش تقویت عامل بر روی محیط زیست Cartpole با استفاده از کتابخانه TF-نمایندگی، شبیه به آموزش DQN .

محیط Cartpole

ما شما را از طریق تمام اجزای یک خط لوله یادگیری تقویتی (RL) برای آموزش، ارزیابی و جمع آوری داده ها راهنمایی می کنیم.

برپایی

اگر وابستگی های زیر را نصب نکرده اید، اجرا کنید:

sudo apt-get update
sudo apt-get install -y xvfb ffmpeg freeglut3-dev
pip install 'imageio==2.4.0'
pip install pyvirtualdisplay
pip install tf-agents[reverb]
pip install pyglet xvfbwrapper
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import base64
import imageio
import IPython
import matplotlib.pyplot as plt
import numpy as np
import PIL.Image
import pyvirtualdisplay
import reverb

import tensorflow as tf

from tf_agents.agents.reinforce import reinforce_agent
from tf_agents.drivers import py_driver
from tf_agents.environments import suite_gym
from tf_agents.environments import tf_py_environment
from tf_agents.networks import actor_distribution_network
from tf_agents.policies import py_tf_eager_policy
from tf_agents.replay_buffers import reverb_replay_buffer
from tf_agents.replay_buffers import reverb_utils
from tf_agents.specs import tensor_spec
from tf_agents.trajectories import trajectory
from tf_agents.utils import common

# Set up a virtual display for rendering OpenAI gym environments.
display = pyvirtualdisplay.Display(visible=0, size=(1400, 900)).start()

فراپارامترها

env_name = "CartPole-v0" # @param {type:"string"}
num_iterations = 250 # @param {type:"integer"}
collect_episodes_per_iteration = 2 # @param {type:"integer"}
replay_buffer_capacity = 2000 # @param {type:"integer"}

fc_layer_params = (100,)

learning_rate = 1e-3 # @param {type:"number"}
log_interval = 25 # @param {type:"integer"}
num_eval_episodes = 10 # @param {type:"integer"}
eval_interval = 50 # @param {type:"integer"}

محیط

محیط‌ها در RL نشان‌دهنده وظیفه یا مشکلی است که ما سعی در حل آن داریم. محیط های استاندارد را می توان به راحتی در TF-نمایندگی با استفاده از ایجاد suites . ما مختلف suites برای بارگذاری محیط از منابع مانند OpenAI بدنسازی، آتاری، DM کنترل، و غیره، با توجه به نام محیط زیست رشته.

حال اجازه دهید محیط CartPole را از مجموعه OpenAI Gym بارگیری کنیم.

env = suite_gym.load(env_name)

ما می توانیم این محیط را رندر کنیم تا ببینیم چگونه به نظر می رسد. یک میله چرخان آزاد به یک گاری وصل شده است. هدف این است که چرخ دستی را به سمت راست یا چپ حرکت دهید تا قطب را به سمت بالا نگه دارید.

env.reset()
PIL.Image.fromarray(env.render())

png

time_step = environment.step(action) بیانیه طول می کشد action در محیط زیست است. TimeStep تاپل بازگشت شامل مشاهدات بعدی محیط زیست و پاداش که برای عمل. time_step_spec() و action_spec() روش در محیط بازگشت مشخصات (انواع، اشکال، محدوده) از time_step و action است.

print('Observation Spec:')
print(env.time_step_spec().observation)
print('Action Spec:')
print(env.action_spec())
Observation Spec:
BoundedArraySpec(shape=(4,), dtype=dtype('float32'), name='observation', minimum=[-4.8000002e+00 -3.4028235e+38 -4.1887903e-01 -3.4028235e+38], maximum=[4.8000002e+00 3.4028235e+38 4.1887903e-01 3.4028235e+38])
Action Spec:
BoundedArraySpec(shape=(), dtype=dtype('int64'), name='action', minimum=0, maximum=1)

بنابراین، می بینیم که مشاهده آرایه ای از 4 شناور است: موقعیت و سرعت گاری، و موقعیت زاویه ای و سرعت قطب. از آنجا که تنها دو عمل امکان پذیر است (حرکت به سمت چپ یا راست حرکت می کند)، به action_spec یک اسکالر که در آن 0 به معنی "حرکت به سمت چپ" و 1 معنی "حق حرکت کند."

time_step = env.reset()
print('Time step:')
print(time_step)

action = np.array(1, dtype=np.int32)

next_time_step = env.step(action)
print('Next time step:')
print(next_time_step)
Time step:
TimeStep(
{'discount': array(1., dtype=float32),
 'observation': array([ 0.02284177, -0.04785635,  0.04171623,  0.04942273], dtype=float32),
 'reward': array(0., dtype=float32),
 'step_type': array(0, dtype=int32)})
Next time step:
TimeStep(
{'discount': array(1., dtype=float32),
 'observation': array([ 0.02188464,  0.14664337,  0.04270469, -0.22981201], dtype=float32),
 'reward': array(1., dtype=float32),
 'step_type': array(1, dtype=int32)})

معمولا ما دو محیط ایجاد می کنیم: یکی برای آموزش و دیگری برای ارزیابی. اکثر محیط در پایتون خالص نوشته شده است، اما می توان آنها را به راحتی به TensorFlow با استفاده از تبدیل TFPyEnvironment لفاف بسته بندی. API محیط اصلی را با استفاده از آرایه های نامپای از TFPyEnvironment این تبدیل به / از Tensors برای شما به راحتی بیشتر تعامل با سیاست های TensorFlow و عوامل.

train_py_env = suite_gym.load(env_name)
eval_py_env = suite_gym.load(env_name)

train_env = tf_py_environment.TFPyEnvironment(train_py_env)
eval_env = tf_py_environment.TFPyEnvironment(eval_py_env)

عامل

الگوریتمی که استفاده می کنیم برای حل یک مشکل RL به عنوان یک نشان Agent . علاوه بر عامل تقویت، TF-نمایندگی فراهم می کند پیاده سازی استاندارد از انواع Agents مانند DQN ، DDPG ، TD3 ، PPO و SAC .

برای ایجاد یک تقویت کننده، ما برای اولین بار نیاز به یک Actor Network که می توانند یاد بگیرند برای پیش بینی عمل با توجه به مشاهدات از محیط زیست است.

ما به راحتی می توانید ایجاد Actor Network با استفاده از مشخصات از مشاهدات و اقدامات. ما می توانیم لایه ها در شبکه که در این مثال، مشخص می fc_layer_params مجموعه آرگومان به یک تاپل از ints به نمایندگی از اندازه از هر یک از لایه های پنهان (بخش Hyperparameters بالا را ببینید).

actor_net = actor_distribution_network.ActorDistributionNetwork(
    train_env.observation_spec(),
    train_env.action_spec(),
    fc_layer_params=fc_layer_params)

ما همچنین نیاز به یک optimizer برای آموزش شبکه ما فقط ایجاد و train_step_counter متغیر برای پیگیری چند بار شبکه به روز شد.

optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)

train_step_counter = tf.Variable(0)

tf_agent = reinforce_agent.ReinforceAgent(
    train_env.time_step_spec(),
    train_env.action_spec(),
    actor_network=actor_net,
    optimizer=optimizer,
    normalize_returns=True,
    train_step_counter=train_step_counter)
tf_agent.initialize()

سیاست های

در TF-عوامل، سیاست های نشان دهنده مفهوم استاندارد از سیاست در RL: با توجه به time_step تولید یک عمل یا یک توزیع بیش از اقدامات. روش اصلی است policy_step = policy.action(time_step) که در آن policy_step یک تاپل به نام PolicyStep(action, state, info) . policy_step.action است action به به محیط زیست استفاده شود، state نشان دهنده دولت برای stateful به (RNN) سیاست ها و info ممکن است مانند احتمال ورود به سیستم از اقدامات حاوی اطلاعات کمکی.

عامل ها شامل دو خط مشی هستند: خط مشی اصلی که برای ارزیابی/استقرار استفاده می شود (agent.policy) و خط مشی دیگری که برای جمع آوری داده ها استفاده می شود (agent.collect_policy).

eval_policy = tf_agent.policy
collect_policy = tf_agent.collect_policy

معیارها و ارزیابی

رایج ترین معیاری که برای ارزیابی یک سیاست استفاده می شود، میانگین بازده است. بازده مجموع پاداش‌هایی است که هنگام اجرای یک سیاست در یک محیط برای یک قسمت به دست می‌آید، و معمولاً این مقدار را در چند قسمت به طور میانگین می‌گیریم. می‌توانیم میانگین بازدهی را به صورت زیر محاسبه کنیم.

def compute_avg_return(environment, policy, num_episodes=10):

  total_return = 0.0
  for _ in range(num_episodes):

    time_step = environment.reset()
    episode_return = 0.0

    while not time_step.is_last():
      action_step = policy.action(time_step)
      time_step = environment.step(action_step.action)
      episode_return += time_step.reward
    total_return += episode_return

  avg_return = total_return / num_episodes
  return avg_return.numpy()[0]


# Please also see the metrics module for standard implementations of different
# metrics.

پخش مجدد بافر

به منظور پیگیری از داده های جمع آوری شده از محیط زیست، ما استفاده ی Reverb ، یک سیستم پخش کارآمد، توسعه، و آسان برای استفاده توسط Deepmind. هنگامی که ما مسیرها را جمع آوری می کنیم، داده های تجربه را ذخیره می کند و در طول آموزش مصرف می شود.

این بافر پخش با استفاده از مشخصات توصیف تانسورها که به ذخیره می شود، که می تواند از عامل با استفاده از به دست آمده ساخته شده است tf_agent.collect_data_spec .

table_name = 'uniform_table'
replay_buffer_signature = tensor_spec.from_spec(
      tf_agent.collect_data_spec)
replay_buffer_signature = tensor_spec.add_outer_dim(
      replay_buffer_signature)
table = reverb.Table(
    table_name,
    max_size=replay_buffer_capacity,
    sampler=reverb.selectors.Uniform(),
    remover=reverb.selectors.Fifo(),
    rate_limiter=reverb.rate_limiters.MinSize(1),
    signature=replay_buffer_signature)

reverb_server = reverb.Server([table])

replay_buffer = reverb_replay_buffer.ReverbReplayBuffer(
    tf_agent.collect_data_spec,
    table_name=table_name,
    sequence_length=None,
    local_server=reverb_server)

rb_observer = reverb_utils.ReverbAddEpisodeObserver(
    replay_buffer.py_client,
    table_name,
    replay_buffer_capacity
)
[reverb/cc/platform/tfrecord_checkpointer.cc:150]  Initializing TFRecordCheckpointer in /tmp/tmpem6la471.
[reverb/cc/platform/tfrecord_checkpointer.cc:385] Loading latest checkpoint from /tmp/tmpem6la471
[reverb/cc/platform/default/server.cc:71] Started replay server on port 19822

برای بسیاری از عوامل، collect_data_spec است Trajectory به نام تاپل حاوی مشاهده، عمل، پاداش و غیره

جمع آوری داده ها

همانطور که REINFORCE از کل قسمت ها یاد می گیرد، ما تابعی را برای جمع آوری یک قسمت با استفاده از خط مشی جمع آوری داده های داده شده تعریف می کنیم و داده ها (مشاهدات، اقدامات، پاداش ها و غیره) را به عنوان مسیرها در بافر پخش مجدد ذخیره می کنیم. در اینجا ما از PyDriver برای اجرای حلقه جمع آوری تجربه استفاده می کنیم. شما می توانید اطلاعات بیشتر در مورد راننده TF نمایندگی ها در ما یاد بگیرند آموزش رانندگان .

def collect_episode(environment, policy, num_episodes):

  driver = py_driver.PyDriver(
    environment,
    py_tf_eager_policy.PyTFEagerPolicy(
      policy, use_tf_function=True),
    [rb_observer],
    max_episodes=num_episodes)
  initial_time_step = environment.reset()
  driver.run(initial_time_step)

آموزش عامل

حلقه آموزشی هم شامل جمع آوری داده ها از محیط و هم بهینه سازی شبکه های عامل است. در طول مسیر، ما گاهی اوقات خط مشی نماینده را ارزیابی می کنیم تا ببینیم که چگونه کار می کنیم.

اجرای موارد زیر 3 دقیقه طول می کشد.

try:
  %%time
except:
  pass

# (Optional) Optimize by wrapping some of the code in a graph using TF function.
tf_agent.train = common.function(tf_agent.train)

# Reset the train step
tf_agent.train_step_counter.assign(0)

# Evaluate the agent's policy once before training.
avg_return = compute_avg_return(eval_env, tf_agent.policy, num_eval_episodes)
returns = [avg_return]

for _ in range(num_iterations):

  # Collect a few episodes using collect_policy and save to the replay buffer.
  collect_episode(
      train_py_env, tf_agent.collect_policy, collect_episodes_per_iteration)

  # Use data from the buffer and update the agent's network.
  iterator = iter(replay_buffer.as_dataset(sample_batch_size=1))
  trajectories, _ = next(iterator)
  train_loss = tf_agent.train(experience=trajectories)  

  replay_buffer.clear()

  step = tf_agent.train_step_counter.numpy()

  if step % log_interval == 0:
    print('step = {0}: loss = {1}'.format(step, train_loss.loss))

  if step % eval_interval == 0:
    avg_return = compute_avg_return(eval_env, tf_agent.policy, num_eval_episodes)
    print('step = {0}: Average Return = {1}'.format(step, avg_return))
    returns.append(avg_return)
[reverb/cc/client.cc:163] Sampler and server are owned by the same process (20164) so Table uniform_table is accessed directly without gRPC.
[reverb/cc/client.cc:163] Sampler and server are owned by the same process (20164) so Table uniform_table is accessed directly without gRPC.
[reverb/cc/client.cc:163] Sampler and server are owned by the same process (20164) so Table uniform_table is accessed directly without gRPC.
[reverb/cc/client.cc:163] Sampler and server are owned by the same process (20164) so Table uniform_table is accessed directly without gRPC.
[reverb/cc/client.cc:163] Sampler and server are owned by the same process (20164) so Table uniform_table is accessed directly without gRPC.
step = 25: loss = 0.8549901247024536
[reverb/cc/client.cc:163] Sampler and server are owned by the same process (20164) so Table uniform_table is accessed directly without gRPC.
step = 50: loss = 1.0025296211242676
step = 50: Average Return = 23.200000762939453
[reverb/cc/client.cc:163] Sampler and server are owned by the same process (20164) so Table uniform_table is accessed directly without gRPC.
step = 75: loss = 1.1377763748168945
step = 100: loss = 1.318871021270752
step = 100: Average Return = 159.89999389648438
step = 125: loss = 1.5053682327270508
[reverb/cc/client.cc:163] Sampler and server are owned by the same process (20164) so Table uniform_table is accessed directly without gRPC.
step = 150: loss = 0.8051948547363281
step = 150: Average Return = 184.89999389648438
step = 175: loss = 0.6872963905334473
step = 200: loss = 2.7238712310791016
step = 200: Average Return = 186.8000030517578
step = 225: loss = 0.7495002746582031
step = 250: loss = -0.3333401679992676
step = 250: Average Return = 200.0

تجسم

توطئه ها

ما می‌توانیم مراحل بازگشت را در مقابل مراحل جهانی ترسیم کنیم تا عملکرد نماینده خود را ببینیم. در Cartpole-v0 ، محیط زیست می دهد جایزه از 1 برای هر مرحله زمان باقی می ماند قطب، و از حداکثر تعداد مراحل 200، حداکثر بازگشت نیز امکان پذیر است 200.

steps = range(0, num_iterations + 1, eval_interval)
plt.plot(steps, returns)
plt.ylabel('Average Return')
plt.xlabel('Step')
plt.ylim(top=250)
(-0.2349997997283939, 250.0)

png

فیلم های

تجسم عملکرد یک عامل با رندر کردن محیط در هر مرحله مفید است. قبل از انجام این کار، اجازه دهید ابتدا یک تابع برای جاسازی ویدیوها در این colab ایجاد کنیم.

def embed_mp4(filename):
  """Embeds an mp4 file in the notebook."""
  video = open(filename,'rb').read()
  b64 = base64.b64encode(video)
  tag = '''
  <video width="640" height="480" controls>
    <source src="data:video/mp4;base64,{0}" type="video/mp4">
  Your browser does not support the video tag.
  </video>'''.format(b64.decode())

  return IPython.display.HTML(tag)

کد زیر خط مشی عامل را برای چند قسمت به تصویر می کشد:

num_episodes = 3
video_filename = 'imageio.mp4'
with imageio.get_writer(video_filename, fps=60) as video:
  for _ in range(num_episodes):
    time_step = eval_env.reset()
    video.append_data(eval_py_env.render())
    while not time_step.is_last():
      action_step = tf_agent.policy.action(time_step)
      time_step = eval_env.step(action_step.action)
      video.append_data(eval_py_env.render())

embed_mp4(video_filename)
WARNING:root:IMAGEIO FFMPEG_WRITER WARNING: input image is not divisible by macro_block_size=16, resizing from (400, 600) to (400, 608) to ensure video compatibility with most codecs and players. To prevent resizing, make your input image divisible by the macro_block_size or set the macro_block_size to None (risking incompatibility). You may also see a FFMPEG warning concerning speedloss due to data not being aligned.
[swscaler @ 0x5604d224f3c0] Warning: data is not aligned! This can lead to a speed loss