Trang này được dịch bởi Cloud Translation API.
Switch to English

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ổ tay

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 trải nghiệm khi thực thi một chính sách trong môi trường. Trong quá trình đào tạo, các 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ởi 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.

Thiết lập

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

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

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

Lớp Replay Buffer có định nghĩa và 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 đệm phát lại được khởi tạo, nó yêu cầu data_spec của các phần tử mà nó sẽ lưu trữ. Thông số kỹ thuật này tương ứng với TensorSpec của các phần tử quỹ đạo sẽ được thêm vào bộ đệm. Thông số kỹ thuật này thường có được bằng cách xem agent.collect_data_spec của agent xác định hình dạng, kiểu và cấu trúc mà agent mong đợi khi đào tạo (sẽ tìm hiểu thêm về điều đó sau).

TFUniformReplayBuffer

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

Bộ đệm lưu trữ các lô phần tử và có dung lượng tối đa các phần tử max_length trên mỗi phân đoạn lô. Do đó, tổng dung lượng bộ đệm là phần tử batch_size x max_length . 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ố dữ liệu thu thập của tác nhân.

Tạo vùng đệm:

Để tạo TFUniformReplayBuffer chúng tôi nhập:

  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. batch size tương ứng với kích thước lô của bộ đệm
  3. số lượng phần tử max_length trên mỗi phân đoạn hàng loạt

Đây là một ví dụ về việc tạo TFUniformReplayBuffer với thông số 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 phần tử vào bộ đệm phát lại, chúng tôi sử dụng phương thức add_batch(items) trong đó items là một danh sách / tuple / tổ các tenxơ đại diện cho lô các mục sẽ được thêm vào bộ đệm. Mỗi phần tử của items phải có kích thước bên ngoài bằng batch_size và các kích thước còn lại phải tuân theo thông số dữ liệu của mục (giống như thông số dữ liệu được chuyển đến phương thức tạo bộ đệ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ề bộ đệm phát lại dưới dạngtf.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ục trong bộ đệm dưới dạng 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 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 <ipython-input-1-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-1-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 có cùng chức năng với TFUniformReplayBuffer nhưng thay vì các biến tf, dữ liệu của nó được lưu trữ trong các mảng nhỏ. Bộ đệm này có thể được sử dụng để thu thập dữ liệu ngoài đồ thị. 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à ví dụ về việc khởi tạo PyUniformReplayBuffer từ thông số quỹ đạo chính sách của tác nhân:

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-Agents, chúng tôi sử dụng Driver (xem hướng dẫn Trình điều khiển để biết thêm chi tiết) để thu thập kinh nghiệm trong môi trường. Để sử dụng Driver , chúng tôi chỉ định Trình Observer là một chức năng để Driver thực thi khi nó nhận được quỹ đạo.

Do đó, để thêm các phần tử quỹ đạo vào bộ đệm phát lại, chúng tôi thêm một trình quan sát gọi add_batch(items) để thêm một loạt các mục trên bộ đệ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 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ố dữ liệu thu thập của tác nhân. Sau đó, chúng tôi đặt phương thức add_batch của nó làm trình quan sát cho trình điều khiển sẽ thu thập dữ liệu 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()
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))

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

Sau khi thêm 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.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))