רשתות

הצג באתר TensorFlow.org הפעל בגוגל קולאב צפה במקור ב-GitHub הורד מחברת

מבוא

בקולאב זה נסקור כיצד להגדיר רשתות מותאמות אישית עבור הסוכנים שלך. הרשתות עוזרות לנו להגדיר את המודל שאומן על ידי סוכנים. ב-TF-Agents תמצאו מספר סוגים שונים של רשתות שימושיות בין סוכנים:

רשתות ראשיות

  • QNetwork: משמש Qlearning עבור סביבות עם פעולות נפרדות, רשת זו ממפה תצפית הערכות שווי עבור כל פעולה אפשרית.
  • CriticNetworks: המכונה גם ValueNetworks בספרות, לומד להעריך גרסה כלשהי של פונקציה ערך מיפוי כמה המדינה לתוך אומדן התשואה הצפויה של מדיניות. רשתות אלו מעריכות עד כמה טוב המצב בו הסוכן נמצא כעת.
  • ActorNetworks: למד מיפוי מתצפיות לפעולות. רשתות אלו משמשות בדרך כלל את המדיניות שלנו כדי ליצור פעולות.
  • ActorDistributionNetworks: בדומה ActorNetworks אבל אלה יוצר חלוקה אשר פוליסה יכולה אז מדגם כדי ליצור פעולות.

רשתות עוזרות

  • EncodingNetwork: מאפשר למשתמשים להגדיר מיפוי בקלות שכבות טרום עיבוד ליישם לקלט של רשת.
  • DynamicUnrollLayer: אוטומטי מאפס את מצב הרשת על גבולות פרק כפי שהוא מוחל על פני רצף זמן.
  • ProjectionNetwork: רשתות כמו CategoricalProjectionNetwork או NormalProjectionNetwork לקחת תשומות וליצור את הפרמטרים הנדרשים כדי ליצור הקטגורי, או הפצות רגילות.

כל הדוגמאות ב-TF-Agents מגיעות עם רשתות מוגדרות מראש. עם זאת, רשתות אלו אינן מוגדרות לטיפול בתצפיות מורכבות.

אם יש לך סביבה שחושפת יותר מתצפית/פעולה אחת ואתה צריך להתאים אישית את הרשתות שלך אז המדריך הזה הוא בשבילך!

להכין

אם עדיין לא התקנת tf-agents, הרץ:

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

הגדרת רשתות

ממשק API של רשת

In-סוכנים TF אנו מכל מחלקה מן Keras נטוורקס . בעזרתו נוכל:

  • פשט את פעולות ההעתקה הנדרשות בעת יצירת רשתות יעד.
  • בצע יצירה משתנה אוטומטית כאשר אתה מתקשר network.variables() .
  • אמת קלט בהתבסס על מפרט_הקלט של הרשת.

EncodingNetwork

כפי שהוזכר מעל EncodingNetwork מאפשר לנו להגדיר מיפוי בקלות שכבות טרום עיבוד ליישם לקלט של הרשת כדי ליצור כמה קידוד.

רשת הקידוד מורכבת מהשכבות הבאות בעיקר אופציונליות:

  • עיבוד מוקדם של שכבות
  • משלב עיבוד מקדים
  • Conv2D
  • לְשַׁטֵחַ
  • צָפוּף

הדבר המיוחד בקידוד רשתות הוא שמופעל עיבוד מקדים של קלט. עיבוד מקדים קלט אפשרי באמצעות preprocessing_layers ו preprocessing_combiner שכבות. ניתן לציין כל אחד מאלה כמבנה מקונן. אם preprocessing_layers הקן הוא רדוד יותר input_tensor_spec , אז ההשכבות תקבלנה את subnests. לדוגמה, אם:

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 ליצור תצפיות מובנות ולאמת היישום שלנו.

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)

מכיוון שהגדרנו את התצפיות ככתבה, עלינו ליצור שכבות עיבוד מקדים כדי לטפל בהן.

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([[4.5753636, 4.946792 , 4.853481 ]], dtype=float32)>,
 ())

באותה אסטרטגיה ניתן להשתמש כדי להתאים אישית כל אחת מהרשתות העיקריות שבהן משתמשים הסוכנים. אתה יכול להגדיר כל עיבוד מקדים ולחבר אותו לשאר הרשת. בזמן שאתה מגדיר מותאם אישית משלך ודא שהגדרות שכבת הפלט של הרשת תואמות.