Copyright 2021 Autorzy TF-Agents.
Zobacz na TensorFlow.org | Uruchom w Google Colab | Wyświetl źródło na GitHub | Pobierz notatnik |
Wstęp
W tej kolaboracji omówimy, jak zdefiniować niestandardowe sieci dla agentów. Sieci pomagają nam zdefiniować model, który jest szkolony przez agentów. W TF-Agents znajdziesz kilka różnych typów sieci, które są przydatne dla agentów:
Główne sieci
- QNetwork: Używany w Qlearning dla środowisk o dyskretnych działań, sieć ta odwzorowuje obserwację do szacunków wartości dla każdego możliwego działania.
- CriticNetworks: Także dalej
ValueNetworks
w literaturze, uczy się oszacować jakąś wersję funkcji Wartość mapujesz stanu do oszacowania dla oczekiwanego zwrotu polityki. Sieci te szacują, w jakim stanie znajduje się obecnie agent. - ActorNetworks: Dowiedz się mapowanie z uwagi na działania. Te sieci są zwykle używane przez nasze zasady do generowania działań.
- ActorDistributionNetworks: podobne do
ActorNetworks
ale te generują rozkład których polityka może następnie próbki do generowania działań.
Sieci pomocnicze
- EncodingNetwork: Pozwala użytkownikom łatwo zdefiniować odwzorowanie wstępne przetwarzanie warstw zastosować, aby wprowadzić sieci.
- DynamicUnrollLayer: Automatycznie przywraca stan w sieci na granicach odcinka, ponieważ nakłada się sekwencji czasowej.
- ProjectionNetwork: Sieci takie jak
CategoricalProjectionNetwork
lubNormalProjectionNetwork
wziąć wejść i generuje wymagane parametry do generowania kategoryczne lub dystrybucje normalne.
Wszystkie przykłady w TF-Agents są dostarczane ze wstępnie skonfigurowanymi sieciami. Jednak sieci te nie są przystosowane do obsługi złożonych obserwacji.
Jeśli masz środowisko, które ujawnia więcej niż jedną obserwację/działanie i potrzebujesz dostosować swoje sieci, ten samouczek jest dla Ciebie!
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 numpy as np
from tf_agents.environments import random_py_environment
from tf_agents.environments import tf_py_environment
from tf_agents.networks import encoding_network
from tf_agents.networks import network
from tf_agents.networks import utils
from tf_agents.specs import array_spec
from tf_agents.utils import common as common_utils
from tf_agents.utils import nest_utils
Definiowanie sieci
Sieciowy interfejs API
W TF-pełnomocników my podklasy z Keras Networks . Dzięki niemu możemy:
- Uprość operacje kopiowania wymagane podczas tworzenia sieci docelowych.
- Wykonaj automatyczne tworzenie zmiennej Dzwoniąc
network.variables()
. - Sprawdź poprawność danych wejściowych na podstawie danych wejściowych sieci.
KodowanieSieć
Jak wspomniano powyżej EncodingNetwork
pozwala nam łatwo zdefiniować odwzorowanie warstw wstępnego przetwarzania zastosować, aby wprowadzić sieci do generowania jakieś kodowanie.
EncodingNetwork składa się z następujących, przeważnie opcjonalnych warstw:
- Wstępne przetwarzanie warstw
- Łącznik przetwarzania wstępnego
- Conv2D
- Spłaszczyć
- Gęsty
Szczególną cechą sieci kodujących jest to, że stosowane jest wstępne przetwarzanie danych wejściowych. Przerób wejście jest możliwe poprzez preprocessing_layers
i preprocessing_combiner
warstwach. Każdy z nich można określić jako strukturę zagnieżdżoną. Jeśli preprocessing_layers
gniazdo jest płytsze niż input_tensor_spec
, następnie warstwy dostanie subnests. Na przykład, jeśli:
input_tensor_spec = ([TensorSpec(3)] * 2, [TensorSpec(3)] * 5)
preprocessing_layers = (Layer1(), Layer2())
wtedy wstępne przetwarzanie wywoła:
preprocessed = [preprocessing_layers[0](observations[0]),
preprocessing_layers[1](observations[1])]
Jeśli jednak
preprocessing_layers = ([Layer1() for _ in range(2)],
[Layer2() for _ in range(5)])
wtedy wstępne przetwarzanie wywoła:
preprocessed = [
layer(obs) for layer, obs in zip(flatten(preprocessing_layers),
flatten(observations))
]
Sieci niestandardowe
Aby tworzyć własne sieci będzie trzeba tylko zastąpić __init__
i call
metod. Stwórzmy sieć przy użyciu niestandardowego, czego dowiedzieliśmy się o EncodingNetworks
do wydzielać ActorNetwork które ma uwag, które zawierają obraz i wektor.
class ActorNetwork(network.Network):
def __init__(self,
observation_spec,
action_spec,
preprocessing_layers=None,
preprocessing_combiner=None,
conv_layer_params=None,
fc_layer_params=(75, 40),
dropout_layer_params=None,
activation_fn=tf.keras.activations.relu,
enable_last_layer_zero_initializer=False,
name='ActorNetwork'):
super(ActorNetwork, self).__init__(
input_tensor_spec=observation_spec, state_spec=(), name=name)
# For simplicity we will only support a single action float output.
self._action_spec = action_spec
flat_action_spec = tf.nest.flatten(action_spec)
if len(flat_action_spec) > 1:
raise ValueError('Only a single action is supported by this network')
self._single_action_spec = flat_action_spec[0]
if self._single_action_spec.dtype not in [tf.float32, tf.float64]:
raise ValueError('Only float actions are supported by this network.')
kernel_initializer = tf.keras.initializers.VarianceScaling(
scale=1. / 3., mode='fan_in', distribution='uniform')
self._encoder = encoding_network.EncodingNetwork(
observation_spec,
preprocessing_layers=preprocessing_layers,
preprocessing_combiner=preprocessing_combiner,
conv_layer_params=conv_layer_params,
fc_layer_params=fc_layer_params,
dropout_layer_params=dropout_layer_params,
activation_fn=activation_fn,
kernel_initializer=kernel_initializer,
batch_squash=False)
initializer = tf.keras.initializers.RandomUniform(
minval=-0.003, maxval=0.003)
self._action_projection_layer = tf.keras.layers.Dense(
flat_action_spec[0].shape.num_elements(),
activation=tf.keras.activations.tanh,
kernel_initializer=initializer,
name='action')
def call(self, observations, step_type=(), network_state=()):
outer_rank = nest_utils.get_outer_rank(observations, self.input_tensor_spec)
# We use batch_squash here in case the observations have a time sequence
# compoment.
batch_squash = utils.BatchSquash(outer_rank)
observations = tf.nest.map_structure(batch_squash.flatten, observations)
state, network_state = self._encoder(
observations, step_type=step_type, network_state=network_state)
actions = self._action_projection_layer(state)
actions = common_utils.scale_to_spec(actions, self._single_action_spec)
actions = batch_squash.unflatten(actions)
return tf.nest.pack_sequence_as(self._action_spec, [actions]), network_state
Stwórzmy RandomPyEnvironment
generowania obserwacje strukturyzowanych i zweryfikować nasze wdrożenia.
action_spec = array_spec.BoundedArraySpec((3,), np.float32, minimum=0, maximum=10)
observation_spec = {
'image': array_spec.BoundedArraySpec((16, 16, 3), np.float32, minimum=0,
maximum=255),
'vector': array_spec.BoundedArraySpec((5,), np.float32, minimum=-100,
maximum=100)}
random_env = random_py_environment.RandomPyEnvironment(observation_spec, action_spec=action_spec)
# Convert the environment to a TFEnv to generate tensors.
tf_env = tf_py_environment.TFPyEnvironment(random_env)
Ponieważ zdefiniowaliśmy obserwacje jako nakaz, musimy utworzyć warstwy przetwarzania wstępnego, aby je obsłużyć.
preprocessing_layers = {
'image': tf.keras.models.Sequential([tf.keras.layers.Conv2D(8, 4),
tf.keras.layers.Flatten()]),
'vector': tf.keras.layers.Dense(5)
}
preprocessing_combiner = tf.keras.layers.Concatenate(axis=-1)
actor = ActorNetwork(tf_env.observation_spec(),
tf_env.action_spec(),
preprocessing_layers=preprocessing_layers,
preprocessing_combiner=preprocessing_combiner)
Teraz, gdy mamy sieć aktorów, możemy przetwarzać obserwacje z otoczenia.
time_step = tf_env.reset()
actor(time_step.observation, time_step.step_type)
(<tf.Tensor: shape=(1, 3), dtype=float32, numpy=array([[4.5753636, 4.946792 , 4.853481 ]], dtype=float32)>, ())
Tej samej strategii można użyć do dostosowania dowolnej z głównych sieci używanych przez agentów. Możesz zdefiniować dowolne przetwarzanie wstępne i połączyć je z resztą sieci. Podczas definiowania własnego niestandardowego upewnij się, że definicje warstwy wyjściowej sieci są zgodne.