REINFORCE-Agent

Auf TensorFlow.org ansehen In Google Colab ausführen Quelle auf GitHub anzeigen Notizbuch herunterladen

Einführung

Dieses Beispiel zeigt , wie man trainiert ein VERSTÄRKUNG - Agenten auf der Cartpole Umwelt unter Verwendung der TF-Agents Bibliothek, ähnlich das DQN Tutorial .

Cartpole-Umgebung

Wir führen Sie durch alle Komponenten einer Reinforcement Learning (RL)-Pipeline für Schulung, Auswertung und Datenerfassung.

Aufstellen

Wenn Sie die folgenden Abhängigkeiten nicht installiert haben, führen Sie Folgendes aus:

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 tensorflow as tf

from tf_agents.agents.reinforce import reinforce_agent
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.replay_buffers import tf_uniform_replay_buffer
from tf_agents.trajectories import trajectory
from tf_agents.utils import common

tf.compat.v1.enable_v2_behavior()


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

Hyperparameter

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"}

Umfeld

Umgebungen in RL repräsentieren die Aufgabe oder das Problem, das wir zu lösen versuchen. Standard - Umgebungen können leicht in TF-Agents verwenden erstellt suites . Wir haben verschiedene suites für Umgebungen aus Quellen wie dem OpenAI Gym, Atari, DM - Steuerung, usw., da ein String - Umgebungsnamen geladen.

Laden wir nun die CartPole-Umgebung aus der OpenAI Gym-Suite.

env = suite_gym.load(env_name)

Wir können diese Umgebung rendern, um zu sehen, wie sie aussieht. An einem Wagen ist eine freischwingende Stange befestigt. Ziel ist es, den Wagen nach rechts oder links zu bewegen, damit die Stange nach oben zeigt.

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

png

Die time_step = environment.step(action) Erklärung nimmt action in der Umwelt. Der TimeStep Tupel zurückgegeben enthält die nächste Beobachtung und Belohnung Umgebung für diese Aktion. Die time_step_spec() und action_spec() Verfahren , die in der Umwelt zurück , die Spezifikationen (Typen, Formen, Grenzen) der time_step und action sind.

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)

Wir sehen also, dass die Beobachtung ein Array von 4 Schwimmern ist: die Position und Geschwindigkeit des Wagens und die Winkelposition und Geschwindigkeit der Stange. Da nur zwei Aktionen möglich sind (nach links oder rechts bewegen), die action_spec ist ein Skalar , wo 0 bedeutet und 1 bedeutet „nach links bewegen“ „nach rechts bewegen.“

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.01819531, -0.0004757 ,  0.04323009, -0.01020878], 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.01820482,  0.19400047,  0.04302592, -0.2889448 ], dtype=float32),
 'reward': array(1., dtype=float32),
 'step_type': array(1, dtype=int32)})

Normalerweise erstellen wir zwei Umgebungen: eine für das Training und eine für die Evaluierung. Die meisten Umgebungen sind in reinem Python geschrieben, aber sie können leicht zu TensorFlow mit dem umgewandelt werden TFPyEnvironment - Wrapper. Die API ursprüngliche Umgebung verwendet numpy Arrays, der TFPyEnvironment wandelt diese in / aus Tensors für Sie zu leicht interact mit TensorFlow Richtlinien und Agenten.

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)

Agent

Der Algorithmus , dass wir ein Problem zu lösen RL verwenden , um als ein vertreten Agent . Zusätzlich zu den Agenten verstärken bietet TF-Agents Standardimplementierungen von einer Vielzahl von Agents wie DQN , DDPG , TD3 , PPO und SAC .

So erstellen Sie einen Agenten VERSTÄRKUNG, müssen wir zuerst ein Actor Network - Actor Network , das die Aktion zur Vorhersage lernen kann eine Beobachtung aus der Umgebung gegeben.

Wir können leicht ein erstellen Actor Network mit den Spezifikationen der Beobachtungen und Handlungen. Wir können die Schichten in dem Netzwerk angeben, die in diesem Beispiel das ist fc_layer_params Argument Satz ein Tupel von ints die Größen der einzelnen versteckten Schicht darstellt (siehe den Hyper Abschnitt oben).

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

Wir brauchen auch einen optimizer das Netzwerk , das wir gerade erstellt hat , und zu trainieren train_step_counter Variable , um zu verfolgen , wie oft das Netzwerk aktualisiert wurde.

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

train_step_counter = tf.compat.v2.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()
2021-08-21 11:08:25.412037: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 11:08:25.420416: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 11:08:25.421446: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 11:08:25.423385: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 AVX512F FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2021-08-21 11:08:25.423977: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 11:08:25.424956: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 11:08:25.425903: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 11:08:26.054444: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 11:08:26.055477: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 11:08:26.056418: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 11:08:26.057337: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1510] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 14648 MB memory:  -> device: 0, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:05.0, compute capability: 7.0

Richtlinien

