Zasady

Zobacz na TensorFlow.org Uruchom w Google Colab Wyświetl źródło na GitHub Pobierz notatnik

Wstęp

W terminologii uczenia się przez wzmacnianie, zasady odwzorowują obserwację ze środowiska na działanie lub podział na działania. W TF-pełnomocników, obserwacje z otoczenia są zawarte w nazwie krotki TimeStep('step_type', 'discount', 'reward', 'observation') , a polityka map timesteps do działań lub dystrybucji ponad działań. Większość polis używać timestep.observation niektóre zasady korzystania timestep.step_type (np aby przywrócić stan na początku epizodu w polityce stanowych), ale timestep.discount i timestep.reward są zazwyczaj ignorowane.

Zasady są powiązane z innymi komponentami TF-Agents w następujący sposób. Większość zasad ma sieć neuronową do obliczania akcji i/lub dystrybucji w ramach akcji z TimeSteps. Agenci mogą zawierać jedną lub więcej zasad do różnych celów, np. główną zasadę, która jest szkolona do wdrażania, oraz zaszumioną zasadę gromadzenia danych. Polityki mogą być zapisywane/przywracane i mogą być używane niezależnie od agenta do zbierania danych, oceny itp.

Niektóre polityki są łatwiejsze do napisania w Tensorflow (np. te z siecią neuronową), podczas gdy inne są łatwiejsze do napisania w Pythonie (np. po skrypcie działań). Tak więc w agentach TF dopuszczamy zarówno polityki Pythona, jak i Tensorflow. Co więcej, polityki napisane w TensorFlow mogą wymagać użycia w środowisku Python lub odwrotnie, np. polityka TensorFlow jest używana do szkolenia, ale później jest wdrażana w środowisku produkcyjnym Python. Aby to ułatwić, udostępniamy wrappery do konwersji między politykami Pythona i TensorFlow.

Inną ciekawą klasą polityk są wrappery polityk, które modyfikują daną politykę w określony sposób, np. dodają określony rodzaj szumu, tworzą zachłanną lub epsilon-greedy wersję polityki stochastycznej, losowo mieszają wiele polityk itp.

Ustawiać

Jeśli nie zainstalowałeś jeszcze agentów tf, uruchom:

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

import abc
import tensorflow as tf
import tensorflow_probability as tfp
import numpy as np

from tf_agents.specs import array_spec
from tf_agents.specs import tensor_spec
from tf_agents.networks import network

from tf_agents.policies import py_policy
from tf_agents.policies import random_py_policy
from tf_agents.policies import scripted_py_policy

from tf_agents.policies import tf_policy
from tf_agents.policies import random_tf_policy
from tf_agents.policies import actor_policy
from tf_agents.policies import q_policy
from tf_agents.policies import greedy_policy

from tf_agents.trajectories import time_step as ts

Zasady Pythona

Interfejs dla polityki Pythona jest zdefiniowany w policies/py_policy.PyPolicy . Główne metody to:

class Base(object):

  @abc.abstractmethod
  def __init__(self, time_step_spec, action_spec, policy_state_spec=()):
    self._time_step_spec = time_step_spec
    self._action_spec = action_spec
    self._policy_state_spec = policy_state_spec

  @abc.abstractmethod
  def reset(self, policy_state=()):
    # return initial_policy_state.
    pass

  @abc.abstractmethod
  def action(self, time_step, policy_state=()):
    # return a PolicyStep(action, state, info) named tuple.
    pass

  @abc.abstractmethod
  def distribution(self, time_step, policy_state=()):
    # Not implemented in python, only for TF policies.
    pass

  @abc.abstractmethod
  def update(self, policy):
    # update self to be similar to the input `policy`.
    pass

  @property
  def time_step_spec(self):
    return self._time_step_spec

  @property
  def action_spec(self):
    return self._action_spec

  @property
  def policy_state_spec(self):
    return self._policy_state_spec

Najważniejszą metodą jest action(time_step) , który mapuje time_step zawierający obserwacje z otoczenia do PolicyStep nazwana krotki zawierającej następujące atrybuty:

  • action : Działanie, które ma być stosowane do środowiska.
  • state : stan polityki (np państwowej RNN) być podawany do kolejnego wezwania do działania.
  • info : Opcjonalne informacje poboczne, takie jak prawdopodobieństw dziennika działanie.

