Telif Hakkı 2021 TF-Agents Yazarları.
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 hatalarının ayıklanması 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 "gym>=0.21.0"
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:
-
observation
: Bu ajan sonraki adımda kendi eylemlerini seçme gözlemleyebilirsiniz çevre devletin bir parçasıdır. -
reward
: ajan Birden çok adımda bu ödülleri toplamını maksimize etmek öğreniyor. -
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 yaFIRST
,MID
veyaLAST
bu kez aşaması bir sırayla, birinci ara ya da son aşama olup olmadığını gösterir. -
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.0138565 , -0.03582913, 0.04861612, -0.03755046], dtype=float32), 'reward': array(0., dtype=float32), 'step_type': array(0, dtype=int32)}) TimeStep( {'discount': array(1., dtype=float32), 'observation': array([ 0.01313992, 0.15856317, 0.0478651 , -0.3145069 ], dtype=float32), 'reward': array(1., dtype=float32), 'step_type': array(1, dtype=int32)}) TimeStep( {'discount': array(1., dtype=float32), 'observation': array([ 0.01631118, 0.35297176, 0.04157497, -0.5917188 ], dtype=float32), 'reward': array(1., dtype=float32), 'step_type': array(1, dtype=int32)}) TimeStep( {'discount': array(1., dtype=float32), 'observation': array([ 0.02337062, 0.54748774, 0.02974059, -0.87102115], dtype=float32), 'reward': array(1., dtype=float32), 'step_type': array(1, dtype=int32)}) TimeStep( {'discount': array(1., dtype=float32), 'observation': array([ 0.03432037, 0.74219286, 0.01232017, -1.1542072 ], dtype=float32), 'reward': array(1., dtype=float32), 'step_type': array(1, dtype=int32)}) TimeStep( {'discount': array(1., dtype=float32), 'observation': array([ 0.04916423, 0.93715197, -0.01076398, -1.4430016 ], dtype=float32), 'reward': array(1., dtype=float32), 'step_type': array(1, dtype=int32)}) TimeStep( {'discount': array(1., dtype=float32), 'observation': array([ 0.06790727, 1.1324048 , -0.03962401, -1.7390285 ], dtype=float32), 'reward': array(1., dtype=float32), 'step_type': array(1, dtype=int32)}) TimeStep( {'discount': array(1., dtype=float32), 'observation': array([ 0.09055536, 1.327955 , -0.07440457, -2.04377 ], dtype=float32), 'reward': array(1., dtype=float32), 'step_type': array(1, dtype=int32)}) TimeStep( {'discount': array(1., dtype=float32), 'observation': array([ 0.11711447, 1.523758 , -0.11527998, -2.3585167 ], dtype=float32), 'reward': array(1., dtype=float32), 'step_type': array(1, dtype=int32)}) TimeStep( {'discount': array(1., dtype=float32), 'observation': array([ 0.14758962, 1.7197047 , -0.16245031, -2.6843033 ], dtype=float32), 'reward': array(1., dtype=float32), 'step_type': array(1, dtype=int32)}) TimeStep( {'discount': array(0., dtype=float32), 'observation': array([ 0.18198372, 1.9156038 , -0.21613638, -3.0218334 ], 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çevelemeleri gerekir. Ş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:
- Oyun, 1...10 numaralı sonsuz bir iskambil destesi kullanılarak oynanır.
- Temsilci her fırsatta 2 şey yapabilir: yeni bir rastgele kart almak veya mevcut turu durdurmak.
- Amaç, turun sonunda kartların toplamını aşmadan 21'e mümkün olduğunca yaklaştırmaktır.
Oyunu temsil eden bir ortam şöyle görünebilir:
- Eylemler: 2 eylemimiz var. Eylem 0: yeni bir kart alın ve Eylem 1: mevcut turu sonlandırın.
- Gözlemler: Mevcut turdaki kartların toplamı.
- Ö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([9], dtype=int32), 'reward': array(0., dtype=float32), 'step_type': array(1, dtype=int32)}) TimeStep( {'discount': array(1., dtype=float32), 'observation': array([12], 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:
-
ActionDiscretizeWrapper
: dönüştürür ayrı bir işlem alanı için sürekli bir hareket alanı. -
RunStats
: Yakalar böyle atılan adımlar sayısı gibi çevre istatistiklerini çalıştırın bölüm sayısı tamamladı vb -
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 alanı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-v1')
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.0078796 , -0.04736348, -0.04966116, 0.04563603]], 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.00882687, -0.24173944, -0.04874843, 0.32224613]], dtype=float32), 'reward': array([1.], dtype=float32), 'step_type': array([1], dtype=int32)})] [TimeStep( {'discount': array([1.], dtype=float32), 'observation': array([[-0.00882687, -0.24173944, -0.04874843, 0.32224613]], 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.01366166, -0.04595843, -0.04230351, 0.01459712]], dtype=float32), 'reward': array([1.], dtype=float32), 'step_type': array([1], dtype=int32)})] [TimeStep( {'discount': array([1.], dtype=float32), 'observation': array([[-0.01366166, -0.04595843, -0.04230351, 0.01459712]], 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.01458083, -0.24044897, -0.04201157, 0.2936384 ]], 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: 131 avg_length 26.2 avg_reward: 26.2