Copyright 2021 Les auteurs TF-Agents.
Voir sur TensorFlow.org | Exécuter dans Google Colab | Voir la source sur GitHub | Télécharger le cahier |
introduction
Dans cette collaboration, nous verrons comment définir des réseaux personnalisés pour vos agents. Les réseaux nous aident à définir le modèle qui est formé par les agents. Dans TF-Agents, vous trouverez plusieurs types de réseaux différents qui sont utiles entre les agents :
Réseaux principaux
- QNetwork: Utilisé dans Qlearning pour les environnements avec des actions discrètes, ce réseau mappe une observation des estimations de valeur pour chaque action possible.
- CriticNetworks: On parle aussi de
ValueNetworks
dans la littérature, apprend à estimer une version d'une fonction de valeur cartographie un état dans une estimation du rendement attendu d'une politique. Ces réseaux estiment à quel point l'état actuel de l'agent est bon. - ActorNetworks: Apprendre une cartographie des observations à des actions. Ces réseaux sont généralement utilisés par nos politiques pour générer des actions.
- ActorDistributionNetworks: similaires à
ActorNetworks
mais ces génèrent une distribution qui une politique peut alors échantillon pour générer des actions.
Réseaux d'assistance
- EncodingNetwork: Permet aux utilisateurs de définir facilement une cartographie des couches de pré-traitement à appliquer à l'entrée d'un réseau.
- DynamicUnrollLayer: remet à zéro automatiquement l'état du réseau sur les limites de l' épisode tel qu'il est appliqué sur une séquence temporelle.
- ProjectionNetwork: Les réseaux comme
CategoricalProjectionNetwork
ouNormalProjectionNetwork
prennent des entrées et générer les paramètres nécessaires pour générer catégorielles ou distributions normales.
Tous les exemples dans TF-Agents sont fournis avec des réseaux préconfigurés. Cependant, ces réseaux ne sont pas configurés pour gérer des observations complexes.
Si vous avez un environnement qui expose plus d'une observation/action et que vous avez besoin de personnaliser vos réseaux alors ce tutoriel est fait pour vous !
Installer
Si vous n'avez pas encore installé tf-agents, exécutez :
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
Définition des réseaux
API réseau
Dans TF-agents nous sous de KERAS Networks . Avec lui, nous pouvons :
- Simplifiez les opérations de copie requises lors de la création de réseaux cibles.
- Effectuer la création de variable automatique lors de l' appel
network.variables()
. - Validez les entrées en fonction des input_specs du réseau.
EncodageRéseau
Comme mentionné ci- dessus de la EncodingNetwork
nous permet de définir facilement une cartographie des couches pré-traitement à appliquer à l'entrée d'un réseau pour générer un codage.
L'EncodingNetwork est composé des couches pour la plupart facultatives suivantes :
- Couches de prétraitement
- Combineur de prétraitement
- Conv2D
- Aplatir
- Dense
La particularité des réseaux d'encodage est qu'un prétraitement d'entrée est appliqué. Pré - traitement d' entrée est possible via preprocessing_layers
et preprocessing_combiner
couches. Chacun d'eux peut être spécifié comme une structure imbriquée. Si le preprocessing_layers
nid est moins profonde que input_tensor_spec
, puis les couches auront la subnests. Par exemple, si :
input_tensor_spec = ([TensorSpec(3)] * 2, [TensorSpec(3)] * 5)
preprocessing_layers = (Layer1(), Layer2())
alors le prétraitement appellera :
preprocessed = [preprocessing_layers[0](observations[0]),
preprocessing_layers[1](observations[1])]
Toutefois, si
preprocessing_layers = ([Layer1() for _ in range(2)],
[Layer2() for _ in range(5)])
alors le prétraitement appellera :
preprocessed = [
layer(obs) for layer, obs in zip(flatten(preprocessing_layers),
flatten(observations))
]
Réseaux personnalisés
Pour créer vos propres réseaux , vous ne devez remplacer les __init__
et call
méthodes. Créons un réseau personnalisé à l' aide ce que nous avons appris EncodingNetworks
pour créer une ActorNetwork qui prend des observations qui contiennent une image et un vecteur.
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
Créons un RandomPyEnvironment
pour générer des observations structurées et valider notre mise en œuvre.
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)
Puisque nous avons défini les observations comme un dict, nous devons créer des couches de prétraitement pour les gérer.
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)
Maintenant que nous avons le réseau d'acteurs, nous pouvons traiter les observations de l'environnement.
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)>, ())
Cette même stratégie peut être utilisée pour personnaliser l'un des principaux réseaux utilisés par les agents. Vous pouvez définir n'importe quel prétraitement et le connecter au reste du réseau. Lorsque vous définissez votre propre personnalisation, assurez-vous que les définitions de la couche de sortie du réseau correspondent.