time_step_spec i action_spec są specyfikacje dla kroku czasowego wejściowego i wyjściowego działania. Zasady mają również reset funkcji, która jest zazwyczaj używany do resetowania stanu w polityce stanowych. update(new_policy) Funkcja aktualizuje self w kierunku new_policy .

Przyjrzyjmy się teraz kilku przykładom zasad Pythona.

Przykład 1: Losowa polityka Pythona

Prostym przykładem PyPolicy jest RandomPyPolicy który generuje losowe działania dyskretnej / ciągłego danego action_spec. Wejście time_step jest ignorowany.

action_spec = array_spec.BoundedArraySpec((2,), np.int32, -10, 10)
my_random_py_policy = random_py_policy.RandomPyPolicy(time_step_spec=None,
    action_spec=action_spec)
time_step = None
action_step = my_random_py_policy.action(time_step)
print(action_step)
action_step = my_random_py_policy.action(time_step)
print(action_step)
PolicyStep(action=array([10, -4], dtype=int32), state=(), info=())
PolicyStep(action=array([7, 6], dtype=int32), state=(), info=())

Przykład 2: Skryptowana polityka Pythona

A oskryptowane odgrywa polityka kopii skryptu działań przedstawionych w postaci listy (num_repeats, action) krotek. Za każdym razem, gdy action wywoływana jest funkcja, zwraca następną akcję z listy aż do określonej liczby powtórzeń jest zrobione, a następnie przechodzi do następnej akcji na liście. reset sposób można nazwać zacząć realizować od początku listy.

action_spec = array_spec.BoundedArraySpec((2,), np.int32, -10, 10)
action_script = [(1, np.array([5, 2], dtype=np.int32)), 
                 (0, np.array([0, 0], dtype=np.int32)), # Setting `num_repeats` to 0 will skip this action.
                 (2, np.array([1, 2], dtype=np.int32)), 
                 (1, np.array([3, 4], dtype=np.int32))]

my_scripted_py_policy = scripted_py_policy.ScriptedPyPolicy(
    time_step_spec=None, action_spec=action_spec, action_script=action_script)

policy_state = my_scripted_py_policy.get_initial_state()
time_step = None
print('Executing scripted policy...')
action_step = my_scripted_py_policy.action(time_step, policy_state)
print(action_step)
action_step= my_scripted_py_policy.action(time_step, action_step.state)
print(action_step)
action_step = my_scripted_py_policy.action(time_step, action_step.state)
print(action_step)

print('Resetting my_scripted_py_policy...')
policy_state = my_scripted_py_policy.get_initial_state()
action_step = my_scripted_py_policy.action(time_step, policy_state)
print(action_step)
Executing scripted policy...
PolicyStep(action=array([5, 2], dtype=int32), state=[0, 1], info=())
PolicyStep(action=array([1, 2], dtype=int32), state=[2, 1], info=())
PolicyStep(action=array([1, 2], dtype=int32), state=[2, 2], info=())
Resetting my_scripted_py_policy...
PolicyStep(action=array([5, 2], dtype=int32), state=[0, 1], info=())

Zasady TensorFlow

Zasady TensorFlow są zgodne z tym samym interfejsem, co zasady Pythona. Spójrzmy na kilka przykładów.

Przykład 1: Losowa polityka TF

RandomTFPolicy mogą być wykorzystywane do generowania przypadkowych działania zgodnie z danym dyskretnym / ciągłego action_spec . Wejście time_step jest ignorowany.

action_spec = tensor_spec.BoundedTensorSpec(
    (2,), tf.float32, minimum=-1, maximum=3)
input_tensor_spec = tensor_spec.TensorSpec((2,), tf.float32)
time_step_spec = ts.time_step_spec(input_tensor_spec)

my_random_tf_policy = random_tf_policy.RandomTFPolicy(
    action_spec=action_spec, time_step_spec=time_step_spec)
observation = tf.ones(time_step_spec.observation.shape)
time_step = ts.restart(observation)
action_step = my_random_tf_policy.action(time_step)

print('Action:')
print(action_step.action)
Action:
tf.Tensor([-0.9448042  1.9039011], shape=(2,), dtype=float32)

