Esta página foi traduzida pela API Cloud Translation.
Switch to English

Redes

Ver no TensorFlow.org Executar no Google Colab Ver fonte no GitHub Baixar caderno

Introdução

Nesta colab, abordaremos como definir redes personalizadas para seus agentes. As redes nos ajudam a definir o modelo que é treinado pelos agentes. Em TF-Agents, você encontrará vários tipos diferentes de redes que são úteis entre os agentes:

Redes Principais

  • QNetwork : usada no Qlearning para ambientes com ações discretas, esta rede mapeia uma observação para estimativas de valor para cada ação possível.
  • CriticNetworks : também conhecido como ValueNetworks na literatura, aprende a estimar alguma versão de uma função de valor mapeando algum estado em uma estimativa do retorno esperado de uma política. Essas redes estimam o quão bom é o estado em que o agente está atualmente.
  • ActorNetworks : aprenda um mapeamento de observações a ações. Essas redes geralmente são usadas por nossas políticas para gerar ações.
  • ActorDistributionNetworks : semelhantes a ActorNetworks mas geram uma distribuição que uma política pode, então, amostrar para gerar ações.

Helper Networks

  • EncodingNetwork : Permite que os usuários definam facilmente um mapeamento de camadas de pré-processamento para aplicar à entrada de uma rede.
  • DynamicUnrollLayer : redefine automaticamente o estado da rede nos limites do episódio à medida que é aplicado ao longo de uma sequência de tempo.
  • ProjectionNetwork : redes como CategoricalProjectionNetwork ou NormalProjectionNetwork entradas e geram os parâmetros necessários para gerar distribuições categóricas ou normais.

Todos os exemplos em TF-Agents vêm com redes pré-configuradas. No entanto, essas redes não são configuradas para lidar com observações complexas.

Se você tem um ambiente que expõe mais de uma observação / ação e precisa customizar suas redes, este tutorial é para você!

Configuração

Se você ainda não instalou tf-agents, execute:

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

Definindo Redes

API de rede

Em TF-Agents, temos uma subclasse de Keras Networks . Com ele podemos:

  • Simplifique as operações de cópia necessárias ao criar redes de destino.
  • Execute a criação automática de variáveis ​​ao chamar network.variables() .
  • Valide as entradas com base em input_specs da rede.

EncodingNetwork

Conforme mencionado acima, EncodingNetwork nos permite definir facilmente um mapeamento de camadas de pré-processamento para aplicar à entrada de uma rede para gerar alguma codificação.

A EncodingNetwork é composta das seguintes camadas, em sua maioria opcionais:

  • Camadas de pré-processamento
  • Combinador de pré-processamento
  • Conv2D
  • Flatten
  • Denso

O especial sobre a codificação de redes é que o pré-processamento de entrada é aplicado. Pré-processamento de entrada é possível através preprocessing_layers e preprocessing_combiner camadas. Cada um deles pode ser especificado como uma estrutura aninhada. Se o ninho preprocessing_layers for mais raso do que input_tensor_spec , as camadas obterão os sub-ninhos. Por exemplo, se:

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

então o pré-processamento chamará:

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

Entretanto se

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

então o pré-processamento chamará:

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

Redes Personalizadas

Para criar suas próprias redes, você só terá que substituir o __init__ e call métodos de call . Vamos criar uma rede personalizada usando o que aprendemos sobre EncodingNetworks para criar uma ActorNetwork que faz observações que contêm uma imagem e um vetor.

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 criar um RandomPyEnvironment para gerar observações estruturadas e validar nossa implementação.

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)

Como definimos as observações como um ditado, precisamos criar camadas de pré-processamento para lidar com elas.

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)

Agora que temos a rede de atores, podemos processar observações do ambiente.

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

Essa mesma estratégia pode ser utilizada para customizar qualquer uma das principais redes utilizadas pelos agentes. Você pode definir qualquer pré-processamento e conectá-lo ao resto da rede. Ao definir seu próprio personalizado, certifique-se de que as definições da camada de saída da rede correspondam.