Refactor CLI/interface: init command, factory field, remove extras_size
- Rename `retro-gamer create` to `retro-gamer init` with positional args (GAME OUTPUT) instead of --game/--output flags - Add [tool.retro-gamer].factory = "module:attr" to declare the game factory function from pyproject.toml instead of relying on a hard-coded create_game attribute - Remove extras_size from user-facing config; it is now measured automatically from a sample observation and never declared - Update docs throughout: create→init, runs/→training/, add factory field documentation, clarify [model] vs [training] hyperparameter sections, remove stale version-history explanations - Bump version to 0.3.0; require retro-games>=2.5.0
This commit is contained in:
@@ -21,32 +21,29 @@ You will need:
|
||||
Preparing your game
|
||||
-------------------
|
||||
|
||||
``retro-gamer`` loads your game by calling a function named
|
||||
``create_game``. The function must take no arguments and return a new
|
||||
``Game`` instance.
|
||||
``retro-gamer`` loads your game by calling a *factory function* — a
|
||||
function that takes no arguments and returns a new ``Game`` instance.
|
||||
You declare this function in ``[tool.retro-gamer]``:
|
||||
|
||||
Here is the ``create_game`` function for Snake:
|
||||
.. code-block:: toml
|
||||
|
||||
[tool.retro-gamer]
|
||||
factory = "snake:create_game"
|
||||
|
||||
The factory function itself lives in your game's Python module:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def create_game():
|
||||
head = SnakeHead()
|
||||
apple = Apple()
|
||||
game = Game([head, apple], {'score': 100}, board_size=(32, 16), framerate=12)
|
||||
game = Game([head, apple], {'score': 0}, board_size=(32, 16), framerate=12)
|
||||
apple.relocate(game)
|
||||
return game
|
||||
|
||||
If your game file does not already have a ``create_game`` function, add
|
||||
one following this pattern.
|
||||
|
||||
When you run ``retro-gamer create``, you can point to your game file
|
||||
directly by path or by Python module name:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% retro-gamer create --game my_game.py --output runs/my_game/
|
||||
% retro-gamer create --game retro.examples.snake --output runs/snake/
|
||||
|
||||
The ``"snake:create_game"`` string follows the ``"module:attr"`` format
|
||||
used throughout Python's packaging ecosystem: ``snake`` is the importable
|
||||
module name and ``create_game`` is the attribute within it.
|
||||
|
||||
Describing your game
|
||||
--------------------
|
||||
@@ -62,12 +59,21 @@ Here is the ``[tool.retro-gamer]`` section for the Snake example:
|
||||
.. code-block:: toml
|
||||
|
||||
[tool.retro-gamer]
|
||||
factory = "snake:create_game"
|
||||
actions = ["KEY_RIGHT", "KEY_UP", "KEY_LEFT", "KEY_DOWN"]
|
||||
reward = "score"
|
||||
character_set = ["@", "*", ">", "<", "^", "v"]
|
||||
|
||||
Let's go through each field.
|
||||
|
||||
``factory``
|
||||
~~~~~~~~~~~
|
||||
|
||||
The ``"module:attr"`` string naming the function that creates a fresh
|
||||
game instance. ``retro-gamer`` calls this function at the start of each
|
||||
training episode and whenever it needs to inspect the game (for example,
|
||||
to discover the board size).
|
||||
|
||||
``actions``
|
||||
~~~~~~~~~~~
|
||||
|
||||
@@ -129,7 +135,7 @@ The ``[tool.retro-gamer]`` section describes the game. Preprocessing
|
||||
options—such as ``spatial`` (whether to use a CNN or MLP, default:
|
||||
``false``) and ``observe_state``—live in the ``[preprocessing]`` section of
|
||||
the generated ``config.toml``. You can edit them there after running
|
||||
``retro-gamer create``. For full control over the observation (for example,
|
||||
``retro-gamer init``. For full control over the observation (for example,
|
||||
a cropped/egocentric board), write an ``observation_function`` instead — see :ref:`observation-function` in the
|
||||
reference docs for details.
|
||||
|
||||
@@ -151,7 +157,7 @@ board encoding (or uses them as the entire observation when
|
||||
``board = false``).
|
||||
|
||||
These values must be set in ``game.state`` at the start of every
|
||||
episode—typically inside ``create_game()``—and must keep the same
|
||||
episode—typically inside the factory function—and must keep the same
|
||||
type and length from episode to episode.
|
||||
|
||||
.. warning::
|
||||
@@ -171,21 +177,19 @@ Once you have written this section, create the training run directory:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% retro-gamer create \
|
||||
--game retro.examples.snake \
|
||||
--output runs/snake/
|
||||
% retro-gamer init games/snake training/snake
|
||||
|
||||
Created training run at runs/snake/config.toml
|
||||
game : retro.examples.snake
|
||||
Initialized training run at training/snake/config.toml
|
||||
game : games/snake
|
||||
board_size : 32×16
|
||||
actions : ['KEY_RIGHT', 'KEY_UP', 'KEY_LEFT', 'KEY_DOWN']
|
||||
reward : score
|
||||
characters : ['@', '*', '>', '<', '^', 'v']
|
||||
architecture: MLP
|
||||
|
||||
``retro-gamer create`` reads your game metadata directly from
|
||||
``retro-gamer init`` reads your game metadata directly from
|
||||
``pyproject.toml`` and writes it—along with all hyperparameters—to
|
||||
``runs/snake/config.toml``.
|
||||
``training/snake/config.toml``.
|
||||
|
||||
Training the agent
|
||||
------------------
|
||||
@@ -194,16 +198,16 @@ With the ``config.toml`` in place, start training:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% retro-gamer train runs/snake/
|
||||
% retro-gamer train training/snake
|
||||
100%|████████████████████| 1000/1000 [12:34<00:00, 1.32ep/s, reward=9.0, eps=0.007, loss=0.0003]
|
||||
Done. Checkpoints saved in runs/snake/checkpoints/
|
||||
Done. Checkpoints saved in training/snake/checkpoints/
|
||||
|
||||
A progress bar shows how far training has gone, along with the most
|
||||
recent episode's reward, the current exploration rate (``eps``), and
|
||||
the average prediction error (``loss``).
|
||||
|
||||
Training saves a checkpoint every 100 episodes to
|
||||
``runs/snake/checkpoints/``. You can stop training at any time with
|
||||
``training/snake/checkpoints/``. You can stop training at any time with
|
||||
Ctrl-C and resume it later—the next ``retro-gamer train`` command will
|
||||
automatically pick up from the latest checkpoint.
|
||||
|
||||
@@ -215,7 +219,7 @@ log:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% cat runs/snake/training.log
|
||||
% cat training/snake/training.log
|
||||
|
||||
The log begins with the full network architecture, followed by one line
|
||||
per checkpoint (every 100 episodes):
|
||||
@@ -264,7 +268,7 @@ checkpoint is always available immediately:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% retro-gamer play runs/snake/
|
||||
% retro-gamer play training/snake
|
||||
|
||||
This loads the most recent checkpoint and runs the agent in your
|
||||
terminal. Press Enter or Escape to quit.
|
||||
@@ -280,7 +284,7 @@ To watch an earlier stage of training, use ``--checkpoint``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% retro-gamer play runs/snake/ --checkpoint ep_0100
|
||||
% retro-gamer play training/snake --checkpoint ep_0100
|
||||
|
||||
Comparing what the agent at episode 100 does versus the agent at episode
|
||||
500 can reveal exactly what the agent has (and has not) learned. For
|
||||
@@ -298,7 +302,7 @@ command you used before:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% retro-gamer train runs/snake/
|
||||
% retro-gamer train training/snake
|
||||
|
||||
``retro-gamer`` automatically detects and resumes from the latest
|
||||
checkpoint. No extra flags are needed. If all configured episodes have
|
||||
@@ -309,7 +313,7 @@ already been completed, it prints a message and exits:
|
||||
Training already complete (1000 episodes). To keep training,
|
||||
increase training_episodes in config.toml.
|
||||
|
||||
To continue training, open ``runs/snake/config.toml``, increase the
|
||||
To continue training, open ``training/snake/config.toml``, increase the
|
||||
``training_episodes`` value, and run ``retro-gamer train`` again.
|
||||
|
||||
Watching a trained agent play
|
||||
@@ -319,15 +323,15 @@ Once training is complete, watch the final agent:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% retro-gamer play runs/snake/
|
||||
% retro-gamer play training/snake
|
||||
|
||||
By default the latest checkpoint is loaded. You can also compare the
|
||||
agent's performance at different stages of training:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% retro-gamer play runs/snake/ --checkpoint ep_0100
|
||||
% retro-gamer play runs/snake/ --checkpoint ep_0500
|
||||
% retro-gamer play training/snake --checkpoint ep_0100
|
||||
% retro-gamer play training/snake --checkpoint ep_0500
|
||||
|
||||
Press Enter or Escape to quit.
|
||||
|
||||
@@ -338,8 +342,8 @@ To review the configuration and recent training progress for a run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% retro-gamer info runs/snake/
|
||||
Game module : retro.examples.snake
|
||||
% retro-gamer info training/snake
|
||||
Game module : snake
|
||||
Metadata : {'actions': ['KEY_RIGHT', ...], 'reward': 'score', 'board_size': [32, 16], ...}
|
||||
Preprocessing : {'spatial': False, 'board': True, 'observe_state': ['apple_dx', 'apple_dy'], ...}
|
||||
Model : {'hidden_sizes': [128, 64]}
|
||||
@@ -358,8 +362,8 @@ Adjusting hyperparameters
|
||||
--------------------------
|
||||
|
||||
The training hyperparameters can be changed by editing ``config.toml``
|
||||
before training, or by passing them as options to ``retro-gamer
|
||||
create``. Common adjustments and their effects:
|
||||
before training, or by passing them as options to ``retro-gamer init``.
|
||||
Common adjustments and their effects:
|
||||
|
||||
**``training_episodes``** — How long to train. More episodes give the
|
||||
agent more time to learn, but also take longer to run. This is always
|
||||
@@ -411,7 +415,7 @@ game or the shape of the network. The saved model weights are
|
||||
incompatible with the new configuration:
|
||||
|
||||
- ``actions``, ``reward``, ``character_set``, ``board_size``,
|
||||
``observation_function``, ``extras_size`` (``[metadata]``) — These define
|
||||
``observation_function`` (``[metadata]``) — These define
|
||||
what the agent perceives and what it can do. Changing them changes the
|
||||
size of the network's input or output layers; the existing weights no
|
||||
longer fit.
|
||||
@@ -443,18 +447,18 @@ To clear out the old checkpoints and begin again:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% retro-gamer clean runs/snake/
|
||||
Will remove 5 checkpoint(s) and training log from runs/snake/:
|
||||
% retro-gamer clean training/snake
|
||||
Will remove 5 checkpoint(s) and training log from training/snake/:
|
||||
checkpoints/ep_0100.pt
|
||||
checkpoints/ep_0200.pt
|
||||
...
|
||||
training.log
|
||||
|
||||
Proceed? [y/N]: y
|
||||
Cleaned. Run 'retro-gamer train runs/snake/' to start fresh.
|
||||
Cleaned. Run 'retro-gamer train training/snake/' to start fresh.
|
||||
|
||||
The ``config.toml`` is always preserved so you do not need to run
|
||||
``retro-gamer create`` again.
|
||||
``retro-gamer init`` again.
|
||||
|
||||
Reasoning about training from the log
|
||||
--------------------------------------
|
||||
@@ -528,4 +532,3 @@ concepts underlying the training algorithm.
|
||||
episode 1000 and watch each play the same game. What has the later
|
||||
agent learned that the earlier one has not? How would you describe
|
||||
this difference to someone who does not know about neural networks?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user