Przykład 2: Polityka aktora

Polityka aktor mogą być tworzone przy użyciu sieci, która mapuje time_steps działań lub sieć, która mapuje time_steps podziału ponad działań.

Korzystanie z sieci akcji

Zdefiniujmy sieć w następujący sposób:

class ActionNet(network.Network):

  def __init__(self, input_tensor_spec, output_tensor_spec):
    super(ActionNet, self).__init__(
        input_tensor_spec=input_tensor_spec,
        state_spec=(),
        name='ActionNet')
    self._output_tensor_spec = output_tensor_spec
    self._sub_layers = [
        tf.keras.layers.Dense(
            action_spec.shape.num_elements(), activation=tf.nn.tanh),
    ]

  def call(self, observations, step_type, network_state):
    del step_type

    output = tf.cast(observations, dtype=tf.float32)
    for layer in self._sub_layers:
      output = layer(output)
    actions = tf.reshape(output, [-1] + self._output_tensor_spec.shape.as_list())

    # Scale and shift actions to the correct range if necessary.
    return actions, network_state

W TensorFlow większość warstw sieciowych jest zaprojektowana do operacji wsadowych, więc oczekujemy, że wejściowe time_steps będą grupowane, a dane wyjściowe sieci również będą grupowane. Również sieć jest odpowiedzialna za tworzenie akcji w odpowiednim zakresie podanego action_spec. Jest to zwykle wykonywane przy użyciu na przykład tanh aktywacji dla ostatniej warstwy na działania produkcji w [1, 1], a następnie skalowanie i przerzucenie do prawidłowego zakresu, action_spec pomiarowego (patrz np tf_agents/agents/ddpg/networks.actor_network() ).

Teraz możemy stworzyć politykę aktora za pomocą powyższej sieci.

input_tensor_spec = tensor_spec.TensorSpec((4,), tf.float32)
time_step_spec = ts.time_step_spec(input_tensor_spec)
action_spec = tensor_spec.BoundedTensorSpec((3,),
                                            tf.float32,
                                            minimum=-1,
                                            maximum=1)

action_net = ActionNet(input_tensor_spec, action_spec)

my_actor_policy = actor_policy.ActorPolicy(
    time_step_spec=time_step_spec,
    action_spec=action_spec,
    actor_network=action_net)

Możemy zastosować go do dowolnej partii time_steps następujących po time_step_spec:

batch_size = 2
observations = tf.ones([2] + time_step_spec.observation.shape.as_list())

time_step = ts.restart(observations, batch_size)

action_step = my_actor_policy.action(time_step)
print('Action:')
print(action_step.action)

distribution_step = my_actor_policy.distribution(time_step)
print('Action distribution:')
print(distribution_step.action)
Action:
tf.Tensor(
[[0.9318627 0.7770741 0.8645338]
 [0.9318627 0.7770741 0.8645338]], shape=(2, 3), dtype=float32)
Action distribution:
tfp.distributions.Deterministic("Deterministic", batch_shape=[2, 3], event_shape=[], dtype=float32)

W powyższym przykładzie stworzyliśmy politykę przy użyciu sieci akcji, która generuje tensor akcji. W tym przypadku, policy.distribution(time_step) jest deterministyczny (delta) rozkład wokół wyjścia policy.action(time_step) . Jednym ze sposobów stworzenia strategii stochastycznej jest opakowanie strategii aktora w opakowanie polityki, które dodaje szum do działań. Innym sposobem jest utworzenie zasad aktora przy użyciu sieci dystrybucji akcji zamiast sieci akcji, jak pokazano poniżej.

Korzystanie z sieci dystrybucji akcji

class ActionDistributionNet(ActionNet):

  def call(self, observations, step_type, network_state):
    action_means, network_state = super(ActionDistributionNet, self).call(
        observations, step_type, network_state)

    action_std = tf.ones_like(action_means)
    return tfp.distributions.MultivariateNormalDiag(action_means, action_std), network_state


action_distribution_net = ActionDistributionNet(input_tensor_spec, action_spec)

my_actor_policy = actor_policy.ActorPolicy(
    time_step_spec=time_step_spec,
    action_spec=action_spec,
    actor_network=action_distribution_net)

