Redes

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar cuaderno

Introducción

En esta colab, cubriremos cómo definir redes personalizadas para sus agentes. Las redes nos ayudan a definir el modelo que entrenan los agentes. En TF-Agents encontrará varios tipos diferentes de redes que son útiles para todos los agentes:

Redes principales

  • QNetwork: Se utiliza en Qlearning para entornos con acciones discretas, esta red se asigna una observación a las estimaciones del valor de cada acción posible.
  • CriticNetworks: También se conoce como ValueNetworks en la literatura, aprende a estimar alguna versión de una función de valor mapeo de algún estado en una estimación para el rendimiento esperado de una política. Estas redes estiman qué tan bueno es el estado en el que se encuentra actualmente el agente.
  • ActorNetworks: Aprender un mapeo de las observaciones a las acciones. Estas redes suelen ser utilizadas por nuestras políticas para generar acciones.
  • ActorDistributionNetworks: Similar a ActorNetworks pero estos generan una distribución que una política puede a continuación muestra para generar acciones.

Redes de ayuda

  • EncodingNetwork: Permite a los usuarios definir fácilmente un mapeo de capas de tratamiento previo para aplicar a la entrada de una red.
  • DynamicUnrollLayer: restablece automáticamente el estado de la red en los límites episodio, ya que se aplica a través de una secuencia de tiempo.
  • ProjectionNetwork: Las redes como CategoricalProjectionNetwork o NormalProjectionNetwork toman entradas y generan los parámetros necesarios para generar categórica, o distribuciones normales.

Todos los ejemplos de TF-Agents vienen con redes preconfiguradas. Sin embargo, estas redes no están configuradas para manejar observaciones complejas.

Si tiene un entorno que expone más de una observación / acción y necesita personalizar sus redes, ¡este tutorial es para usted!

Configuración

Si aún no ha instalado tf-agents, ejecute:

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

Definición de redes

API de red

En la carretera TF-Agentes que subclase de Keras Redes . Con él podemos:

  • Simplifique las operaciones de copia necesarias al crear redes de destino.
  • Realizar la creación variable automática al llamar network.variables() .
  • Valide las entradas según las especificaciones de entrada de la red.

Codificación de red

Como se mencionó anteriormente la EncodingNetwork nos permite definir fácilmente un mapeo de capas pre-procesamiento para aplicar a la entrada de una red de generar algo de codificación.

EncodingNetwork se compone de las siguientes capas, en su mayoría opcionales:

  • Capas de preprocesamiento
  • Combinador de preprocesamiento
  • Conv2D
  • Aplanar
  • Denso

Lo especial de la codificación de redes es que se aplica el preprocesamiento de entrada. Preprocesamiento de entrada es posible a través de preprocessing_layers y preprocessing_combiner capas. Cada uno de estos se puede especificar como una estructura anidada. Si el preprocessing_layers nido es menos profundo que input_tensor_spec , a continuación, las capas se obtienen los subnests. Por ejemplo, si:

input_tensor_spec = ([TensorSpec(3)] * 2, [TensorSpec(3)] * 5)
preprocessing_layers = (Layer1(), Layer2())

entonces el preprocesamiento llamará:

preprocessed = [preprocessing_layers[0](observations[0]),
                preprocessing_layers[1](observations[1])]

Sin embargo, si

preprocessing_layers = ([Layer1() for _ in range(2)],
                        [Layer2() for _ in range(5)])

entonces el preprocesamiento llamará:

preprocessed = [
  layer(obs) for layer, obs in zip(flatten(preprocessing_layers),
                                    flatten(observations))
]

Redes personalizadas

Para crear sus propias redes a las que sólo tendrá que reemplazar los __init__ y call métodos. Vamos a crear una red personalizada utilizando lo que aprendimos sobre EncodingNetworks para crear un ActorNetwork que tiene observaciones que contienen una imagen y un vector.

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

Vamos a crear un RandomPyEnvironment para generar observaciones estructuradas y validar nuestra aplicación.

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)

Dado que hemos definido las observaciones como un dictado, necesitamos crear capas de preprocesamiento para manejarlas.

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)

Ahora que tenemos la red de actores, podemos procesar las observaciones del entorno.

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

Esta misma estrategia se puede utilizar para personalizar cualquiera de las principales redes utilizadas por los agentes. Puede definir cualquier preprocesamiento y conectarlo al resto de la red. Al definir su propia personalización, asegúrese de que las definiciones de la capa de salida de la red coincidan.