Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Buffer di replay

Visualizza su TensorFlow.org Esegui in Google Colab Visualizza sorgente su GitHub Scarica notebook

introduzione

Gli algoritmi di apprendimento per rinforzo utilizzano i buffer di riproduzione per memorizzare le traiettorie dell'esperienza durante l'esecuzione di una politica in un ambiente. Durante l'addestramento, i buffer di riproduzione vengono interrogati per un sottoinsieme delle traiettorie (un sottoinsieme sequenziale o un campione) per "riprodurre" l'esperienza dell'agente.

In questa raccolta, esploriamo due tipi di buffer di riproduzione: supportati da python e supportati da tensorflow, condividendo un'API comune. Nelle sezioni seguenti, descriviamo l'API, ciascuna delle implementazioni del buffer e come utilizzarle durante l'addestramento alla raccolta dati.

Impostare

Installa tf-agent se non l'hai già fatto.

pip install -q tf-agents
pip install -q gym
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tensorflow as tf
import numpy as np

from tf_agents import specs
from tf_agents.agents.dqn import dqn_agent
from tf_agents.drivers import dynamic_step_driver
from tf_agents.environments import suite_gym
from tf_agents.environments import tf_py_environment
from tf_agents.networks import q_network
from tf_agents.replay_buffers import py_uniform_replay_buffer
from tf_agents.replay_buffers import tf_uniform_replay_buffer
from tf_agents.specs import tensor_spec
from tf_agents.trajectories import time_step

tf.compat.v1.enable_v2_behavior()

Replay Buffer API

La classe Replay Buffer ha la definizione e i metodi seguenti:

class ReplayBuffer(tf.Module):
  """Abstract base class for TF-Agents replay buffer."""

  def __init__(self, data_spec, capacity):
    """Initializes the replay buffer.

    Args:
      data_spec: A spec or a list/tuple/nest of specs describing
        a single item that can be stored in this buffer
      capacity: number of elements that the replay buffer can hold.
    """

  @property
  def data_spec(self):
    """Returns the spec for items in the replay buffer."""

  @property
  def capacity(self):
    """Returns the capacity of the replay buffer."""

  def add_batch(self, items):
    """Adds a batch of items to the replay buffer."""

  def get_next(self,
               sample_batch_size=None,
               num_steps=None,
               time_stacked=True):
    """Returns an item or batch of items from the buffer."""

  def as_dataset(self,
                 sample_batch_size=None,
                 num_steps=None,
                 num_parallel_calls=None):
    """Creates and returns a dataset that returns entries from the buffer."""


  def gather_all(self):
    """Returns all the items in buffer."""
    return self._gather_all()

  def clear(self):
    """Resets the contents of replay buffer"""

Notare che quando l'oggetto buffer di riproduzione viene inizializzato, richiede data_spec degli elementi che memorizzerà. Questa specifica corrisponde alla TensorSpec degli elementi di traiettoria che verranno aggiunti al buffer. Questa specifica viene solitamente acquisita guardando agent.collect_data_spec un agente che definisce le forme, i tipi e le strutture attesi dall'agente durante l'addestramento (ne agent.collect_data_spec più avanti)

TFUniformReplayBuffer

TFUniformReplayBuffer è il replay buffer più comunemente usato in TF-Agents, quindi lo useremo nel nostro tutorial qui. In TFUniformReplayBuffer la memorizzazione del buffer di backup viene eseguita dalle variabili tensorflow e quindi fa parte del grafico di calcolo.

Il buffer memorizza batch di elementi e ha una capacità massima max_length elementi per segmento batch. Pertanto, la capacità del buffer totale è batch_size x max_length elementi. Gli elementi memorizzati nel buffer devono avere tutti una specifica dati corrispondente. Quando il buffer di riproduzione viene utilizzato per la raccolta dei dati, la specifica è la specifica di raccolta dei dati dell'agente.

Creazione del buffer:

Per creare un TFUniformReplayBuffer passiamo:

  1. la specifica degli elementi di dati che il buffer memorizzerà
  2. la batch size del batch size corrispondente alla dimensione del batch del buffer
  3. il numero max_length di elementi per segmento batch

Di seguito è riportato un esempio di creazione di un TFUniformReplayBuffer con specifiche dei dati di esempio, batch_size 32 e max_length 1000.

