Réseaux

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 ou NormalProjectionNetwork 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.