ortamlar

TensorFlow.org'da görüntüleyin Google Colab'da çalıştırın Kaynağı GitHub'da görüntüleyin Not defterini indir

Tanıtım

Reinforcement Learning'in (RL) amacı, bir ortamla etkileşim kurarak öğrenen aracılar tasarlamaktır. Standart RL ayarında, etmen her zaman adımında bir gözlem alır ve bir eylem seçer. Eylem çevreye uygulanır ve çevre bir ödül ve yeni bir gözlem döndürür. Aracı, getiri olarak da bilinen ödüllerin toplamını en üst düzeye çıkarmak için eylemleri seçmek için bir politika eğitir.

TF-Agent'larda ortamlar Python veya TensorFlow'da uygulanabilir. Python ortamlarının uygulanması, anlaşılması ve hata ayıklaması genellikle daha kolaydır, ancak TensorFlow ortamları daha verimlidir ve doğal paralelleştirmeye izin verir. En yaygın iş akışı, Python'da bir ortam uygulamak ve onu otomatik olarak TensorFlow'a dönüştürmek için sarmalayıcılarımızdan birini kullanmaktır.

Önce Python ortamlarına bakalım. TensorFlow ortamları çok benzer bir API izler.

Kurmak

Henüz tf-agents veya gym yüklemediyseniz, şunu çalıştırın:

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 py_environment
from tf_agents.environments import tf_environment
from tf_agents.environments import tf_py_environment
from tf_agents.environments import utils
from tf_agents.specs import array_spec
from tf_agents.environments import wrappers
from tf_agents.environments import suite_gym
from tf_agents.trajectories import time_step as ts

Python Ortamları

Python ortamları var step(action) -> next_time_step ortama bir eylem uygular ve sonraki adım hakkında şu bilgileri verir yöntemi:

  1. observation : Bu ajan sonraki adımda kendi eylemlerini seçme gözlemleyebilirsiniz çevre devletin bir parçasıdır.
  2. reward : ajan Birden çok adımda bu ödülleri toplamını maksimize etmek öğreniyor.
  3. step_type : çevre ile etkileşim genellikle bir sekans / bölüm bir parçasıdır. örneğin bir satranç oyununda birden fazla hamle. step_type olabilir ya FIRST , MID veya LAST bu kez aşaması bir sırayla, birinci ara ya da son aşama olup olmadığını gösterir.
  4. discount : Bu şimdiki zaman adımında ödülüne dahaki sefere adım nispetle ödül ağırlık ne kadar temsil eden bir şamandıra olduğunu.

Bunlar adlandırılmış tanımlama grubu halinde gruplandırılır TimeStep(step_type, reward, discount, observation) .

Tüm Python ortamları uygulamaları gerektiğini arayüz olduğu environments/py_environment.PyEnvironment . Ana yöntemler şunlardır:

class PyEnvironment(object):

  def reset(self):
    """Return initial_time_step."""
    self._current_time_step = self._reset()
    return self._current_time_step

  def step(self, action):
    """Apply action and return new time_step."""
    if self._current_time_step is None:
        return self.reset()
    self._current_time_step = self._step(action)
    return self._current_time_step

  def current_time_step(self):
    return self._current_time_step

  def time_step_spec(self):
    """Return time_step_spec."""

  @abc.abstractmethod
  def observation_spec(self):
    """Return observation_spec."""

  @abc.abstractmethod
  def action_spec(self):
    """Return action_spec."""

  @abc.abstractmethod
  def _reset(self):
    """Return initial_time_step."""

  @abc.abstractmethod
  def _step(self, action):
    """Apply action and return new time_step."""

Ek olarak step() yöntemi, ortamlar da temin reset() , yeni bir dizisini başlatır ve bir ilk içerir yöntem TimeStep . Aramaya gerek yoktur reset açıkça yöntemi. Bir bölümün sonuna geldiklerinde veya step() ilk kez çağrıldığında ortamların otomatik olarak sıfırlandığını varsayıyoruz.

Not alt sınıfları uygulamamanızı step() veya reset() doğrudan. Bunlar yerine geçersiz _step() ve _reset() yöntemleri. Bu yöntemlerin döndü zaman adım önbelleğe ve içinden maruz kalacak current_time_step() .