In TF-Agenten stellt Politik den Standard Begriff der Politik in RL: Da ein time_step eine Aktion oder eine Verteilung über Aktionen erzeugen. Die wichtigste Methode ist policy_step = policy.action(time_step) , wo policy_step ist ein benannter Tupel PolicyStep(action, state, info) . Die policy_step.action die ist action für die Umwelt anzuwenden, state stellt den Zustand für Stateful (RNN) Richtlinien und info Zusatzinformationen enthalten, wie Protokoll Wahrscheinlichkeiten der Aktionen.

Agenten enthalten zwei Richtlinien: die Hauptrichtlinie, die für die Evaluierung/Bereitstellung verwendet wird (agent.policy) und eine weitere Richtlinie, die für die Datenerfassung verwendet wird (agent.collect_policy).

eval_policy = tf_agent.policy
collect_policy = tf_agent.collect_policy

Metriken und Auswertung

Die am häufigsten verwendete Kennzahl zur Bewertung einer Richtlinie ist die durchschnittliche Rendite. Die Rendite ist die Summe der Belohnungen, die Sie erhalten, wenn Sie eine Police in einer Umgebung für eine Episode ausführen, und wir mitteln diese normalerweise über einige Episoden. Wir können die durchschnittliche Renditemetrik wie folgt berechnen.

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.

Wiedergabepuffer

Um den Überblick über die gesammelten Daten aus der Umgebung zu behalten, verwenden wir den TFUniformReplayBuffer. Diese Wiedergabepuffer sind so konstruiert , Spezifikationen mit den Tensoren beschreiben , die zu speichern sind, die von dem Agenten unter Verwendung erhalten werden können tf_agent.collect_data_spec .

replay_buffer = tf_uniform_replay_buffer.TFUniformReplayBuffer(
    data_spec=tf_agent.collect_data_spec,
    batch_size=train_env.batch_size,
    max_length=replay_buffer_capacity)

Für die meisten Agenten, die collect_data_spec ist eine Trajectory genannt Tupel enthält die Beobachtung, Aktion, belohnen usw.

Datensammlung

Da REINFORCE aus ganzen Episoden lernt, definieren wir eine Funktion, um eine Episode mit der gegebenen Datensammlungsrichtlinie zu sammeln und die Daten (Beobachtungen, Aktionen, Belohnungen usw.) als Trajektorien im Wiedergabepuffer zu speichern.

def collect_episode(environment, policy, num_episodes):

  episode_counter = 0
  environment.reset()

  while episode_counter < num_episodes:
    time_step = environment.current_time_step()
    action_step = policy.action(time_step)
    next_time_step = environment.step(action_step.action)
    traj = trajectory.from_transition(time_step, action_step, next_time_step)

    # Add trajectory to the replay buffer
    replay_buffer.add_batch(traj)

    if traj.is_boundary():
      episode_counter += 1


# This loop is so common in RL, that we provide standard implementations of
# these. For more details see the drivers module.

Schulung des Agenten

Die Trainingsschleife umfasst sowohl das Sammeln von Daten aus der Umgebung als auch die Optimierung der Netzwerke des Agenten. Unterwegs werden wir gelegentlich die Richtlinien des Agenten bewerten, um zu sehen, wie es uns geht.

Die Ausführung der folgenden Schritte dauert ~3 Minuten.

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_env, tf_agent.collect_policy, collect_episodes_per_iteration)

  # Use data from the buffer and update the agent's network.
  experience = replay_buffer.gather_all()
  train_loss = tf_agent.train(experience)
  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)
WARNING:tensorflow:From /tmp/ipykernel_25952/1685850678.py:24: ReplayBuffer.gather_all (from tf_agents.replay_buffers.replay_buffer) is deprecated and will be removed in a future version.
Instructions for updating:
Use `as_dataset(..., single_deterministic_pass=True)` instead.
2021-08-21 11:08:28.113107: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:185] None of the MLIR Optimization Passes are enabled (registered 2)
step = 25: loss = -0.04456901550292969
step = 50: loss = 0.5135548114776611
step = 50: Average Return = 78.80000305175781
step = 75: loss = 0.12783002853393555
step = 100: loss = -0.9588792324066162
step = 100: Average Return = 137.39999389648438
step = 125: loss = -3.0638797283172607
step = 150: loss = 0.46179866790771484
step = 150: Average Return = 184.39999389648438
step = 175: loss = -1.0802335739135742
step = 200: loss = -3.6960906982421875
step = 200: Average Return = 200.0
step = 225: loss = -5.610248565673828
step = 250: loss = 0.6127729415893555
step = 250: Average Return = 200.0

Visualisierung

Grundstücke

Wir können die Rendite im Vergleich zu den globalen Schritten darstellen, um die Leistung unseres Agenten zu sehen. In Cartpole-v0 gibt die Umwelt eine Belohnung von +1 für jeden Zeitschritt der Pole Aufenthalte auf, und da die maximale Anzahl von Schritten 200 ist die maximal mögliche Rendite ist auch 200.

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

png

Videos

Es ist hilfreich, die Leistung eines Agenten zu visualisieren, indem die Umgebung bei jedem Schritt gerendert wird. Bevor wir das tun, erstellen wir zunächst eine Funktion zum Einbetten von Videos in diese 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)

Der folgende Code visualisiert die Richtlinie des Agenten für einige Episoden:

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 @ 0x55a995bd53c0] Warning: data is not aligned! This can lead to a speed loss