Reti

Visualizza su TensorFlow.org Esegui in Google Colab Visualizza la fonte su GitHub Scarica taccuino

introduzione

In questa collaborazione tratteremo come definire reti personalizzate per i tuoi agenti. Le reti ci aiutano a definire il modello che viene addestrato dagli agenti. In TF-Agents troverai diversi tipi di reti utili tra gli agenti:

Reti principali

  • QNetwork: Utilizzato in Qlearning per ambienti con azioni discrete, questa rete associa un'osservazione per le stime di valore per ogni possibile azione.
  • CriticNetworks: Indicato anche come ValueNetworks nella letteratura, impara a stimare una qualche versione di una funzione di valore mappare qualche stato in una stima per il rendimento atteso di una politica. Queste reti stimano lo stato in cui si trova attualmente l'agente.
  • ActorNetworks: Imparare una mappatura dalle osservazioni alle azioni. Queste reti vengono solitamente utilizzate dalle nostre norme per generare azioni.
  • ActorDistributionNetworks: simili ActorNetworks ma questi generano una distribuzione che una politica può allora campione per generare azioni.

Reti di aiuto

  • EncodingNetwork: Consente agli utenti di definire facilmente una mappatura dei livelli pre-elaborazione per applicare all'ingresso di una rete.
  • DynamicUnrollLayer: reimposta automaticamente lo stato della rete sui confini episodio come viene applicato su una sequenza temporale.
  • ProjectionNetwork: Le reti come CategoricalProjectionNetwork o NormalProjectionNetwork prendono ingressi e generano i parametri necessari per generare categoriali, o distribuzioni normali.

Tutti gli esempi in TF-Agents sono forniti con reti preconfigurate. Tuttavia queste reti non sono configurate per gestire osservazioni complesse.

Se hai un ambiente che espone più di un'osservazione/azione e hai bisogno di personalizzare le tue reti, questo tutorial fa per te!

Impostare

Se non hai ancora installato tf-agent, esegui:

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

Definizione di reti

API di rete

Nel TF-Agenti abbiamo sottoclasse da Keras Networks . Con esso possiamo:

  • Semplifica le operazioni di copia richieste durante la creazione di reti di destinazione.
  • Eseguire la creazione automatica variabile quando si chiama network.variables() .
  • Convalida gli input in base a input_specs di rete.

Rete di codifica

Come accennato in precedenza EncodingNetwork permette di definire facilmente una mappatura di strati di pre-elaborazione per applicare all'ingresso di una rete per generare qualche codifica.

La EncodingNetwork è composta dai seguenti livelli per lo più opzionali:

  • Strati di pre-elaborazione
  • Combinatore di pre-elaborazione
  • Conv2D
  • Appiattire
  • Denso

La particolarità della codifica delle reti è che viene applicata la preelaborazione dell'input. Pre-elaborazione di ingresso è possibile tramite preprocessing_layers e preprocessing_combiner strati. Ognuno di questi può essere specificato come una struttura nidificata. Se il preprocessing_layers nido è meno profonda input_tensor_spec , quindi gli strati sarà possibile ottenere il subnests. Ad esempio, se:

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

quindi la pre-elaborazione chiamerà:

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

Tuttavia se

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

quindi la pre-elaborazione chiamerà:

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

Reti personalizzate

Per creare le proprie reti si avrà solo per sostituire le __init__ e call metodi. Creiamo una rete personalizzata utilizzando quello che abbiamo imparato a conoscere EncodingNetworks per creare un ActorNetwork che prende le osservazioni che contengono un'immagine e un vettore.

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

Creiamo un RandomPyEnvironment per generare osservazioni strutturate e convalidare la nostra implementazione.

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)

Poiché abbiamo definito le osservazioni come un dettato, abbiamo bisogno di creare livelli di pre-elaborazione per gestirli.

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)

Ora che abbiamo la rete di attori, possiamo elaborare le osservazioni dall'ambiente.

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

Questa stessa strategia può essere utilizzata per personalizzare qualsiasi delle principali reti utilizzate dagli agenti. Puoi definire qualsiasi pre-elaborazione e connetterla al resto della rete. Quando definisci la tua personalizzazione, assicurati che le definizioni del livello di output della rete corrispondano.