observation_spec ve action_spec yöntemler bir yuva dönüş (Bounded)ArraySpecs sırasıyla gözlem ve eylemlerin isim, şekil, veri türü ve aralıkları tarif eder.

TF-Agent'larda, listeler, demetler, adlandırılmış demetler veya sözlüklerden oluşan herhangi bir ağaç benzeri yapı olarak tanımlanan yuvalara tekrar tekrar atıfta bulunuruz. Bunlar, gözlemlerin ve eylemlerin yapısını korumak için keyfi olarak oluşturulabilir. Bunu, birçok gözlem ve eylemin olduğu daha karmaşık ortamlar için çok yararlı bulduk.

Standart Ortamları Kullanma

TF Ajanlar yerleşik OpenAI Spor Salonu, DeepMind-kontrol ve Atari gibi birçok standart ortamlar için sargılar, onlar bizim izleyin böylece py_environment.PyEnvironment arayüzü. Bu sarılmış ortamlar, ortam paketlerimiz kullanılarak kolayca yüklenebilir. OpenAI spor salonundan CartPole ortamını yükleyelim ve eyleme ve time_step_spec'e bakalım.

environment = suite_gym.load('CartPole-v0')
print('action_spec:', environment.action_spec())
print('time_step_spec.observation:', environment.time_step_spec().observation)
print('time_step_spec.step_type:', environment.time_step_spec().step_type)
print('time_step_spec.discount:', environment.time_step_spec().discount)
print('time_step_spec.reward:', environment.time_step_spec().reward)
action_spec: BoundedArraySpec(shape=(), dtype=dtype('int64'), name='action', minimum=0, maximum=1)
time_step_spec.observation: BoundedArraySpec(shape=(4,), dtype=dtype('float32'), name='observation', minimum=[-4.8000002e+00 -3.4028235e+38 -4.1887903e-01 -3.4028235e+38], maximum=[4.8000002e+00 3.4028235e+38 4.1887903e-01 3.4028235e+38])
time_step_spec.step_type: ArraySpec(shape=(), dtype=dtype('int32'), name='step_type')
time_step_spec.discount: BoundedArraySpec(shape=(), dtype=dtype('float32'), name='discount', minimum=0.0, maximum=1.0)
time_step_spec.reward: ArraySpec(shape=(), dtype=dtype('float32'), name='reward')

Biz çevre tipi eylemlerini beklediğini görüyoruz Yani int64 içinde [0, 1] ve iadeler TimeSteps gözlemler bir olan float32 uzunluğu 4 ve indirimli faktörünün vektör, float32 [0.0, 1.0] içinde. Şimdi, sabit bir eylemde deneyelim (1,) bir bütün bölüm için.

action = np.array(1, dtype=np.int32)
time_step = environment.reset()
print(time_step)
while not time_step.is_last():
  time_step = environment.step(action)
  print(time_step)
TimeStep(
{'discount': array(1., dtype=float32),
 'observation': array([-0.0267876 ,  0.00672831, -0.00395687, -0.03253767], dtype=float32),
 'reward': array(0., dtype=float32),
 'step_type': array(0, dtype=int32)})
TimeStep(
{'discount': array(1., dtype=float32),
 'observation': array([-0.02665303,  0.20190677, -0.00460763, -0.3264664 ], dtype=float32),
 'reward': array(1., dtype=float32),
 'step_type': array(1, dtype=int32)})
TimeStep(
{'discount': array(1., dtype=float32),
 'observation': array([-0.0226149 ,  0.397094  , -0.01113695, -0.6205988 ], dtype=float32),
 'reward': array(1., dtype=float32),
 'step_type': array(1, dtype=int32)})
TimeStep(
{'discount': array(1., dtype=float32),
 'observation': array([-0.01467302,  0.59236974, -0.02354893, -0.9167684 ], dtype=float32),
 'reward': array(1., dtype=float32),
 'step_type': array(1, dtype=int32)})
