Phát lại bộ đệm

Xem trên TensorFlow.org Chạy trong Google Colab Xem nguồn trên GitHub Tải xuống sổ ghi chép

Giới thiệu

Các thuật toán học củng cố sử dụng bộ đệm phát lại để lưu trữ quỹ đạo của trải nghiệm khi thực thi một chính sách trong một môi trường. Trong quá trình đào tạo, bộ đệm phát lại được truy vấn cho một tập hợp con của quỹ đạo (tập hợp con tuần tự hoặc một mẫu) để "phát lại" trải nghiệm của tác nhân.

Trong chuyên mục này, chúng tôi khám phá hai loại bộ đệm phát lại: được hỗ trợ bằng python và được hỗ trợ bởi tensorflow, chia sẻ một API chung. Trong các phần sau, chúng tôi mô tả API, từng cách triển khai bộ đệm và cách sử dụng chúng trong quá trình đào tạo thu thập dữ liệu.

Cài đặt

Cài đặt tf-agent nếu bạn chưa cài đặt.

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

API bộ đệm phát lại

Lớp Replay Buffer có định nghĩa và các phương thức sau:

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

Lưu ý rằng khi đối tượng phát lại đệm được khởi tạo, nó đòi hỏi các data_spec trong những yếu tố đó nó sẽ lưu trữ. Đây đặc tả tương ứng với TensorSpec của các yếu tố quỹ đạo sẽ được bổ sung vào bộ đệm. Spec này thường được mua lại bằng cách nhìn vào một đại lý agent.collect_data_spec trong đó xác định hình dạng, chủng loại, và các công trình dự kiến của các đại lý khi đào tạo (thêm về điều này sau).

TFUniformReplayBuffer

TFUniformReplayBuffer là bộ đệm phát lại thường được sử dụng nhất trong TF-Đại lý, do đó chúng tôi sẽ sử dụng nó trong hướng dẫn của chúng tôi ở đây. Trong TFUniformReplayBuffer sự ủng hộ lưu trữ đệm được thực hiện bằng các biến tensorflow và do đó là một phần của đồ thị tính toán.

Các cửa hàng đệm lô của các yếu tố và có công suất tối đa max_length yếu tố cho mỗi phân đoạn hàng loạt. Như vậy, tổng công suất đệm là batch_size x max_length yếu tố. Tất cả các phần tử được lưu trữ trong bộ đệm phải có một thông số dữ liệu phù hợp. Khi bộ đệm phát lại được sử dụng để thu thập dữ liệu, thông số kỹ thuật là thông số kỹ thuật thu thập dữ liệu của tác nhân.

Tạo vùng đệm:

Để tạo một TFUniformReplayBuffer chúng tôi vượt qua trong:

  1. thông số kỹ thuật của các phần tử dữ liệu mà bộ đệm sẽ lưu trữ
  2. các batch size tương ứng với kích thước hàng loạt của bộ đệm
  3. các max_length số phần tử mỗi phân khúc hàng loạt

Dưới đây là một ví dụ về việc tạo ra một TFUniformReplayBuffer với thông số kỹ thuật dữ liệu mẫu, batch_size 32 và 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)

Ghi vào bộ đệm:

Để thêm các yếu tố để các bộ đệm phát lại, chúng tôi sử dụng add_batch(items) phương pháp mà items là danh sách / tuple / tổ của tensors đại diện cho hàng loạt các mặt hàng được thêm vào bộ đệm. Mỗi phần tử của items phải có một chiều kích bên ngoài bằng batch_size và kích thước còn lại phải tuân theo spec dữ liệu của sản phẩm (tương tự như các thông số kỹ thuật dữ liệu truyền cho constructor đệm phát lại).

Đây là một ví dụ về việc thêm một loạt các mặt hàng

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)

Đọc từ bộ đệm

Có ba cách để đọc dữ liệu từ TFUniformReplayBuffer :

  1. get_next() - trả về một mẫu từ bộ đệm. Kích thước lô mẫu và số bước thời gian được trả về có thể được chỉ định thông qua các đối số của phương thức này.
  2. as_dataset() - trả về đệm phát lại như một tf.data.Dataset . Sau đó, người ta có thể tạo một trình lặp tập dữ liệu và lặp qua các mẫu của các mục trong bộ đệm.
  3. gather_all() - trả về tất cả các mặt hàng trong bộ đệm như một tensor với hình dạng [batch, time, data_spec]

Dưới đây là các ví dụ về cách đọc từ bộ đệm phát lại bằng cách sử dụng từng phương pháp sau:

# 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 có functionaly giống như TFUniformReplayBuffer nhưng thay vì biến tf, dữ liệu của nó được lưu trữ trong mảng NumPy. Bộ đệm này có thể được sử dụng để thu thập dữ liệu ngoài biểu đồ. Việc có bộ nhớ dự phòng trong numpy có thể giúp một số ứng dụng thao tác dữ liệu dễ dàng hơn (chẳng hạn như lập chỉ mục để cập nhật các mức độ ưu tiên) mà không cần sử dụng các biến Tensorflow. Tuy nhiên, việc triển khai này sẽ không có lợi ích của việc tối ưu hóa đồ thị với Tensorflow.

Dưới đây là một ví dụ về instantiating một PyUniformReplayBuffer từ thông số kỹ thuật quỹ đạo chính sách của đại lý:

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

Sử dụng bộ đệm phát lại trong quá trình đào tạo

Bây giờ chúng ta đã biết cách tạo bộ đệm phát lại, ghi các mục vào nó và đọc từ nó, chúng ta có thể sử dụng nó để lưu trữ quỹ đạo trong quá trình đào tạo các đại lý của mình.

Thu thập dữ liệu

Đầu tiên, hãy xem cách sử dụng bộ đệm phát lại trong quá trình thu thập dữ liệu.

Trong TF-Đại lý chúng tôi sử dụng một Driver (xem hướng dẫn lái xe để biết thêm chi tiết) kinh nghiệm thu thập trong một môi trường. Để sử dụng Driver , chúng tôi chỉ định một Observer đó là một chức năng cho Driver để thực hiện khi nó nhận được một quỹ đạo.

Vì vậy, để thêm các yếu tố quỹ đạo để các bộ đệm phát lại, chúng tôi thêm một người quan sát các cuộc gọi add_batch(items) để thêm một loạt các mục khác trên đệm phát lại.

Dưới đây là một ví dụ về điều này với TFUniformReplayBuffer . Đầu tiên chúng tôi tạo ra một môi trường, một mạng lưới và một đại lý. Sau đó, chúng tôi tạo ra một TFUniformReplayBuffer . Lưu ý rằng thông số kỹ thuật của các phần tử quỹ đạo trong bộ đệm phát lại bằng với thông số kỹ thuật dữ liệu thu thập của tác nhân. Sau đó chúng tôi thiết lập của nó add_batch phương pháp như người quan sát cho người lái xe sẽ làm các dữ liệu thu thập trong quá trình đào tạo của chúng tôi:

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

Đọc dữ liệu cho một bước tàu

Sau khi thêm các phần tử quỹ đạo vào bộ đệm phát lại, chúng ta có thể đọc hàng loạt quỹ đạo từ bộ đệm phát lại để sử dụng làm dữ liệu đầu vào cho một bước tàu.

Dưới đây là một ví dụ về cách huấn luyện theo quỹ đạo từ bộ đệm phát lại trong vòng lặp huấn luyện:

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