Copyright 2021 Os autores do TF-Agents.
![]() | ![]() | ![]() | ![]() |
Introdução
Um padrão comum na aprendizagem por reforço é executar uma política em um ambiente por um número especificado de etapas ou episódios. Isso acontece, por exemplo, durante a coleta de dados, avaliação e geração de um vídeo do agente.
Enquanto isso é relativamente simples escrever em python, é muito mais complexo para escrever e depurar em TensorFlow porque envolve tf.while
loops, tf.cond
e tf.control_dependencies
. Portanto, abstraímos essa noção de um loop de execução em uma classe chamada driver
e fornecemos implementações bem testadas em Python e TensorFlow.
Além disso, os dados encontrados pelo driver em cada etapa são salvos em uma tupla nomeada chamada Trajetória e transmitidos a um conjunto de observadores, como buffers de reprodução e métricas. Esses dados incluem a observação do meio ambiente, a ação recomendada pela política, a recompensa obtida, o tipo do atual e o próximo passo, etc.
Configuração
Se você ainda não instalou tf-agents ou gym, execute:
pip install -q tf-agents
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from tf_agents.environments import suite_gym
from tf_agents.environments import tf_py_environment
from tf_agents.policies import random_py_policy
from tf_agents.policies import random_tf_policy
from tf_agents.metrics import py_metrics
from tf_agents.metrics import tf_metrics
from tf_agents.drivers import py_driver
from tf_agents.drivers import dynamic_episode_driver
tf.compat.v1.enable_v2_behavior()
Drivers Python
A classe PyDriver
usa um ambiente python, uma política python e uma lista de observadores para atualizar a cada etapa. O método principal é run()
, que analisa o ambiente usando ações da política até que pelo menos um dos seguintes critérios de encerramento seja atendido: O número de etapas atinge max_steps
ou o número de episódios atinge max_episodes
.
A implementação é aproximadamente a seguinte:
class PyDriver(object):
def __init__(self, env, policy, observers, max_steps=1, max_episodes=1):
self._env = env
self._policy = policy
self._observers = observers or []
self._max_steps = max_steps or np.inf
self._max_episodes = max_episodes or np.inf
def run(self, time_step, policy_state=()):
num_steps = 0
num_episodes = 0
while num_steps < self._max_steps and num_episodes < self._max_episodes:
# Compute an action using the policy for the given time_step
action_step = self._policy.action(time_step, policy_state)
# Apply the action to the environment and get the next step
next_time_step = self._env.step(action_step.action)
# Package information into a trajectory
traj = trajectory.Trajectory(
time_step.step_type,
time_step.observation,
action_step.action,
action_step.info,
next_time_step.step_type,
next_time_step.reward,
next_time_step.discount)
for observer in self._observers:
observer(traj)
# Update statistics to check termination
num_episodes += np.sum(traj.is_last())
num_steps += np.sum(~traj.is_boundary())
time_step = next_time_step
policy_state = action_step.state
return time_step, policy_state
Agora, vamos examinar o exemplo de execução de uma política aleatória no ambiente CartPole, salvando os resultados em um buffer de reprodução e calculando algumas métricas.
env = suite_gym.load('CartPole-v0')
policy = random_py_policy.RandomPyPolicy(time_step_spec=env.time_step_spec(),
action_spec=env.action_spec())
replay_buffer = []
metric = py_metrics.AverageReturnMetric()
observers = [replay_buffer.append, metric]
driver = py_driver.PyDriver(
env, policy, observers, max_steps=20, max_episodes=1)
initial_time_step = env.reset()
final_time_step, _ = driver.run(initial_time_step)
print('Replay Buffer:')
for traj in replay_buffer:
print(traj)
print('Average Return: ', metric.result())
Replay Buffer: Trajectory(step_type=array(0, dtype=int32), observation=array([-0.00990336, -0.0200395 , 0.00614474, 0.02728521], dtype=float32), action=array(1), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.01030415, 0.1749938 , 0.00669044, -0.26345268], dtype=float32), action=array(0), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.00680427, -0.02022301, 0.00142139, 0.03133296], dtype=float32), action=array(0), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.00720873, -0.21536532, 0.00204805, 0.32446402], dtype=float32), action=array(1), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.01151604, -0.02027259, 0.00853733, 0.03242766], dtype=float32), action=array(0), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.01192149, -0.21551593, 0.00918588, 0.32779193], dtype=float32), action=array(1), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.01623181, -0.02052594, 0.01574172, 0.03801991], dtype=float32), action=array(1), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.01664233, 0.17436677, 0.01650212, -0.24965507], dtype=float32), action=array(0), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.01315499, -0.0209869 , 0.01150902, 0.04818695], dtype=float32), action=array(0), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.01357473, -0.21627198, 0.01247276, 0.34447876], dtype=float32), action=array(1), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.01790017, -0.02132966, 0.01936233, 0.05575491], dtype=float32), action=array(0), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.01832676, -0.21672381, 0.02047743, 0.35448337], dtype=float32), action=array(1), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.02266124, -0.02189892, 0.0275671 , 0.06832724], dtype=float32), action=array(0), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.02309922, -0.21740502, 0.02893364, 0.3695787 ], dtype=float32), action=array(0), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.02744732, -0.41292587, 0.03632522, 0.6712425 ], dtype=float32), action=array(1), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.03570583, -0.21832724, 0.04975007, 0.39021435], dtype=float32), action=array(1), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.04007238, -0.02394538, 0.05755435, 0.11362283], dtype=float32), action=array(0), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.04055129, -0.21984278, 0.05982681, 0.42389402], dtype=float32), action=array(0), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.04494815, -0.41575894, 0.06830469, 0.7348211 ], dtype=float32), action=array(1), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Trajectory(step_type=array(1, dtype=int32), observation=array([-0.05326332, -0.22164375, 0.08300111, 0.46439326], dtype=float32), action=array(0), policy_info=(), next_step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32)) Average Return: 0.0
Drivers TensorFlow
Também temos drivers no TensorFlow que são funcionalmente semelhantes aos drivers Python, mas usam ambientes TF, políticas TF, observadores TF etc. Atualmente temos 2 drivers TensorFlow: DynamicStepDriver
, que termina após um determinado número de etapas de ambiente (válidas) e DynamicEpisodeDriver
, que termina após um determinado número de episódios. Vejamos um exemplo do DynamicEpisode em ação.
env = suite_gym.load('CartPole-v0')
tf_env = tf_py_environment.TFPyEnvironment(env)
tf_policy = random_tf_policy.RandomTFPolicy(action_spec=tf_env.action_spec(),
time_step_spec=tf_env.time_step_spec())
num_episodes = tf_metrics.NumberOfEpisodes()
env_steps = tf_metrics.EnvironmentSteps()
observers = [num_episodes, env_steps]
driver = dynamic_episode_driver.DynamicEpisodeDriver(
tf_env, tf_policy, observers, num_episodes=2)
# Initial driver.run will reset the environment and initialize the policy.
final_time_step, policy_state = driver.run()
print('final_time_step', final_time_step)
print('Number of Steps: ', env_steps.result().numpy())
print('Number of Episodes: ', num_episodes.result().numpy())
final_time_step TimeStep(step_type=<tf.Tensor: shape=(1,), dtype=int32, numpy=array([0], dtype=int32)>, reward=<tf.Tensor: shape=(1,), dtype=float32, numpy=array([0.], dtype=float32)>, discount=<tf.Tensor: shape=(1,), dtype=float32, numpy=array([1.], dtype=float32)>, observation=<tf.Tensor: shape=(1, 4), dtype=float32, numpy= array([[ 0.03522634, 0.02645643, -0.03399573, 0.01959801]], dtype=float32)>) Number of Steps: 44 Number of Episodes: 2
# Continue running from previous state
final_time_step, _ = driver.run(final_time_step, policy_state)
print('final_time_step', final_time_step)
print('Number of Steps: ', env_steps.result().numpy())
print('Number of Episodes: ', num_episodes.result().numpy())
final_time_step TimeStep(step_type=<tf.Tensor: shape=(1,), dtype=int32, numpy=array([0], dtype=int32)>, reward=<tf.Tensor: shape=(1,), dtype=float32, numpy=array([0.], dtype=float32)>, discount=<tf.Tensor: shape=(1,), dtype=float32, numpy=array([1.], dtype=float32)>, observation=<tf.Tensor: shape=(1, 4), dtype=float32, numpy=array([[0.03159906, 0.03318344, 0.01724435, 0.01201768]], dtype=float32)>) Number of Steps: 84 Number of Episodes: 4