action_step = my_actor_policy.action(time_step)
print('Action:')
print(action_step.action)
distribution_step = my_actor_policy.distribution(time_step)
print('Action distribution:')
print(distribution_step.action)
Action:
tf.Tensor(
[[ 0.96731853  1.          1.        ]
 [ 0.94488937 -0.29294527  1.        ]], shape=(2, 3), dtype=float32)
Action distribution:
tfp.distributions.MultivariateNormalDiag("ActionNet_MultivariateNormalDiag", batch_shape=[2], event_shape=[3], dtype=float32)

Zauważ, że w powyższym przykładzie akcje są przycinane do zakresu podanej specyfikacji akcji [-1, 1]. Dzieje się tak, ponieważ argument konstruktora ActorPolicy clip=True domyślnie. Ustawienie tego na false zwróci nieobcięte akcje wytwarzane przez sieć.

Stochastyczne zasady może być przekształcany do deterministycznych zasady przy użyciu, na przykład, owijki GreedyPolicy które wybiera stochastic_policy.distribution().mode() , jak i jego działania, deterministyczną rozkład / delta wokół tego chciwego działania jako jego distribution() .

Przykład 3: Polityka Q

Zasady AQ są używane w agentach takich jak DQN i opierają się na sieci Q, która przewiduje wartość Q dla każdego działania dyskretnego. Dla danego kroku czasowego rozkład akcji w zasadach Q jest rozkładem kategorycznym utworzonym przy użyciu wartości q jako logit.

input_tensor_spec = tensor_spec.TensorSpec((4,), tf.float32)
time_step_spec = ts.time_step_spec(input_tensor_spec)
action_spec = tensor_spec.BoundedTensorSpec((),
                                            tf.int32,
                                            minimum=0,
                                            maximum=2)
num_actions = action_spec.maximum - action_spec.minimum + 1


class QNetwork(network.Network):

  def __init__(self, input_tensor_spec, action_spec, num_actions=num_actions, name=None):
    super(QNetwork, self).__init__(
        input_tensor_spec=input_tensor_spec,
        state_spec=(),
        name=name)
    self._sub_layers = [
        tf.keras.layers.Dense(num_actions),
    ]

  def call(self, inputs, step_type=None, network_state=()):
    del step_type
    inputs = tf.cast(inputs, tf.float32)
    for layer in self._sub_layers:
      inputs = layer(inputs)
    return inputs, network_state


batch_size = 2
observation = tf.ones([batch_size] + time_step_spec.observation.shape.as_list())
time_steps = ts.restart(observation, batch_size=batch_size)

my_q_network = QNetwork(
    input_tensor_spec=input_tensor_spec,
    action_spec=action_spec)
my_q_policy = q_policy.QPolicy(
    time_step_spec, action_spec, q_network=my_q_network)
action_step = my_q_policy.action(time_steps)
distribution_step = my_q_policy.distribution(time_steps)

print('Action:')
print(action_step.action)

print('Action distribution:')
print(distribution_step.action)
Action:
tf.Tensor([2 2], shape=(2,), dtype=int32)
Action distribution:
tfp.distributions.Categorical("Categorical", batch_shape=[2], event_shape=[], dtype=int32)

Opakowania polis

Opakowania polityk można użyć do pakowania i modyfikowania danej polityki, np. dodawania szumu. Opakowania zasad są podklasą zasad (Python/TensorFlow) i dlatego mogą być używane tak samo jak inne zasady.

Przykład: Polityka chciwości

Chciwy Owijka może być stosowany w stosunku do dowolnych zasady TensorFlow implementującej distribution() . GreedyPolicy.action() powróci wrapped_policy.distribution().mode() i GreedyPolicy.distribution() jest deterministyczny rozkład / delta około GreedyPolicy.action() :

my_greedy_policy = greedy_policy.GreedyPolicy(my_q_policy)

action_step = my_greedy_policy.action(time_steps)
print('Action:')
print(action_step.action)

distribution_step = my_greedy_policy.distribution(time_steps)
print('Action distribution:')
print(distribution_step.action)
Action:
tf.Tensor([1 1], shape=(2,), dtype=int32)
Action distribution:
tfp.distributions.DeterministicWithLogProb("Deterministic", batch_shape=[2], event_shape=[], dtype=int32)