data_spec =  (
        tf.TensorSpec([3], tf.float32, 'action'),
        (
            tf.TensorSpec([5], tf.float32, 'lidar'),
            tf.TensorSpec([3, 2], tf.float32, 'camera')
        )
)

batch_size = 32
max_length = 1000

replay_buffer = tf_uniform_replay_buffer.TFUniformReplayBuffer(
    data_spec,
    batch_size=batch_size,
    max_length=max_length)

Scrittura nel buffer:

Per aggiungere elementi al buffer di riproduzione, usiamo il add_batch(items) dove items è una lista / tupla / nido di tensori che rappresenta il batch di elementi da aggiungere al buffer. Ogni elemento di items deve avere una dimensione esterna uguale batch_size e le dimensioni rimanenti devono aderire alla specifica dei dati dell'elemento (come le specifiche dei dati passate al costruttore del buffer di riproduzione).

Ecco un esempio di aggiunta di un lotto di articoli

action = tf.constant(1 * np.ones(
    data_spec[0].shape.as_list(), dtype=np.float32))
lidar = tf.constant(
    2 * np.ones(data_spec[1][0].shape.as_list(), dtype=np.float32))
camera = tf.constant(
    3 * np.ones(data_spec[1][1].shape.as_list(), dtype=np.float32))
  
values = (action, (lidar, camera))
values_batched = tf.nest.map_structure(lambda t: tf.stack([t] * batch_size),
                                       values)
  
replay_buffer.add_batch(values_batched)

Lettura dal buffer

Esistono tre modi per leggere i dati da TFUniformReplayBuffer :

  1. get_next() - restituisce un campione dal buffer. La dimensione del batch campione e il numero di timestep restituiti possono essere specificati tramite gli argomenti di questo metodo.
  2. as_dataset() - restituisce il buffer di riproduzione come tf.data.Dataset . È quindi possibile creare un iteratore del set di dati e iterare attraverso i campioni degli elementi nel buffer.
  3. gather_all() - restituisce tutti gli elementi nel buffer come un tensore con forma [batch, time, data_spec]

Di seguito sono riportati esempi di come leggere dal buffer di riproduzione utilizzando ciascuno di questi metodi:

# add more items to the buffer before reading
for _ in range(5):
  replay_buffer.add_batch(values_batched)

# Get one sample from the replay buffer with batch size 10 and 1 timestep:

sample = replay_buffer.get_next(sample_batch_size=10, num_steps=1)

# Convert the replay buffer to a tf.data.Dataset and iterate through it
dataset = replay_buffer.as_dataset(
    sample_batch_size=4,
    num_steps=2)

iterator = iter(dataset)
print("Iterator trajectories:")
trajectories = []
for _ in range(3):
  t, _ = next(iterator)
  trajectories.append(t)
  
print(tf.nest.map_structure(lambda t: t.shape, trajectories))

# Read all elements in the replay buffer:
trajectories = replay_buffer.gather_all()

print("Trajectories from gather all:")
print(tf.nest.map_structure(lambda t: t.shape, trajectories))

WARNING:tensorflow:From <ipython-input-6-1f9907631cb9>:7: ReplayBuffer.get_next (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=False) instead.
Iterator trajectories:
[(TensorShape([4, 2, 3]), (TensorShape([4, 2, 5]), TensorShape([4, 2, 3, 2]))), (TensorShape([4, 2, 3]), (TensorShape([4, 2, 5]), TensorShape([4, 2, 3, 2]))), (TensorShape([4, 2, 3]), (TensorShape([4, 2, 5]), TensorShape([4, 2, 3, 2])))]
WARNING:tensorflow:From <ipython-input-6-1f9907631cb9>: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.
Trajectories from gather all:
(TensorShape([32, 6, 3]), (TensorShape([32, 6, 5]), TensorShape([32, 6, 3, 2])))

PyUniformReplayBuffer

PyUniformReplayBuffer ha le stesse funzionalità di TFUniformReplayBuffer ma invece delle variabili tf, i suoi dati sono memorizzati in array numpy. Questo buffer può essere utilizzato per la raccolta di dati fuori grafico. Avere l'archiviazione di backup in numpy può rendere più facile per alcune applicazioni la manipolazione dei dati (come l'indicizzazione per l'aggiornamento delle priorità) senza utilizzare le variabili Tensorflow. Tuttavia, questa implementazione non avrà il vantaggio delle ottimizzazioni dei grafici con Tensorflow.

