Se usó la API de Cloud Translation para traducir esta página.
Switch to English

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 : utilizada en Qlearning para entornos con acciones discretas, esta red asigna una observación a estimaciones de valor para cada acción posible.
  • CriticNetworks : también conocido como ValueNetworks en la literatura, aprende a estimar alguna versión de una función de valor mapeando algún estado en una estimación del rendimiento esperado de una póliza. Estas redes estiman qué tan bueno es el estado actual del agente.
  • ActorNetworks : aprenda un mapeo de observaciones a acciones. Estas redes suelen ser utilizadas por nuestras políticas para generar acciones.
  • ActorDistributionNetworks : similar a ActorNetworks pero estos generan una distribución que luego una política puede muestrear para generar acciones.

Redes de ayuda

  • EncodingNetwork : permite a los usuarios definir fácilmente una asignación de capas de preprocesamiento para aplicar a la entrada de una red.
  • DynamicUnrollLayer : restablece automáticamente el estado de la red en los límites del episodio a medida que se aplica en una secuencia de tiempo.
  • ProjectionNetwork : redes como CategoricalProjectionNetwork o NormalProjectionNetwork toman entradas y generan los parámetros necesarios para generar distribuciones categóricas o 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!

Preparar

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

pip install -q 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

tf.compat.v1.enable_v2_behavior()

Definición de redes

API de red

En TF-Agents tenemos una subclase de Keras Networks . Con él podemos:

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

Codificación de red

Como se mencionó anteriormente, EncodingNetwork nos permite definir fácilmente un mapeo de capas de preprocesamiento para aplicar a la entrada de una red para 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. El preprocesamiento de entrada es posible mediante las capas preprocessing_layers y preprocessing_combiner . Cada uno de estos se puede especificar como una estructura anidada. Si el nido preprocessing_layers es menos profundo que input_tensor_spec , entonces las capas obtendrán 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](obsrevations[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, solo tendrá que anular los métodos __init__ y call . Creemos una red personalizada usando lo que aprendimos sobre EncodingNetworks para crear una ActorNetwork que toma 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

RandomPyEnvironment un RandomPyEnvironment para generar observaciones estructuradas y validar nuestra implementació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([[7.026863 , 4.5458393, 4.7681847]], 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. Cuando defina su propia personalización, asegúrese de que las definiciones de la capa de salida de la red coincidan.