TimeStep(
{'discount': array(1., dtype=float32),
 'observation': array([-0.00282562,  0.78780204, -0.0418843 , -1.2167584 ], dtype=float32),
 'reward': array(1., dtype=float32),
 'step_type': array(1, dtype=int32)})
TimeStep(
{'discount': array(1., dtype=float32),
 'observation': array([ 0.01293042,  0.9834384 , -0.06621946, -1.5222659 ], dtype=float32),
 'reward': array(1., dtype=float32),
 'step_type': array(1, dtype=int32)})
TimeStep(
{'discount': array(1., dtype=float32),
 'observation': array([ 0.03259919,  1.179295  , -0.09666478, -1.834861  ], dtype=float32),
 'reward': array(1., dtype=float32),
 'step_type': array(1, dtype=int32)})
TimeStep(
{'discount': array(1., dtype=float32),
 'observation': array([ 0.05618509,  1.3753439 , -0.13336201, -2.155937  ], dtype=float32),
 'reward': array(1., dtype=float32),
 'step_type': array(1, dtype=int32)})
TimeStep(
{'discount': array(1., dtype=float32),
 'observation': array([ 0.08369196,  1.5714991 , -0.17648074, -2.4866495 ], dtype=float32),
 'reward': array(1., dtype=float32),
 'step_type': array(1, dtype=int32)})
TimeStep(
{'discount': array(0., dtype=float32),
 'observation': array([ 0.11512195,  1.7675985 , -0.22621372, -2.827846  ], dtype=float32),
 'reward': array(1., dtype=float32),
 'step_type': array(2, dtype=int32)})

Kendi Python Ortamınızı Oluşturmak

Birçok müşteri için yaygın bir kullanım durumu, TF-Agent'lardaki standart aracılardan birini (bakınız aracılar/) sorunlarına uygulamaktır. Bunu yapmak için problemlerini bir çevre olarak çerçevelemek zorundalar. Şimdi Python'da bir ortamın nasıl uygulanacağına bakalım.

