Буферы воспроизведения

Вступление

Алгоритмы обучения с подкреплением используют буферы воспроизведения для хранения траекторий опыта при выполнении политики в среде. Во время обучения буферы воспроизведения запрашиваются для подмножества траекторий (либо последовательного подмножества, либо выборки), чтобы «воспроизвести» опыт агента.

В этой колабе мы исследуем два типа буферов воспроизведения: поддерживаемые питоном и поддерживаемые тензорным потоком, с общим API. В следующих разделах мы описываем API, каждую из реализаций буфера и способы их использования во время обучения сбору данных.

Настраивать

Установите tf-agent, если вы еще этого не сделали.

pip install tf-agents
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

Replay Buffer API

Класс Replay Buffer имеет следующее определение и методы:

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

Обратите внимание , что , когда объект воспроизведения буфера инициализируется, он требует data_spec элементов , которые он будет хранить. Эта спецификация соответствует TensorSpec траекторных элементов , которые будут добавлены в буфер. Эта спецификация обычно приобретаются, глядя на агент agent.collect_data_spec , который определяет форму, тип и структуры , ожидаемые агентом при обучении (об этом позже).

TFUniformReplayBuffer

TFUniformReplayBuffer является наиболее часто используемым переигровка буфера в TF-агентов, таким образом , мы будем использовать его в нашем учебнике здесь. В TFUniformReplayBuffer буферное хранилище поддержка осуществляется tensorflow переменных и , таким образом , является частью графа вычислений.

Буфер хранит партии элементов и имеет максимальную емкость max_length элементов на пакетном сегменте. Таким образом, общая емкость буфера batch_size х max_length элементов. Все элементы, хранящиеся в буфере, должны иметь соответствующую спецификацию данных. Когда буфер воспроизведения используется для сбора данных, спецификация является спецификацией сбора данных агента.

Создание буфера:

Для создания TFUniformReplayBuffer мы переходим в:

  1. спецификация элементов данных, которые будет хранить буфер
  2. batch size , соответствующего размера партии буфера
  3. max_length количество элементов в пакетном сегменте

Ниже приведен пример создания TFUniformReplayBuffer с образцами спецификации данных, batch_size 32 и 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)

Запись в буфер:

Для добавления элементов в буфер воспроизведения, мы используем add_batch(items) способ , в котором items представляют собой список / кортеж / гнездо тензоров , представляющих партию предметов , которые будут добавлены в буфер. Каждый элемент items должен иметь внешний размер , равный batch_size , а остальные размеры должны соответствовать спецификациям данных элемента (такого же , как спецификации данных , передаваемых в буфере конструктора воспроизведения).

Вот пример добавления партии товаров

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)

Чтение из буфера

Есть три способа считывания данных из TFUniformReplayBuffer :

  1. get_next() - возвращает один образец из буфера. Размер пакета выборки и количество возвращаемых временных шагов можно указать с помощью аргументов этого метода.
  2. as_dataset() - возвращает буфер повтора в качестве tf.data.Dataset . Затем можно создать итератор набора данных и перебирать образцы элементов в буфере.
  3. gather_all() - возвращает все элементы в буфере в качестве тензором с формой [batch, time, data_spec]

Ниже приведены примеры того, как читать из буфера воспроизведения с использованием каждого из этих методов:

# 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 /tmp/ipykernel_15476/1348928897.py: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.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/data/experimental/ops/counter.py:66: scan (from tensorflow.python.data.experimental.ops.scan_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.data.Dataset.scan(...) 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 /tmp/ipykernel_15476/1348928897.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.
Trajectories from gather all:
(TensorShape([32, 6, 3]), (TensorShape([32, 6, 5]), TensorShape([32, 6, 3, 2])))

PyUniformReplayBuffer

PyUniformReplayBuffer имеет тот же functionaly как TFUniformReplayBuffer но вместо Tf переменных, его данные хранятся в Numpy массивов. Этот буфер можно использовать для сбора данных вне графика. Наличие резервного хранилища в numpy может упростить некоторым приложениям манипулирование данными (например, индексацию для обновления приоритетов) без использования переменных Tensorflow. Однако в этой реализации не будет преимуществ оптимизации графов с помощью Tensorflow.

Ниже приведен пример инстанцирования PyUniformReplayBuffer от траекторных политики спецификации поверенного:

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))

Использование буферов воспроизведения во время обучения

Теперь, когда мы знаем, как создавать буфер воспроизведения, записывать в него элементы и читать из него, мы можем использовать его для хранения траекторий во время обучения наших агентов.

Сбор данных

Сначала давайте посмотрим, как использовать буфер воспроизведения во время сбора данных.

В TF-агентах мы используем Driver (см учебника драйвера для более подробной информации) , чтобы собрать опыт в среде. Чтобы использовать Driver , зададим Observer , которая является функцией для Driver , чтобы выполнить , когда он получает траекторию.

Таким образом, добавление траекторных элементов в буфер воспроизведения, мы добавим наблюдатель , который призывает add_batch(items) , чтобы добавить партию элементов на буфер воспроизведения.

Ниже приведен пример этого с TFUniformReplayBuffer . Сначала мы создаем среду, сеть и агента. Затем мы создаем TFUniformReplayBuffer . Обратите внимание, что характеристики элементов траектории в буфере воспроизведения совпадают со спецификациями сбора данных агента. Затем мы устанавливаем его add_batch метод в качестве наблюдателя для водителя , который будет делать эти данные собирают во время нашего обучения:

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()

Чтение данных для шага поезда

После добавления элементов траектории в буфер воспроизведения мы можем считывать пакеты траекторий из буфера воспроизведения, чтобы использовать их в качестве входных данных для шага поезда.

Вот пример того, как тренироваться по траекториям из буфера воспроизведения в цикле обучения:

# 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.7/site-packages/tensorflow/python/util/dispatch.py:206: 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))