Di seguito è riportato un esempio di istanza di un PyUniformReplayBuffer dalle specifiche della traiettoria della politica dell'agente:

replay_buffer_capacity = 1000*32 # same capacity as the TFUniformReplayBuffer

py_replay_buffer = py_uniform_replay_buffer.PyUniformReplayBuffer(
    capacity=replay_buffer_capacity,
    data_spec=tensor_spec.to_nest_array_spec(data_spec))

Utilizzo dei buffer di replay durante l'allenamento

Ora che sappiamo come creare un buffer di replay, scrivere elementi su di esso e leggere da esso, possiamo usarlo per memorizzare le traiettorie durante l'addestramento dei nostri agenti.

Raccolta dati

Per prima cosa, vediamo come utilizzare il buffer di riproduzione durante la raccolta dei dati.

In TF-Agent utilizziamo un Driver (vedere il tutorial sui driver per maggiori dettagli) per raccogliere esperienza in un ambiente. Per utilizzare un Driver , specifichiamo un Observer che è una funzione che il Driver deve eseguire quando riceve una traiettoria.

Quindi, per aggiungere elementi di traiettoria al buffer di replay, aggiungiamo un osservatore che chiama add_batch(items) per aggiungere un (batch di) elementi al buffer di replay.

Di seguito è riportato un esempio di ciò con TFUniformReplayBuffer . Per prima cosa creiamo un ambiente, una rete e un agente. Quindi creiamo un TFUniformReplayBuffer . Notare che le specifiche degli elementi di traiettoria nel buffer di riproduzione sono uguali alle specifiche di raccolta dei dati dell'agente. Quindi impostiamo il suo metodo add_batch come osservatore per il conducente che raccoglierà i dati durante il nostro addestramento:

env = suite_gym.load('CartPole-v0')
tf_env = tf_py_environment.TFPyEnvironment(env)

q_net = q_network.QNetwork(
    tf_env.time_step_spec().observation,
    tf_env.action_spec(),
    fc_layer_params=(100,))

agent = dqn_agent.DqnAgent(
    tf_env.time_step_spec(),
    tf_env.action_spec(),
    q_network=q_net,
    optimizer=tf.compat.v1.train.AdamOptimizer(0.001))

replay_buffer_capacity = 1000

replay_buffer = tf_uniform_replay_buffer.TFUniformReplayBuffer(
    agent.collect_data_spec,
    batch_size=tf_env.batch_size,
    max_length=replay_buffer_capacity)

# Add an observer that adds to the replay buffer:
replay_observer = [replay_buffer.add_batch]

collect_steps_per_iteration = 10
collect_op = dynamic_step_driver.DynamicStepDriver(
  tf_env,
  agent.collect_policy,
  observers=replay_observer,
  num_steps=collect_steps_per_iteration).run()
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tf_agents/drivers/dynamic_step_driver.py:203: calling while_loop_v2 (from tensorflow.python.ops.control_flow_ops) with back_prop=False is deprecated and will be removed in a future version.
Instructions for updating:
back_prop=False is deprecated. Consider using tf.stop_gradient instead.
Instead of:
results = tf.while_loop(c, b, vars, back_prop=False)
Use:
results = tf.nest.map_structure(tf.stop_gradient, tf.while_loop(c, b, vars))

Lettura dei dati per un passaggio del treno

Dopo aver aggiunto elementi di traiettoria al buffer di replay, possiamo leggere batch di traiettorie dal buffer di replay da utilizzare come dati di input per una fase del treno.

Ecco un esempio di come allenarsi sulle traiettorie dal buffer di riproduzione in un ciclo di allenamento:

# Read the replay buffer as a Dataset,
# read batches of 4 elements, each with 2 timesteps:
dataset = replay_buffer.as_dataset(
    sample_batch_size=4,
    num_steps=2)

iterator = iter(dataset)

num_train_steps = 10

for _ in range(num_train_steps):
  trajectories, _ = next(iterator)
  loss = agent.train(experience=trajectories)

WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/util/dispatch.py:201: calling foldr_v2 (from tensorflow.python.ops.functional_ops) with back_prop=False is deprecated and will be removed in a future version.
Instructions for updating:
back_prop=False is deprecated. Consider using tf.stop_gradient instead.
Instead of:
results = tf.foldr(fn, elems, back_prop=False)
Use:
results = tf.nest.map_structure(tf.stop_gradient, tf.foldr(fn, elems))