Aşağıdaki (Black Jack'ten ilham alan) kart oyununu oynamak için bir temsilci yetiştirmek istediğimizi varsayalım:

  1. Oyun, 1...10 numaralı sonsuz bir iskambil destesi kullanılarak oynanır.
  2. Temsilci her fırsatta 2 şey yapabilir: yeni bir rastgele kart almak veya mevcut turu durdurmak.
  3. Amaç, tur sonunda kartların toplamını 21'e mümkün olduğunca yakın, atlamadan elde etmektir.

Oyunu temsil eden bir ortam şöyle görünebilir:

  1. Eylemler: 2 eylemimiz var. Eylem 0: yeni bir kart alın ve Eylem 1: mevcut turu sonlandırın.
  2. Gözlemler: Mevcut turdaki kartların toplamı.
  3. Ödül: Amaç, 21'e atlamadan olabildiğince yaklaşmak, böylece turun sonunda aşağıdaki ödülü kullanarak bunu başarabiliriz: sum_of_cards - 21 if sum_of_cards <= 21, else -21
class CardGameEnv(py_environment.PyEnvironment):

  def __init__(self):
    self._action_spec = array_spec.BoundedArraySpec(
        shape=(), dtype=np.int32, minimum=0, maximum=1, name='action')
    self._observation_spec = array_spec.BoundedArraySpec(
        shape=(1,), dtype=np.int32, minimum=0, name='observation')
    self._state = 0
    self._episode_ended = False

  def action_spec(self):
    return self._action_spec

  def observation_spec(self):
    return self._observation_spec

  def _reset(self):
    self._state = 0
    self._episode_ended = False
    return ts.restart(np.array([self._state], dtype=np.int32))

  def _step(self, action):

    if self._episode_ended:
      # The last action ended the episode. Ignore the current action and start
      # a new episode.
      return self.reset()

    # Make sure episodes don't go on forever.
    if action == 1:
      self._episode_ended = True
    elif action == 0:
      new_card = np.random.randint(1, 11)
      self._state += new_card
    else:
      raise ValueError('`action` should be 0 or 1.')

    if self._episode_ended or self._state >= 21:
      reward = self._state - 21 if self._state <= 21 else -21
      return ts.termination(np.array([self._state], dtype=np.int32), reward)
    else:
      return ts.transition(
          np.array([self._state], dtype=np.int32), reward=0.0, discount=1.0)

Yukarıdaki ortamı tanımlayan her şeyi doğru yaptığımızdan emin olalım. Kendi ortamınızı yaratırken, oluşturulan gözlemlerin ve zaman adımlarının, özelliklerinizde tanımlandığı gibi doğru şekil ve türleri takip ettiğinden emin olmalısınız. Bunlar, TensorFlow grafiğini oluşturmak için kullanılır ve bu nedenle, yanlış anlarsak hata ayıklaması zor sorunlar yaratabilir.

Ortamımızı doğrulamak için eylemler oluşturmak için rastgele bir politika kullanacağız ve işlerin istendiği gibi çalıştığından emin olmak için 5 bölüm üzerinde yineleyeceğiz. Ortam özelliklerine uymayan bir time_step alırsak bir hata oluşur.

environment = CardGameEnv()
utils.validate_py_environment(environment, episodes=5)

Artık ortamın amaçlandığı gibi çalıştığını bildiğimize göre, bu ortamı sabit bir politika kullanarak çalıştıralım: 3 kart isteyin ve ardından turu bitirin.

get_new_card_action = np.array(0, dtype=np.int32)
end_round_action = np.array(1, dtype=np.int32)

environment = CardGameEnv()
time_step = environment.reset()
print(time_step)
cumulative_reward = time_step.reward

for _ in range(3):
  time_step = environment.step(get_new_card_action)
  print(time_step)
  cumulative_reward += time_step.reward

time_step = environment.step(end_round_action)
print(time_step)
cumulative_reward += time_step.reward
print('Final Reward = ', cumulative_reward)
TimeStep(
{'discount': array(1., dtype=float32),
 'observation': array([0], dtype=int32),
 'reward': array(0., dtype=float32),
 'step_type': array(0, dtype=int32)})
TimeStep(
{'discount': array(1., dtype=float32),
 'observation': array([6], dtype=int32),
 'reward': array(0., dtype=float32),
 'step_type': array(1, dtype=int32)})
TimeStep(
{'discount': array(1., dtype=float32),
 'observation': array([16], dtype=int32),
 'reward': array(0., dtype=float32),
 'step_type': array(1, dtype=int32)})
TimeStep(
{'discount': array(0., dtype=float32),
 'observation': array([21], dtype=int32),
 'reward': array(0., dtype=float32),
 'step_type': array(2, dtype=int32)})
TimeStep(
{'discount': array(0., dtype=float32),
 'observation': array([21], dtype=int32),
 'reward': array(0., dtype=float32),
 'step_type': array(2, dtype=int32)})
Final Reward =  0.0

Çevre Sarmalayıcılar

Bir ortam sarmalayıcı, bir Python ortamını alır ve ortamın değiştirilmiş bir sürümünü döndürür. Orijinal çevre ve modifiye ortam Hem örnekleri olan py_environment.PyEnvironment ve çoklu sarma birlikte zincirleme edilebilir.

Bazı yaygın sarmalayıcıları bulunabilir environments/wrappers.py . Örneğin:

  1. ActionDiscretizeWrapper : dönüştürür ayrı bir işlem alanı için sürekli bir hareket alanı.
  2. RunStats : Yakalar böyle atılan adımlar sayısı gibi çevre istatistiklerini çalıştırın bölüm sayısı tamamladı vb
  3. TimeLimit : adımların sabit sayıda sonra bölüm sonlandırır.

Örnek 1: Eylem Ayrık Sarmalayıcı

InvertedPendulum aralığında sürekli işlemleri kabul eden bir PyBullet ortamı [-2, 2] . Bu ortamda DQN gibi ayrık bir eylem ajanı eğitmek istiyorsak eylem uzayını ayrıklaştırmamız (nicelleştirmemiz) gerekir. Bu tam olarak ne ActionDiscretizeWrapper yapar. Karşılaştırma action_spec öncesi ve sarma sonra:

env = suite_gym.load('Pendulum-v0')
print('Action Spec:', env.action_spec())

discrete_action_env = wrappers.ActionDiscretizeWrapper(env, num_actions=5)
print('Discretized Action Spec:', discrete_action_env.action_spec())
Action Spec: BoundedArraySpec(shape=(1,), dtype=dtype('float32'), name='action', minimum=-2.0, maximum=2.0)
Discretized Action Spec: BoundedArraySpec(shape=(), dtype=dtype('int32'), name='action', minimum=0, maximum=4)

Sarılmış discrete_action_env bir örneği olan py_environment.PyEnvironment ve düzenli bir Python ortam gibi tedavi edilebilir.

TensorFlow Ortamları

TF ortamları için arayüz tanımlanır environments/tf_environment.TFEnvironment ve Python ortamlarında çok benzer görünüyor. TF Ortamları, Python ortamlarından birkaç yönden farklıdır:

  • Diziler yerine tensör nesneleri üretirler
  • TF ortamları, spesifikasyonlarla karşılaştırıldığında oluşturulan tensörlere bir toplu boyut ekler.

Python ortamlarını TFEnvs'e dönüştürmek, tensorflow'un işlemleri paralelleştirmesine olanak tanır. Örneğin, bir bir tanımlayabilir collect_experience_op olduğu toplar ortamdan veriler ve ekler replay_buffer ve train_op okur replay_buffer ve madde trenler ve TensorFlow doğal olarak, paralel olarak çalışır.

class TFEnvironment(object):

  def time_step_spec(self):
    """Describes the `TimeStep` tensors returned by `step()`."""

  def observation_spec(self):
    """Defines the `TensorSpec` of observations provided by the environment."""

  def action_spec(self):
    """Describes the TensorSpecs of the action expected by `step(action)`."""

  def reset(self):
    """Returns the current `TimeStep` after resetting the Environment."""
    return self._reset()

  def current_time_step(self):
    """Returns the current `TimeStep`."""
    return self._current_time_step()

  def step(self, action):
    """Applies the action and returns the new `TimeStep`."""
    return self._step(action)

  @abc.abstractmethod
  def _reset(self):
    """Returns the current `TimeStep` after resetting the Environment."""

  @abc.abstractmethod
  def _current_time_step(self):
    """Returns the current `TimeStep`."""

  @abc.abstractmethod
  def _step(self, action):
    """Applies the action and returns the new `TimeStep`."""

current_time_step() metodu mevcut time_step döner ve gerekirse çevre başlatır.

reset() metodu kuvvetleri çevre ve geri dönüş CURRENT_STEP bir reset.

Eğer action önceki bağlı değildir time_step bir tf.control_dependency gerekli olduğunu Graph modu.

Şimdilik, bize nasıl bakalım TFEnvironments oluşturulur.

Kendi TensorFlow Ortamınızı Oluşturma

Bu, Python'da ortamlar oluşturmaktan daha karmaşıktır, bu nedenle bu ortak çalışmada ele almayacağız. Bir örnek mevcuttur burada . Daha yaygın kullanım şeklidir Python ortamınızı uygulamak ve bizim kullanarak TensorFlow onu sarmak için olan TFPyEnvironment sarmalayıcı (aşağıya bakınız).

TensorFlow'da Python Ortamını Sarma

Biz kolayca kullanarak TensorFlow ortamına herhangi bir Python ortamı sarabilirsiniz TFPyEnvironment sarmalayıcı.

env = suite_gym.load('CartPole-v0')
tf_env = tf_py_environment.TFPyEnvironment(env)

print(isinstance(tf_env, tf_environment.TFEnvironment))
print("TimeStep Specs:", tf_env.time_step_spec())
print("Action Specs:", tf_env.action_spec())
True
TimeStep Specs: TimeStep(
{'discount': BoundedTensorSpec(shape=(), dtype=tf.float32, name='discount', minimum=array(0., dtype=float32), maximum=array(1., dtype=float32)),
 'observation': BoundedTensorSpec(shape=(4,), dtype=tf.float32, name='observation', minimum=array([-4.8000002e+00, -3.4028235e+38, -4.1887903e-01, -3.4028235e+38],
      dtype=float32), maximum=array([4.8000002e+00, 3.4028235e+38, 4.1887903e-01, 3.4028235e+38],
      dtype=float32)),
 'reward': TensorSpec(shape=(), dtype=tf.float32, name='reward'),
 'step_type': TensorSpec(shape=(), dtype=tf.int32, name='step_type')})
Action Specs: BoundedTensorSpec(shape=(), dtype=tf.int64, name='action', minimum=array(0), maximum=array(1))

: Gözlük Çeşidi şimdi Not (Bounded)TensorSpec .

Kullanım Örnekleri

Basit Örnek

env = suite_gym.load('CartPole-v0')

tf_env = tf_py_environment.TFPyEnvironment(env)
# reset() creates the initial time_step after resetting the environment.
time_step = tf_env.reset()
num_steps = 3
transitions = []
reward = 0
for i in range(num_steps):
  action = tf.constant([i % 2])
  # applies the action and returns the new TimeStep.
  next_time_step = tf_env.step(action)
  transitions.append([time_step, action, next_time_step])
  reward += next_time_step.reward
  time_step = next_time_step

np_transitions = tf.nest.map_structure(lambda x: x.numpy(), transitions)
print('\n'.join(map(str, np_transitions)))
print('Total reward:', reward.numpy())
[TimeStep(
{'discount': array([1.], dtype=float32),
 'observation': array([[ 0.00300747,  0.00684385,  0.03566956, -0.008827  ]],
      dtype=float32),
 'reward': array([0.], dtype=float32),
 'step_type': array([0], dtype=int32)}), array([0], dtype=int32), TimeStep(
{'discount': array([1.], dtype=float32),
 'observation': array([[ 0.00314435, -0.18877101,  0.03549302,  0.2948933 ]],
      dtype=float32),
 'reward': array([1.], dtype=float32),
 'step_type': array([1], dtype=int32)})]
[TimeStep(
{'discount': array([1.], dtype=float32),
 'observation': array([[ 0.00314435, -0.18877101,  0.03549302,  0.2948933 ]],
      dtype=float32),
 'reward': array([1.], dtype=float32),
 'step_type': array([1], dtype=int32)}), array([1], dtype=int32), TimeStep(
{'discount': array([1.], dtype=float32),
 'observation': array([[-0.00063107,  0.00582743,  0.04139088,  0.01361222]],
      dtype=float32),
 'reward': array([1.], dtype=float32),
 'step_type': array([1], dtype=int32)})]
[TimeStep(
{'discount': array([1.], dtype=float32),
 'observation': array([[-0.00063107,  0.00582743,  0.04139088,  0.01361222]],
      dtype=float32),
 'reward': array([1.], dtype=float32),
 'step_type': array([1], dtype=int32)}), array([0], dtype=int32), TimeStep(
{'discount': array([1.], dtype=float32),
 'observation': array([[-0.00051452, -0.18986294,  0.04166313,  0.3190618 ]],
      dtype=float32),
 'reward': array([1.], dtype=float32),
 'step_type': array([1], dtype=int32)})]
Total reward: [3.]

Tüm Bölümler

env = suite_gym.load('CartPole-v0')
tf_env = tf_py_environment.TFPyEnvironment(env)

time_step = tf_env.reset()
rewards = []
steps = []
num_episodes = 5

for _ in range(num_episodes):
  episode_reward = 0
  episode_steps = 0
  while not time_step.is_last():
    action = tf.random.uniform([1], 0, 2, dtype=tf.int32)
    time_step = tf_env.step(action)
    episode_steps += 1
    episode_reward += time_step.reward.numpy()
  rewards.append(episode_reward)
  steps.append(episode_steps)
  time_step = tf_env.reset()

num_steps = np.sum(steps)
avg_length = np.mean(steps)
avg_reward = np.mean(rewards)

print('num_episodes:', num_episodes, 'num_steps:', num_steps)
print('avg_length', avg_length, 'avg_reward:', avg_reward)
num_episodes: 5 num_steps: 102
avg_length 20.4 avg_reward: 20.4