Google I / O'daki önemli notları, ürün oturumlarını, atölyeleri ve daha fazlasını izleyin Oynatma listesine bakın

Ortamlar

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

Giriş

Takviyeli Öğrenmenin (RL) amacı, bir çevre ile etkileşime girerek öğrenen aracılar tasarlamaktır. Standart RL ayarında, aracı her adımda 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. Temsilci, geri dönüş olarak da bilinen ödüllerin toplamını en üst düzeye çıkarmak için eylemler seçmek üzere bir politika geliştirir.

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'yi takip eder.

Kurulum

Henüz tf-agent veya gym kurmadıysanız, şunu çalıştırın:

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

tf.compat.v1.enable_v2_behavior()

Python Ortamları

Python ortamlarının, ortama bir eylem uygulayan ve sonraki adım hakkında aşağıdaki bilgileri döndüren bir step(action) -> next_time_step yöntemi vardır:

  1. observation : Bu, ortam durumunun, aracının bir sonraki adımda eylemlerini seçmek için gözlemleyebileceği bölümüdür.
  2. reward : Temsilci, bu ödüllerin toplamını birden çok adımda en üst düzeye çıkarmayı öğreniyor.
  3. step_type : Çevre ile etkileşimler genellikle bir dizinin / bölümün parçasıdır. örneğin bir satranç oyununda birden fazla hamle. step_type, bu zaman adımının bir dizideki ilk, ara veya son adım olduğunu belirtmek için FIRST , MID veya LAST olabilir.
  4. discount : Bu, bir sonraki adımda ödülün geçerli zaman adımındaki ödüle göre ne kadar ağırlıklandırılacağını temsil eden bir kayan değerdir.

Bunlar, adlandırılmış bir TimeStep(step_type, reward, discount, observation) olarak gruplandırılır.

