Continuação do artigo anterior: Análise do código-fonte do ambiente FrozenLake (cena) no OpenAI Gym (5)
O artigo anterior depurou a terceira etapa chave por meio do pdb:
- env.action_space.sample()
Este artigo analisa a terceira etapa principal:
-
env.step(ação)
Para facilitar a visualização e a depuração, saia da depuração anterior e execute novamente o seguinte comando para iniciar uma nova depuração:
python -m pdb frozen_lake2.py
Os comandos e resultados são os seguintes:
$ python -m pdb frozen_lake2.py
> /home/penghao/OpenAI-Gym/sample_code/frozen_lake2.py(1)<module>()
-> import numpy as np
(Pdb)
env.action_space.sample() está na linha 73 de frozen_lake2.py, portanto defina o ponto de interrupção na linha 73 do arquivo. Os comandos e resultados são os seguintes:
$ python -m pdb frozen_lake2.py
> /home/penghao/OpenAI-Gym/sample_code/frozen_lake2.py(1)<module>()
-> import numpy as np
(Pdb) b 73
Breakpoint 1 at /home/penghao/OpenAI-Gym/sample_code/frozen_lake2.py:73
(Pdb)
Em seguida, insira c para fazer com que o programa continue em execução (execute até este ponto de interrupção). Do seguinte modo:
(Pdb) c
The observation space: Discrete(16)
16
The action space: Discrete(4)
4
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
> /home/penghao/OpenAI-Gym/sample_code/frozen_lake2.py(73)<module>()
-> new_state, reward, done, truncated, info = env.step(action) # 这个也是,刚开始报错,来后我查了新的库这个函数输出五个数,网上说最后那个加‘_’就行(Pdb)
Pode-se ver que o programa parou no ponto de interrupção. Digite s, ajuste a execução, que é comumente chamada de Step In, ou seja, insira a função ou método. Do seguinte modo:
-> new_state, reward, done, truncated, info = env.step(action) # 这个也是,刚开始报错,来后我查了新的库这个函数输出五个数,网上说最后那个加‘_’就行(Pdb) s
--Call--
> /home/penghao/.local/lib/python3.11/site-packages/gym/wrappers/time_limit.py(39)step()
-> def step(self, action):
(Pdb)
Como você pode ver, o programa entrou na função de etapa. O mais importante é que indica a localização da função step, que está no arquivo gym/wrappers/time_limit.py. O código do método step é o seguinte:
def step(self, action):
"""Steps through the environment and if the number of steps elapsed exceeds ``max_episode_steps`` then truncate.
Args:
action: The environment step action
Returns:
The environment step ``(observation, reward, terminated, truncated, info)`` with `truncated=True`
if the number of steps elapsed >= max episode steps
"""
observation, reward, terminated, truncated, info = self.env.step(action)
self._elapsed_steps += 1
if self._elapsed_steps >= self._max_episode_steps:
truncated = True
return observation, reward, terminated, truncated, info
Esta função é um método na classe TimeLimit(gym.Wrapper). Continue acompanhando a depuração:
--Call--
> /home/penghao/.local/lib/python3.11/site-packages/gym/wrappers/time_limit.py(39)step()
-> def step(self, action):
(Pdb) s
> /home/penghao/.local/lib/python3.11/site-packages/gym/wrappers/time_limit.py(50)step()
-> observation, reward, terminated, truncated, info = self.env.step(action)
(Pdb) s
--Call--
> /home/penghao/.local/lib/python3.11/site-packages/gym/wrappers/order_enforcing.py(33)step()
-> def step(self, action):
(Pdb)
Este método de etapa está localizado no arquivo gym/wrappers/order_enforcing.py. O código do método step é o seguinte:
def step(self, action):
"""Steps through the environment with `kwargs`."""
if not self._has_reset:
raise ResetNeeded("Cannot call env.step() before calling env.reset()")
return self.env.step(action)
Continue acompanhando a depuração:
--Call--
> /home/penghao/.local/lib/python3.11/site-packages/gym/wrappers/order_enforcing.py(33)step()
-> def step(self, action):
(Pdb) s
> /home/penghao/.local/lib/python3.11/site-packages/gym/wrappers/order_enforcing.py(35)step()
-> if not self._has_reset:
(Pdb) s
> /home/penghao/.local/lib/python3.11/site-packages/gym/wrappers/order_enforcing.py(37)step()
-> return self.env.step(action)
(Pdb) s
--Call--
> /home/penghao/.local/lib/python3.11/site-packages/gym/wrappers/env_checker.py(33)step()
-> def step(self, action: ActType):
(Pdb)
Desta vez, cheguei ao
método step da classe PassiveEnvChecker(gym.Wrapper) em gym/wrappers/env_checker.py. código mostra como abaixo:
def step(self, action: ActType):
"""Steps through the environment that on the first call will run the `passive_env_step_check`."""
if self.checked_step is False:
self.checked_step = True
return env_step_passive_checker(self.env, action)
else:
return self.env.step(action)
Seguir:
--Call--
> /home/penghao/.local/lib/python3.11/site-packages/gym/wrappers/env_checker.py(33)step()
-> def step(self, action: ActType):
(Pdb) s
> /home/penghao/.local/lib/python3.11/site-packages/gym/wrappers/env_checker.py(35)step()
-> if self.checked_step is False:
(Pdb) s
> /home/penghao/.local/lib/python3.11/site-packages/gym/wrappers/env_checker.py(36)step()
-> self.checked_step = True
(Pdb) s
> /home/penghao/.local/lib/python3.11/site-packages/gym/wrappers/env_checker.py(37)step()
-> return env_step_passive_checker(self.env, action)
(Pdb) s
--Call--
> /home/penghao/.local/lib/python3.11/site-packages/gym/utils/passive_env_checker.py(211)env_step_passive_checker()
-> def env_step_passive_checker(env, action):
O método env_step_passive_checker está localizado no arquivo gym/utils/passive_env_checker.py. código mostra como abaixo:
def env_step_passive_checker(env, action):
"""A passive check for the environment step, investigating the returning data then returning the data unchanged."""
# We don't check the action as for some environments then out-of-bounds values can be given
result = env.step(action)
assert isinstance(
result, tuple
), f"Expects step result to be a tuple, actual type: {type(result)}"
if len(result) == 4:
logger.deprecation(
"Core environment is written in old step API which returns one bool instead of two. "
"It is recommended to rewrite the environment with new step API. "
)
obs, reward, done, info = result
if not isinstance(done, (bool, np.bool8)):
logger.warn(
f"Expects `done` signal to be a boolean, actual type: {type(done)}"
)
elif len(result) == 5:
obs, reward, terminated, truncated, info = result
# np.bool is actual python bool not np boolean type, therefore bool_ or bool8
if not isinstance(terminated, (bool, np.bool8)):
logger.warn(
f"Expects `terminated` signal to be a boolean, actual type: {type(terminated)}"
)
if not isinstance(truncated, (bool, np.bool8)):
logger.warn(
f"Expects `truncated` signal to be a boolean, actual type: {type(truncated)}"
)
else:
raise error.Error(
f"Expected `Env.step` to return a four or five element tuple, actual number of elements returned: {len(result)}."
)
check_obs(obs, env.observation_space, "step")
if not (
np.issubdtype(type(reward), np.integer)
or np.issubdtype(type(reward), np.floating)
):
logger.warn(
f"The reward returned by `step()` must be a float, int, np.integer or np.floating, actual type: {type(reward)}"
)
else:
if np.isnan(reward):
logger.warn("The reward is a NaN value.")
if np.isinf(reward):
logger.warn("The reward is an inf value.")
assert isinstance(
info, dict
), f"The `info` returned by `step()` must be a python dictionary, actual type: {type(info)}"
return result
Continue acompanhando a depuração:
--Call--
> /home/penghao/.local/lib/python3.11/site-packages/gym/utils/passive_env_checker.py(211)env_step_passive_checker()
-> def env_step_passive_checker(env, action):
(Pdb) s
> /home/penghao/.local/lib/python3.11/site-packages/gym/utils/passive_env_checker.py(214)env_step_passive_checker()
-> result = env.step(action)
(Pdb) s
--Call--
> /home/penghao/.local/lib/python3.11/site-packages/gym/envs/toy_text/frozen_lake.py(244)step()
-> def step(self, a):
(Pdb)
Finalmente chegou ao arquivo gym/envs/toy_text/frozen_lake.py, conforme analisado no artigo anterior. O código da função step em frozen_lake.py é o seguinte:
def step(self, a):
transitions = self.P[self.s][a]
i = categorical_sample([t[0] for t in transitions], self.np_random)
p, s, r, t = transitions[i]
self.s = s
self.lastaction = a
if self.render_mode == "human":
self.render()
return (int(s), r, t, False, {"prob": p})
Para a análise específica da função degrau, consulte o próximo capítulo.