このページは Cloud Translation API によって翻訳されました。
Switch to English

ネットワーク

TensorFlow.orgで表示 GoogleColabで実行 GitHubでソースを表示ノートブックをダウンロード

前書き

このコラボでは、エージェントのカスタムネットワークを定義する方法について説明します。ネットワークは、エージェントによってトレーニングされるモデルを定義するのに役立ちます。 TF-Agentには、エージェント間で役立ついくつかの異なるタイプのネットワークがあります。

メインネットワーク

  • QNetwork :離散アクションのある環境のQlearningで使用されるこのネットワークは、観測値を、考えられる各アクションの推定値にマップします。
  • CriticNetworks :文献ではValueNetworksとも呼ばれ、ある状態をポリシーの期待収益の見積もりにマッピングするValue関数のバージョンを見積もることを学習します。これらのネットワークは、エージェントが現在どの程度良好な状態にあるかを推定します。
  • ActorNetworks :観察から行動へのマッピングを学びます。これらのネットワークは通常、アクションを生成するためにポリシーによって使用されます。
  • ActorDistributionNetworksActorNetworksに似ていActorNetworksが、これらは、ポリシーがアクションを生成するためにサンプリングできる分布を生成します。

ヘルパーネットワーク

  • EncodingNetwork :ユーザーがネットワークの入力に適用する前処理レイヤーのマッピングを簡単に定義できるようにします。
  • DynamicUnrollLayer :時系列に適用されると、エピソード境界でネットワークの状態を自動的にリセットします。
  • ProjectionNetworkCategoricalProjectionNetworkNormalProjectionNetworkなどのネットワークは、入力をNormalProjectionNetwork 、カテゴリ分布または正規分布を生成するために必要なパラメーターを生成します。

TF-Agentのすべての例には、事前構成されたネットワークが付属しています。ただし、これらのネットワークは、複雑な観測を処理するように設定されていません。

複数の観測/アクションを公開する環境があり、ネットワークをカスタマイズする必要がある場合は、このチュートリアルが最適です。

セットアップ

tf-agentsをまだインストールしていない場合は、次を実行します。

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

ネットワークの定義

ネットワークAPI

TF-Agentでは、KerasNetworksからサブクラス化します。これにより、次のことが可能になります。

  • ターゲットネットワークを作成するときに必要なコピー操作を簡素化します。
  • network.variables()呼び出すときに自動変数作成を実行します。
  • ネットワークinput_specsに基づいて入力を検証します。

EncodingNetwork

上記のように、 EncodingNetwork使用すると、前処理レイヤーのマッピングを簡単に定義して、ネットワークの入力に適用し、エンコードを生成できます。

EncodingNetworkは、次のほとんどオプションのレイヤーで構成されています。

  • 前処理レイヤー
  • 前処理コンバイナー
  • Conv2D
  • 平らにする
  • 密集

ネットワークのエンコードの特別な点は、入力前処理が適用されることです。入力前処理は、 preprocessing_layersおよびpreprocessing_combinerレイヤーを介して可能です。これらはそれぞれ、ネストされた構造として指定できます。 preprocessing_layersネストがinput_tensor_specよりも浅い場合、レイヤーはサブネストを取得します。たとえば、次の場合:

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

その後、前処理は以下を呼び出します。

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

ただし、

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

その後、前処理は以下を呼び出します。

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

カスタムネットワーク

独自のネットワークを作成するには、 __init__メソッドとcallメソッドをオーバーライドするだけです。 EncodingNetworksについて学んだことを使用してカスタムネットワークを作成し、画像とベクトルを含む観測値を取得するActorNetworkを作成しましょう。

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を作成して、構造化された観測RandomPyEnvironmentを生成し、実装を検証しましょう。

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)

観測値をdictとして定義したので、これらを処理する前処理レイヤーを作成する必要があります。

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)

アクターネットワークができたので、環境からの観測を処理できます。

time_step = tf_env.reset()
actor(time_step.observation, time_step.step_type)
(<tf.Tensor: shape=(1, 3), dtype=float32, numpy=array([[5.196383 , 5.20836  , 4.9908404]], dtype=float32)>,
 ())

これと同じ戦略を使用して、エージェントが使用するメインネットワークをカスタマイズできます。前処理を定義して、それをネットワークの残りの部分に接続できます。独自のカスタムを定義するときは、ネットワークの出力レイヤー定義が一致していることを確認してください。