Copyright 2021 Autorzy TF-Agents.
Zobacz na TensorFlow.org | Uruchom w Google Colab | Wyświetl źródło na GitHub | Pobierz notatnik |
Wstęp
Ten przykład pokazuje, jak trenować WZMOCNIENIA środka na środowisko Cartpole wykorzystaniem biblioteki TF-agentów, podobną do samouczka DQN .
Przeprowadzimy Cię przez wszystkie komponenty potoku Wzmocnienie uczenia się (RL) w celu szkolenia, oceny i gromadzenia danych.
Ustawiać
Jeśli nie zainstalowałeś następujących zależności, uruchom:
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()
Hiperparametry
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"}
Środowisko
Środowiska w RL reprezentują zadanie lub problem, który próbujemy rozwiązać. Standardowe środowisk mogą być łatwo tworzone w TF-agentów korzystających z suites
. Mamy różne suites
do ładowania środowiska ze źródeł takich jak OpenAI Siłownia, Atari, DM Kontroli itd podano nazwę środowisko ciąg.
Teraz załadujmy środowisko CartPole z pakietu OpenAI Gym.
env = suite_gym.load(env_name)
Możemy renderować to środowisko, aby zobaczyć, jak wygląda. Do wózka przymocowany jest swobodnie bujający się drążek. Celem jest przesunięcie wózka w prawo lub w lewo, aby utrzymać drążek skierowany do góry.
env.reset()
PIL.Image.fromarray(env.render())
time_step = environment.step(action)
oświadczenie wykonuje action
w środowisku. TimeStep
krotka zwrócony zawiera środowiska następny obserwacji i nagrodę dla tego działania. time_step_spec()
i action_spec()
metodami w środowisku zwrócić dane (typ, kształty, przedział) z time_step
i action
odpowiednio.
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)
Widzimy więc, że obserwacja to tablica 4 pływaków: położenie i prędkość wózka oraz położenie kątowe i prędkość bieguna. Ponieważ tylko dwa działania są możliwe (ruch w lewo lub w prawo przesunąć), przy czym action_spec
jest skalarne, gdzie 0 oznacza „ruch w lewo”, a 1 oznacza „dobry ruch.”
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)})
Zazwyczaj tworzymy dwa środowiska: jedno do szkolenia, drugie do ewaluacji. Większość środowisk są napisane w czystym Pythonie, ale mogą być łatwo przekształcone do TensorFlow pomocą TFPyEnvironment
opakowanie. Oryginalne środowisko API używa numpy tablice The TFPyEnvironment
konwertuje je do / z Tensors
, aby łatwiej współdziałać z polityką TensorFlow i agentów.
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
Algorytm, którego używamy, aby rozwiązać problem RL jest reprezentowany jako Agent
. Oprócz środka wzmocnić TF-agentów zawiera standardowe implementacje wielu Agents
jak DQN , DDPG , TD3 , PPO i PKA .
Aby utworzyć WZMOCNIENIA agenta, najpierw musimy się Actor Network
, które mogą nauczyć się przewidywać działania danej obserwacji z otoczenia.
Możemy łatwo stworzyć Actor Network
używając specyfikacje obserwacji i działań. Możemy określić warstw w sieci, który w tym przykładzie jest fc_layer_params
zestaw argument krotką ints
reprezentujących rozmiary każdej warstwie ukrytej (patrz sekcja hiperparametrów powyżej).
actor_net = actor_distribution_network.ActorDistributionNetwork(
train_env.observation_spec(),
train_env.action_spec(),
fc_layer_params=fc_layer_params)
My również potrzebujemy optimizer
do trenowania sieci właśnie utworzony i train_step_counter
zmienną śledzić ile razy sieć została zaktualizowana.
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()
Zasady
W TF-pełnomocników, polityka stanowią standardową koncepcję polityki w RL: dali time_step
wytwarzają działanie lub dystrybucję nad działaniami. Główną metodą jest policy_step = policy.action(time_step)
gdzie policy_step
to nazwana krotki PolicyStep(action, state, info)
. policy_step.action
jest action
, które należy stosować w środowisku, state
reprezentuje stan na stanowych (RNN) polityk i info
mogą zawierać informacje pomocnicze, takie jak prawdopodobieństw dziennika działań.
Agenci zawierają dwie zasady: główną zasadę używaną do oceny/wdrażania (agent.policy) i inną zasadę używaną do zbierania danych (agent.collect_policy).
eval_policy = tf_agent.policy
collect_policy = tf_agent.collect_policy
Metryki i ocena
Najczęstszym miernikiem używanym do oceny zasad jest średni zwrot. Zwrot to suma nagród uzyskanych podczas prowadzenia polisy w środowisku dla odcinka, i zwykle uśredniamy to dla kilku odcinków. Metrykę średniego zwrotu możemy obliczyć w następujący sposób.
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.
Bufor powtórek
W celu śledzenia danych zebranych ze środowiska użyjemy Reverb , sprawny, rozszerzalny i łatwy w obsłudze system powtórka przez Deepmind. Przechowuje dane dotyczące doświadczenia, gdy zbieramy trajektorie i jest zużywane podczas treningu.
Bufor odtwarzania jest wykonana przy użyciu specyfikacje opisujące tensory, które mają być przechowywane, które mogą być otrzymane z użyciem środka 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
Dla większości agentów The collect_data_spec
jest Trajectory
nazwie krotka zawierająca obserwacji, działania, itp nagradzać
Zbieranie danych
Ponieważ REINFORCE uczy się z całych odcinków, definiujemy funkcję do zbierania odcinka przy użyciu określonej polityki zbierania danych i zapisywania danych (obserwacji, działań, nagród itp.) jako trajektorii w buforze powtórek. Tutaj używamy „PyDriver”, aby uruchomić pętlę zbierania doświadczeń. Możesz dowiedzieć się więcej o kierowcy TF agentów w naszym poradniku kierowców .
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)
Szkolenie agenta
Pętla treningowa obejmuje zarówno zbieranie danych z otoczenia, jak i optymalizację sieci agenta. Po drodze będziemy od czasu do czasu oceniać politykę agenta, aby zobaczyć, jak sobie radzimy.
Wykonanie poniższych czynności zajmie około 3 minut.
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
Wyobrażanie sobie
Działki
Możemy wykreślić zwrot z globalnych kroków, aby zobaczyć wydajność naszego agenta. W Cartpole-v0
, środowisko daje nagrodę +1 dla każdego kroku czasowego na biegun zatrzymuje się, a ponieważ maksymalna liczba kroków wynosi 200, maksymalny możliwy powrót jest również 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)
Filmy
Pomocna jest wizualizacja wydajności agenta poprzez renderowanie środowiska na każdym kroku. Zanim to zrobimy, stwórzmy najpierw funkcję do osadzania filmów w tej kolaboracji.
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)
Poniższy kod wizualizuje politykę agenta dla kilku odcinków:
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