Tüm Python ortamlarının uygulaması gereken arayüz, environments/py_environment.PyEnvironment . Ana yöntemler:

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."""

Ortamlar step() yöntemine ek olarak, yeni bir dizi başlatan ve bir başlangıç TimeStep sağlayan bir reset() yöntemi de sağlar. reset yöntemini açıkça çağırmak gerekli değildir. Bir bölümün sonuna geldiklerinde veya () adımı ilk kez çağrıldığında ortamların otomatik olarak sıfırlandığını varsayıyoruz.

Alt sınıfların step() veya reset() doğrudan uygulamadığını unutmayın. Bunun yerine _step() ve _reset() yöntemlerini geçersiz _step() . Bu yöntemlerden döndürülen zaman adımları önbelleğe alınacak ve current_time_step() aracılığıyla gösterilecektir.

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, tuplelar, isimlendirilmiş tuplelar 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 eyleminizin olduğu daha karmaşık ortamlar için çok yararlı bulduk.

Standart Ortamları Kullanma

TF Agent'lar, OpenAI Gym, DeepMind-control ve Atari gibi birçok standart ortam için yerleşik sarmalayıcılara sahiptir, böylece py_environment.PyEnvironment arayüzümüzü takip py_environment.PyEnvironment . Bu sarılı ortamlar, çevre süitlerimiz kullanılarak kolayca yüklenebilir. CartPole ortamını OpenAI spor salonundan yükleyelim ve action 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, tüm bölüm için sabit bir eylem (1,) yapmaya çalışalım.

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(step_type=array(0, dtype=int32), reward=array(0., dtype=float32), discount=array(1., dtype=float32), observation=array([ 0.01285449,  0.04769544,  0.01983412, -0.00245379], dtype=float32))
TimeStep(step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32), observation=array([ 0.0138084 ,  0.24252741,  0.01978504, -0.2888134 ], dtype=float32))
TimeStep(step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32), observation=array([ 0.01865895,  0.43736172,  0.01400878, -0.57519126], dtype=float32))
TimeStep(step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32), observation=array([ 0.02740618,  0.6322845 ,  0.00250495, -0.8634283 ], dtype=float32))
TimeStep(step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32), observation=array([ 0.04005187,  0.82737225, -0.01476362, -1.1553226 ], dtype=float32))
TimeStep(step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32), observation=array([ 0.05659932,  1.0226836 , -0.03787007, -1.452598  ], dtype=float32))
TimeStep(step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32), observation=array([ 0.07705299,  1.2182497 , -0.06692202, -1.7568679 ], dtype=float32))
TimeStep(step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32), observation=array([ 0.10141798,  1.4140631 , -0.10205939, -2.069591  ], dtype=float32))
TimeStep(step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32), observation=array([ 0.12969925,  1.6100639 , -0.1434512 , -2.3920157 ], dtype=float32))
TimeStep(step_type=array(1, dtype=int32), reward=array(1., dtype=float32), discount=array(1., dtype=float32), observation=array([ 0.16190052,  1.8061239 , -0.19129153, -2.725115  ], dtype=float32))
TimeStep(step_type=array(2, dtype=int32), reward=array(1., dtype=float32), discount=array(0., dtype=float32), observation=array([ 0.198023  ,  2.002027  , -0.24579382, -3.0695074 ], dtype=float32))

Kendi Python Ortamınızı Oluşturmak

Birçok müşteri için yaygın bir kullanım durumu, TF-Agent'lardaki standart ajanlardan birini (bkz. Aracılar /) sorunlarına uygulamaktır. Bunu yapmak için, sorunlarını bir çevre olarak çerçevelemeleri gerekir. Öyleyse Python'da bir ortamın nasıl uygulanacağına bakalım.

Aşağıdaki (Black Jack'den ilham alan) kart oyununu oynaması için bir temsilciyi eğitmek istediğimizi varsayalım:

  1. Oyun, 1 ... 10 numaralı kartlardan oluşan sonsuz bir desteyle oynanır.
  2. Temsilci her fırsatta 2 şey yapabilir: yeni bir rastgele kart almak veya mevcut turu durdurmak.
  3. Amaç, turun sonunda kartlarınızın toplamını mümkün olduğunca 21'e yaklaştırmaktır.

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ç, üstünden geçmeden mümkün olduğunca 21'e yaklaşmaktır, böylece bunu turun sonunda aşağıdaki ödülü kullanarak başarabiliriz: sum_of_cards - sum_of_cards <= 21 ise 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ı doğru bir şekilde tanımlayan her şeyi yaptığımızdan emin olalım. Kendi ortamınızı oluştururken, oluşturulan gözlemlerin ve zaman_ adımlarının, özelliklerinizde tanımlanan doğru şekil ve türlere uyduğundan 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.

Çevremizi doğrulamak için eylemler oluşturmak için rastgele bir politika kullanacağız ve işlerin amaçlandığı gibi çalıştığından emin olmak için 5 bölümden fazla yineleme yapacağız. Ortam özelliklerine uymayan bir zaman adımı 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(step_type=array(0, dtype=int32), reward=array(0., dtype=float32), discount=array(1., dtype=float32), observation=array([0], dtype=int32))
TimeStep(step_type=array(1, dtype=int32), reward=array(0., dtype=float32), discount=array(1., dtype=float32), observation=array([2], dtype=int32))
TimeStep(step_type=array(1, dtype=int32), reward=array(0., dtype=float32), discount=array(1., dtype=float32), observation=array([7], dtype=int32))
TimeStep(step_type=array(1, dtype=int32), reward=array(0., dtype=float32), discount=array(1., dtype=float32), observation=array([8], dtype=int32))
TimeStep(step_type=array(2, dtype=int32), reward=array(-13., dtype=float32), discount=array(0., dtype=float32), observation=array([8], dtype=int32))
Final Reward =  -13.0

Çevre Sarmalayıcıları

Bir ortam sarmalayıcısı bir Python ortamını alır ve ortamın değiştirilmiş bir sürümünü döndürür. Hem orijinal ortam hem de değiştirilmiş ortam py_environment.PyEnvironment örnekleridir ve birden çok sarmalayıcı birbirine zincirlenebilir.

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

  1. ActionDiscretizeWrapper : Sürekli bir eylem alanını ayrı bir eylem alanına dönüştürür.
  2. RunStats : RunStats adım sayısı, tamamlanan bölüm sayısı vb. Gibi ortamın çalıştırma istatistiklerini yakalar.
  3. TimeLimit : Belirli sayıda adımdan sonra bölümü sonlandırır.

Örnek 1: Eylem Discretize Wrapper

InvertedPendulum, [-2, 2] aralığında sürekli eylemleri kabul eden bir PyBullet ortamıdır. Bu ortamda DQN gibi ayrı bir eylem aracısını eğitmek istiyorsak, eylem alanını ayırmalıyız (nicelleştirmeliyiz). ActionDiscretizeWrapper yaptığı tam olarak budur. action_spec önceki ve sonraki action_spec karşılaştırın:

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)

py_environment.PyEnvironment discrete_action_env , py_environment.PyEnvironment bir örneğidir ve normal bir Python ortamı gibi değerlendirilebilir.

TensorFlow Ortamları

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

  • Diziler yerine tensör nesneleri üretirler
  • TF ortamları, spesifikasyonlarla karşılaştırıldığında üretilen tensörlere bir parti boyutu ekler.

Python ortamlarını TFEnv'lere dönüştürmek, tensorflow'un işlemleri paralelleştirmesine izin verir. Örneğin, collect_experience_op veri toplayan ve bir replay_buffer ekleyen bir replay_buffer ve train_op okuyan ve replay_buffer eğiten ve TensorFlow'da doğal olarak paralel olarak çalıştıran bir train_op tanımlanabilir.

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 current_time_step() yöntemi, geçerli time_step'i döndürür ve gerekirse ortamı başlatır.

reset() yöntemi, ortamda bir sıfırlamayı zorlar ve current_step'i döndürür.

action önceki time_step bağlı tf.control_dependency , Graph modunda bir tf.control_dependency gereklidir.

Şimdilik, TFEnvironments nasıl TFEnvironments bakalım.

Kendi TensorFlow Ortamınızı oluşturma

Bu, Python'da ortam oluşturmaktan daha karmaşıktır, bu yüzden bu yazıda bunu ele almayacağız. Burada bir örnek mevcuttur. Daha yaygın kullanım durumu, ortamınızı Python'da uygulamak ve TFPyEnvironment sarmalayıcımızı kullanarak TFPyEnvironment (aşağıya bakın).

TensorFlow'da Python Ortamını Sarma

TFPyEnvironment sarmalayıcısını kullanarak herhangi bir Python ortamını bir TensorFlow ortamına kolayca sarabiliriz.

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(step_type=TensorSpec(shape=(), dtype=tf.int32, name='step_type'), reward=TensorSpec(shape=(), dtype=tf.float32, name='reward'), 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)))
Action Specs: BoundedTensorSpec(shape=(), dtype=tf.int64, name='action', minimum=array(0), maximum=array(1))

Özelliklerin artık şu türde (Bounded)TensorSpec : (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(step_type=array([0], dtype=int32), reward=array([0.], dtype=float32), discount=array([1.], dtype=float32), observation=array([[-0.03501577, -0.04957427,  0.00623939,  0.03762257]],
      dtype=float32)), array([0], dtype=int32), TimeStep(step_type=array([1], dtype=int32), reward=array([1.], dtype=float32), discount=array([1.], dtype=float32), observation=array([[-0.03600726, -0.24478514,  0.00699184,  0.33226755]],
      dtype=float32))]
[TimeStep(step_type=array([1], dtype=int32), reward=array([1.], dtype=float32), discount=array([1.], dtype=float32), observation=array([[-0.03600726, -0.24478514,  0.00699184,  0.33226755]],
      dtype=float32)), array([1], dtype=int32), TimeStep(step_type=array([1], dtype=int32), reward=array([1.], dtype=float32), discount=array([1.], dtype=float32), observation=array([[-0.04090296, -0.0497634 ,  0.01363719,  0.04179767]],
      dtype=float32))]
[TimeStep(step_type=array([1], dtype=int32), reward=array([1.], dtype=float32), discount=array([1.], dtype=float32), observation=array([[-0.04090296, -0.0497634 ,  0.01363719,  0.04179767]],
      dtype=float32)), array([0], dtype=int32), TimeStep(step_type=array([1], dtype=int32), reward=array([1.], dtype=float32), discount=array([1.], dtype=float32), observation=array([[-0.04189822, -0.24507822,  0.01447314,  0.33875188]],
      dtype=float32))]
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: 138
avg_length 27.6 avg_reward: 27.6