diff --git a/brax/experimental/biggym/README.md b/brax/experimental/biggym/README.md
index 0dff8eec..55c775d2 100644
--- a/brax/experimental/biggym/README.md
+++ b/brax/experimental/biggym/README.md
@@ -1,12 +1,47 @@
# BIG-Gym
-BIG-Gym is a *crowd-sourcing* challenge for RL *environments* and *behaviors*, inspired by [BIG-Bench](https://github.com/google/BIG-bench). It is co-organized as part of NeurIPS 2021 [Ecology Theory for RL (EcoRL)](https://sites.google.com/view/ecorl2021/home) workshop. *Our goal is to create the "ImageNet" for continuous control, with diversity in agent morphologies, environment scenes, objects, and tasks.* We solicit submissions for two tracks: **Open-Ended Creativity Track** and **Goal-Oriented Competition Track**.
+BIG-Gym is a *crowd-sourcing* challenge for RL *environments* and *behaviors*, inspired by [BIG-Bench](https://github.com/google/BIG-bench). *Our goal is to create the "ImageNet" for continuous control, with diversity in agent morphologies, environment scenes, objects, and tasks.* We solicit submissions for two tracks: **Open-Ended Creativity Track** and **Goal-Oriented Competition Track**.
+```python
+from brax.experimental import biggym
-## Organizers
+# register all in registry/__init__.py
+biggym.register_all(verbose=True)
+
+# register a specific folder under registry/
+# `biggym.ENVS_BY_TRACKS` shows which envs are registered under each track
+env_names, component_names, task_env_names = biggym.register(registry_name)
+
+# (optional) inspect and get default configurable parameters of an environment
+env_params, _ = biggym.inspect_env(env_names[0])
+
+# create an environment
+env = biggym.create(env_names[0], env_params=env_params)
+```
-Core organizers: [Shixiang Shane Gu](https://sites.google.com/view/gugurus/home), [Hiroki Furuta](https://frt03.github.io/), [Manfred Diaz](https://manfreddiaz.github.io/)
+Challenge details (timelines, submission instructions) are [here](https://sites.google.com/view/rlbiggym).
-Supported by:
+## Citing
+
+If you use BIG-Gym in a publication, please cite referenced libraries:
+
+```
+@article{gu2021braxlines,
+ title={Braxlines: Fast and Interactive Toolkit for RL-driven Behavior Engineering beyond Reward Maximization},
+ author={Gu, Shixiang Shane and Diaz, Manfred and Freeman, Daniel C and Furuta, Hiroki and Ghasemipour, Seyed Kamyar Seyed and Raichuk, Anton and David, Byron and Frey, Erik and Coumans, Erwin and Bachem, Olivier},
+ journal={arXiv preprint arXiv:2110.04686},
+ year={2021}
+}
+@software{brax2021github,
+ author = {C. Daniel Freeman and Erik Frey and Anton Raichuk and Sertan Girgin and Igor Mordatch and Olivier Bachem},
+ title = {Brax - A Differentiable Physics Engine for Large Scale Rigid Body Simulation},
+ url = {http://github.com/google/brax},
+ version = {0.0.5},
+ year = {2021},
+}
+```
+
+## Organizers
+* [Shixiang Shane Gu](https://sites.google.com/view/gugurus/home) (Google Brain), [Hiroki Furuta](https://frt03.github.io/) (University of Tokyo), [Manfred Diaz](https://manfreddiaz.github.io/) (University of Montreal)
* [Brax](https://github.com/google/brax)/[Braxlines](https://arxiv.org/abs/2110.04686) teams
* [NeurIPS 2021 EcoRL workshop](https://sites.google.com/view/ecorl2021/home) organizers
diff --git a/brax/experimental/biggym/__init__.py b/brax/experimental/biggym/__init__.py
index 1c2b7768..898c4b62 100644
--- a/brax/experimental/biggym/__init__.py
+++ b/brax/experimental/biggym/__init__.py
@@ -14,13 +14,17 @@
"""BIG-Gym: crowd-sourced environments and behaviors."""
# pylint:disable=protected-access
+# pylint:disable=g-complex-comprehension
+import difflib
import functools
import importlib
+import inspect
from typing import Any, Union, Dict, Callable, Optional
from brax import envs as brax_envs
from brax.envs import Env
from brax.envs import wrappers
-from brax.experimental.biggym.tasks import TASKS
+from brax.experimental.biggym import registry
+from brax.experimental.biggym import tasks
from brax.experimental.braxlines.envs import obs_indices
from brax.experimental.composer import components as composer_components
from brax.experimental.composer import composer
@@ -31,10 +35,18 @@
ROOT_PATH = 'brax.experimental.biggym.registry'
ENVS = {}
+REGISTRIES = {}
+OPEN_ENDED_TRACKS = ('rl', 'mimax')
+GOAL_ORIENTED_TRACKS = sorted(tasks.TASKS)
+ENVS_BY_TRACKS = dict(
+ open_ended={k: () for k in OPEN_ENDED_TRACKS},
+ goal_oriented={k: () for k in GOAL_ORIENTED_TRACKS},
+)
def inspect_env(env_name: str):
"""Inspect env_params of an env (ComposerEnv only)."""
+ assert_exists(env_name)
if composer_envs.exists(env_name):
return composer_envs.inspect_env(env_name)
else:
@@ -45,6 +57,7 @@ def assert_env_params(env_name: str,
env_params: Dict[str, Any],
ignore_kwargs: bool = True):
"""Inspect env_params of an env (ComposerEnv only)."""
+ assert_exists(env_name)
if composer_envs.exists(env_name):
composer_envs.assert_env_params(env_name, env_params, ignore_kwargs)
else:
@@ -61,12 +74,65 @@ def exists(env_name: str):
return env_name in list_env()
-def register(registry_name: str, assert_override: bool = True):
+def assert_exists(env_name: str):
+ """Assert if an environment is registered."""
+ exists_ = exists(env_name)
+ if not exists_:
+ closest = difflib.get_close_matches(env_name, list_env(), n=3)
+ assert 0, f'{env_name} not found. Closest={closest}'
+
+
+def get_func_kwargs(func):
+ """Get keyword args of a function."""
+ # first, unwrap functools.partial. only extra keyword arguments.
+ partial_supported_params = {}
+ while isinstance(func, functools.partial):
+ partial_supported_params.update(func.keywords)
+ func = func.func
+ # secondly, inspect the original function for keyword arguments.
+ fn_params = inspect.signature(func).parameters
+ support_kwargs = any(
+ v.kind == inspect.Parameter.VAR_KEYWORD for v in fn_params.values())
+ supported_params = {
+ k: v.default
+ for k, v in fn_params.items()
+ if v.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD and
+ v.default != inspect._empty
+ }
+ supported_params.update(partial_supported_params)
+ return supported_params, support_kwargs
+
+
+def register_all(verbose: bool = False, **kwargs):
+ """Register all registries."""
+ for registry_name in registry.REGISTRIES:
+ env_names, comp_names, task_env_names = register(registry_name, **kwargs)
+ if verbose:
+ print((f'Registered {registry_name}: '
+ f'{len(env_names)} envs, '
+ f'{len(comp_names)} comps, '
+ f'{len(task_env_names)} task_envs, '))
+
+
+def register(registry_name: str,
+ assert_override: bool = True,
+ optional: bool = True):
"""Register all envs and components."""
- global ENVS
+ global ENVS, REGISTRIES, ENVS_BY_TRACKS
+
+ assert (optional or registry_name not in REGISTRIES
+ ), f'non-optional register() conflicts: {registry_name}'
+ if registry_name in REGISTRIES:
+ return REGISTRIES[registry_name]
+
lib = importlib.import_module(f'{ROOT_PATH}.{registry_name}')
envs = lib.ENVS or {}
components = lib.COMPONENTS or {}
+ envs = {registry.get_env_name(registry_name, k): v for k, v in envs.items()}
+ components = {
+ registry.get_comp_name(registry_name, k): v
+ for k, v in components.items()
+ }
task_envs = []
# register environments
@@ -86,7 +152,11 @@ def register(registry_name: str, assert_override: bool = True):
else:
# register a standard Env
ENVS[env_name] = env_module
- if 'mimax' in env_info.get('tracks', []):
+ tracks = env_info.get('tracks', ['rl'])
+ for track in tracks:
+ assert track in OPEN_ENDED_TRACKS, f'{track} not in {OPEN_ENDED_TRACKS}'
+ ENVS_BY_TRACKS['open_ended'][track] += (env_name,)
+ if 'mimax' in tracks:
# (MI-Max only) register obs_indices
for indices_type, indices in env_info.get('obs_indices', {}).items():
obs_indices.register_indices(env_name, indices_type, indices)
@@ -98,25 +168,30 @@ def register(registry_name: str, assert_override: bool = True):
comp_name
), f'{composer_components.list_components()} contains {comp_name}'
comp_module = comp_info['module']
- composer_components.register_component(
+ comp_lib = composer_components.register_component(
comp_name,
load_path=f'{ROOT_PATH}.{registry_name}.components.{comp_module}',
override=True)
+ component_params = get_func_kwargs(comp_lib.get_specs)[0]
for track in comp_info.get('tracks', []):
- assert track in TASKS, f'{track} not in {sorted(TASKS)}'
- track_env_name = f'{track}_{registry_name}_{comp_name}'
- track_env_module = TASKS[track](
- component=comp_module,
- component_params=comp_info.get('component_params', {}))
+ assert (track
+ in GOAL_ORIENTED_TRACKS), f'{track} not in {GOAL_ORIENTED_TRACKS}'
+ track_env_name = tasks.get_task_env_name(track, comp_name)
if assert_override:
assert not exists(
track_env_name), f'{list_env()} contains {track_env_name}'
+ track_env_module = functools.partial(tasks.TASKS[track], comp_name,
+ **component_params)
# register a ComposerEnv
composer_envs.register_env(
track_env_name, track_env_module, override=True)
task_envs += [track_env_name]
+ ENVS_BY_TRACKS['goal_oriented'][track] += (track_env_name,)
- return sorted(envs), sorted(components), sorted(task_envs)
+ assert envs or task_envs, 'no envs registered'
+ REGISTRIES[registry_name] = (sorted(envs), sorted(components),
+ sorted(task_envs))
+ return REGISTRIES[registry_name]
def create(env_name: str = None,
@@ -126,6 +201,7 @@ def create(env_name: str = None,
batch_size: Optional[int] = None,
**kwargs) -> Env:
"""Creates an Env with a specified brax system."""
+ assert_exists(env_name)
if env_name in ENVS:
env = ENVS[env_name](**kwargs)
if episode_length is not None:
diff --git a/brax/experimental/biggym/registry/__init__.py b/brax/experimental/biggym/registry/__init__.py
new file mode 100644
index 00000000..806e5092
--- /dev/null
+++ b/brax/experimental/biggym/registry/__init__.py
@@ -0,0 +1,29 @@
+# Copyright 2021 The Brax Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Registry of BIG-Gym environments and components."""
+
+# keep alphabetical ordering
+REGISTRIES = [
+ 'jump',
+ 'proant',
+]
+
+
+def get_comp_name(registry_name: str, comp_name: str):
+ return f'{registry_name}__{comp_name}'
+
+
+def get_env_name(registry_name: str, env_name: str):
+ return f'{registry_name}__{env_name}'
diff --git a/brax/experimental/biggym/registry/jump_cheetah/__init__.py b/brax/experimental/biggym/registry/jump/__init__.py
similarity index 91%
rename from brax/experimental/biggym/registry/jump_cheetah/__init__.py
rename to brax/experimental/biggym/registry/jump/__init__.py
index 36052ae1..a7900693 100644
--- a/brax/experimental/biggym/registry/jump_cheetah/__init__.py
+++ b/brax/experimental/biggym/registry/jump/__init__.py
@@ -15,8 +15,8 @@
"""Example: an existing Env + a new reward."""
ENVS = dict(
- jump_cheetah=dict(
- module='jump_cheetah:JumpCheetah',
+ cheetah=dict(
+ module='cheetah:JumpCheetah',
tracks=('rl',),
),)
diff --git a/brax/experimental/biggym/registry/jump_cheetah/envs/jump_cheetah.py b/brax/experimental/biggym/registry/jump/envs/cheetah.py
similarity index 100%
rename from brax/experimental/biggym/registry/jump_cheetah/envs/jump_cheetah.py
rename to brax/experimental/biggym/registry/jump/envs/cheetah.py
diff --git a/brax/experimental/biggym/registry/procedural_ant/__init__.py b/brax/experimental/biggym/registry/proant/__init__.py
similarity index 92%
rename from brax/experimental/biggym/registry/procedural_ant/__init__.py
rename to brax/experimental/biggym/registry/proant/__init__.py
index dfd2d4a2..5706507c 100644
--- a/brax/experimental/biggym/registry/procedural_ant/__init__.py
+++ b/brax/experimental/biggym/registry/proant/__init__.py
@@ -15,13 +15,13 @@
"""Example: a Component + env rewards."""
ENVS = dict(
- ant_run_bg=dict(
+ run=dict(
module='ant:Run',
tracks=('rl',),
),)
COMPONENTS = dict(
- ant_bg=dict(
+ ant=dict(
module='ant',
- tracks=('run',),
+ tracks=('race',),
),)
diff --git a/brax/experimental/biggym/registry/proant/components/ant.py b/brax/experimental/biggym/registry/proant/components/ant.py
new file mode 100644
index 00000000..93196f69
--- /dev/null
+++ b/brax/experimental/biggym/registry/proant/components/ant.py
@@ -0,0 +1,17 @@
+# Copyright 2021 The Brax Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Procedural ant."""
+# pylint:disable=unused-import
+from brax.experimental.composer.components.pro_ant import get_specs
diff --git a/brax/experimental/biggym/registry/procedural_ant/envs/ant.py b/brax/experimental/biggym/registry/proant/envs/ant.py
similarity index 90%
rename from brax/experimental/biggym/registry/procedural_ant/envs/ant.py
rename to brax/experimental/biggym/registry/proant/envs/ant.py
index 4fedda7e..22d38023 100644
--- a/brax/experimental/biggym/registry/procedural_ant/envs/ant.py
+++ b/brax/experimental/biggym/registry/proant/envs/ant.py
@@ -13,13 +13,14 @@
# limitations under the License.
"""Ant tasks."""
+from brax.experimental.biggym import registry
def Run(num_legs: int = 4):
return dict(
components=dict(
agent1=dict(
- component='ant_bg',
+ component=registry.get_comp_name('proant', 'ant'),
component_params=dict(num_legs=num_legs),
pos=(0, 0, 0),
reward_fns=dict(
diff --git a/brax/experimental/biggym/registry/procedural_ant/components/ant.py b/brax/experimental/biggym/registry/procedural_ant/components/ant.py
deleted file mode 100644
index 6b68ace2..00000000
--- a/brax/experimental/biggym/registry/procedural_ant/components/ant.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# Copyright 2021 The Brax Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Procedural ant."""
-from brax.experimental.composer.components.ant import DEFAULT_OBSERVERS
-from brax.experimental.composer.components.ant import ROOT
-from brax.experimental.composer.components.ant import term_fn
-import numpy as np
-
-
-def generate_ant_config_with_n_legs(n):
- """Generate info for n-legged ant."""
-
- def template_leg(theta, ind):
- tmp = f"""
- bodies {{
- name: "Aux 1_{str(ind)}"
- colliders {{
- rotation {{ x: 90 y: -90 }}
- capsule {{
- radius: 0.08
- length: 0.4428427219390869
- }}
- }}
- inertia {{ x: 1.0 y: 1.0 z: 1.0 }}
- mass: 1
- }}
- bodies {{
- name: "$ Body 4_{str(ind)}"
- colliders {{
- rotation {{ x: 90 y: -90 }}
- capsule {{
- radius: 0.08
- length: 0.7256854176521301
- end: -1
- }}
- }}
- inertia {{ x: 1.0 y: 1.0 z: 1.0 }}
- mass: 1
- }}
- joints {{
- name: "{ROOT}_Aux 1_{str(ind)}"
- parent_offset {{ x: {((0.4428427219390869/2.)+.08)*np.cos(theta)} y: {((0.4428427219390869/2.)+.08)*np.sin(theta)} }}
- child_offset {{ }}
- parent: "{ROOT}"
- child: "Aux 1_{str(ind)}"
- stiffness: 5000.0
- angular_damping: 35
- angle_limit {{ min: -30.0 max: 30.0 }}
- rotation {{ y: -90 }}
- reference_rotation {{ z: {theta*180/np.pi} }}
- }}
- joints {{
- name: "Aux 1_$ Body 4_{str(ind)}"
- parent_offset {{ x: {0.4428427219390869/2. - .08} }}
- child_offset {{ x:{-0.7256854176521301/2. + .08} }}
- parent: "Aux 1_{str(ind)}"
- child: "$ Body 4_{str(ind)}"
- stiffness: 5000.0
- angular_damping: 35
- rotation: {{ z: 90 }}
- angle_limit {{
- min: 30.0
- max: 70.0
- }}
- }}
- actuators {{
- name: "{ROOT}_Aux 1_{str(ind)}"
- joint: "{ROOT}_Aux 1_{str(ind)}"
- strength: 350.0
- torque {{}}
- }}
- actuators {{
- name: "Aux 1_$ Body 4_{str(ind)}"
- joint: "Aux 1_$ Body 4_{str(ind)}"
- strength: 350.0
- torque {{}}
- }}
- """
- collides = (f'Aux 1_{str(ind)}', f'$ Body 4_{str(ind)}')
- return tmp, collides
-
- base_config = f"""
- bodies {{
- name: "{ROOT}"
- colliders {{
- capsule {{
- radius: 0.25
- length: 0.5
- end: 1
- }}
- }}
- inertia {{ x: 1.0 y: 1.0 z: 1.0 }}
- mass: 10
- }}
- """
- collides = (ROOT,)
- for i in range(n):
- config_i, collides_i = template_leg((1. * i / n) * 2 * np.pi, i)
- base_config += config_i
- collides += collides_i
-
- return base_config, collides
-
-
-def get_specs(num_legs: int = 10):
- message_str, collides = generate_ant_config_with_n_legs(num_legs)
- return dict(
- message_str=message_str,
- collides=collides,
- root=ROOT,
- term_fn=term_fn,
- observers=DEFAULT_OBSERVERS)
diff --git a/brax/experimental/biggym/tasks.py b/brax/experimental/biggym/tasks.py
index e598c612..f9fb84ee 100644
--- a/brax/experimental/biggym/tasks.py
+++ b/brax/experimental/biggym/tasks.py
@@ -13,10 +13,13 @@
# limitations under the License.
"""BIG-Gym tasks."""
-from typing import Dict, Any
-def Run(component: str, component_params: Dict[str, Any]):
+def get_task_env_name(task_name: str, env_name: str):
+ return f'{task_name}__{env_name}'
+
+
+def race(component: str, **component_params):
return dict(
components=dict(
agent1=dict(
@@ -35,4 +38,4 @@ def Run(component: str, component_params: Dict[str, Any]):
)
-TASKS = dict(run=Run,)
+TASKS = dict(race=race,)
diff --git a/brax/experimental/composer/envs/__init__.py b/brax/experimental/composer/envs/__init__.py
index 8b205ccf..91fff7cc 100644
--- a/brax/experimental/composer/envs/__init__.py
+++ b/brax/experimental/composer/envs/__init__.py
@@ -20,7 +20,10 @@
composer.py loads from `ENV_DESCS` with `env_name`,
where each entry can be a `env_desc` or a function that returns `env_desc`.
"""
+# pylint:disable=protected-access
+# pylint:disable=g-complex-comprehension
import copy
+import functools
import importlib
import inspect
from typing import Any, Dict
@@ -69,6 +72,27 @@ def exists(env_name: str):
return env_name in ENV_DESCS
+def get_func_kwargs(func):
+ """Get keyword args of a function."""
+ # first, unwrap functools.partial. only extra keyword arguments.
+ partial_supported_params = {}
+ while isinstance(func, functools.partial):
+ partial_supported_params.update(func.keywords)
+ func = func.func
+ # secondly, inspect the original function for keyword arguments.
+ fn_params = inspect.signature(func).parameters
+ support_kwargs = any(
+ v.kind == inspect.Parameter.VAR_KEYWORD for v in fn_params.values())
+ supported_params = {
+ k: v.default
+ for k, v in fn_params.items()
+ if v.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD and
+ v.default != inspect._empty
+ }
+ supported_params.update(partial_supported_params)
+ return supported_params, support_kwargs
+
+
def inspect_env(env_name: str):
"""Inspect parameters of the env."""
desc = env_name
@@ -77,11 +101,7 @@ def inspect_env(env_name: str):
assert callable(desc) or isinstance(desc, dict), desc
if not callable(desc):
return {}, False
- fn_params = inspect.signature(desc).parameters
- supported_params = {k: v.default for k, v in fn_params.items()}
- support_kwargs = 'kwargs' in supported_params
- supported_params.pop('kwargs', None)
- return supported_params, support_kwargs
+ return get_func_kwargs(desc)
def assert_env_params(env_name: str,
diff --git a/js/system.js b/js/system.js
index 589b263b..5a855a9b 100644
--- a/js/system.js
+++ b/js/system.js
@@ -132,6 +132,7 @@ function addHat(child, collider) {
const beanie = new THREE.Mesh(new THREE.LatheGeometry(points), new THREE.MeshPhongMaterial({
color: 0xff0000
}));
+ beanie.baseMaterial = beanie.material;
hat.add(beanie);
const whiteMaterial = new THREE.MeshPhongMaterial({
@@ -140,11 +141,13 @@ function addHat(child, collider) {
const pompom = new THREE.Mesh(new THREE.SphereGeometry(thickness, 8, 8), whiteMaterial);
pompom.position.set(0, points[points.length - 1].y, 0);
+ pompom.baseMaterial = pompom.material;
hat.add(pompom);
const side = new THREE.Mesh(new THREE.TorusGeometry(hatRadius, thickness, 8, 25), whiteMaterial);
side.rotateX(Math.PI / 2);
side.position.set(0, (hatRadius + thickness) / 2, 0);
+ side.baseMaterial = side.material;
hat.add(side);
// Tilt the hat slightly.
hat.rotateZ(0.3);
diff --git a/js/viewer.js b/js/viewer.js
index ad777383..4ad91c7f 100644
--- a/js/viewer.js
+++ b/js/viewer.js
@@ -271,10 +271,12 @@ class Viewer {
}
});
}
- const titleElement =
- this.bodyFolders[object.name].domElement.querySelector('.title');
- if (titleElement) {
- titleElement.style.backgroundColor = hovering ? '#2fa1d6' : '#000';
+ if (object.name in this.bodyFolders) {
+ const titleElement =
+ this.bodyFolders[object.name].domElement.querySelector('.title');
+ if (titleElement) {
+ titleElement.style.backgroundColor = hovering ? '#2fa1d6' : '#000';
+ }
}
}
@@ -286,10 +288,12 @@ class Viewer {
child.material = selected ? selectMaterial : child.baseMaterial;
}
});
- if (object.selected) {
- this.bodyFolders[object.name].open();
- } else {
- this.bodyFolders[object.name].close();
+ if (object.name in this.bodyFolders) {
+ if (object.selected) {
+ this.bodyFolders[object.name].open();
+ } else {
+ this.bodyFolders[object.name].close();
+ }
}
this.setDirty();
}
diff --git a/notebooks/training.ipynb b/notebooks/training.ipynb
index 1e86fa1b..a82cf917 100644
--- a/notebooks/training.ipynb
+++ b/notebooks/training.ipynb
@@ -15,7 +15,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 1,
"metadata": {
"id": "_sOmCoOrF0F8"
},
@@ -23,7 +23,7 @@
"source": [
"#@title Install Brax and some helper modules\n",
"#@markdown ## ⚠️ PLEASE NOTE:\n",
- "#@markdown This colab runs best using a TPU runtime. From the Colab menu, choose Runtime \u003e Change Runtime Type, then select **'TPU'** in the dropdown.\n",
+ "#@markdown This colab runs best using a TPU runtime. From the Colab menu, choose Runtime > Change Runtime Type, then select **'TPU'** in the dropdown.\n",
"\n",
"from datetime import datetime\n",
"import functools\n",
@@ -64,60 +64,55 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 2,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 480
},
"id": "NaJDZqhCLovU",
- "outputId": "847e65fe-a80a-46e5-922a-fd0ac4b64356"
+ "outputId": "e98ab22a-6788-4db3-f2c9-1782bd1300b0"
},
"outputs": [
{
+ "output_type": "execute_result",
"data": {
"text/html": [
"\n",
- "\u003chtml\u003e\n",
- "\n",
- " \u003chead\u003e\n",
- " \u003ctitle\u003ebrax visualizer\u003c/title\u003e\n",
- " \u003cstyle\u003e\n",
+ "\n",
+ "
\n",
+ " brax visualizer\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ "\n"
],
"text/plain": [
- "\u003cIPython.core.display.HTML object\u003e"
+ ""
]
},
- "execution_count": 2,
"metadata": {},
- "output_type": "execute_result"
+ "execution_count": 2
}
],
"source": [
@@ -153,34 +148,34 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 3,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
- "height": 317
+ "height": 318
},
"id": "4vgMSWODfyMC",
- "outputId": "a25126f4-64c4-4347-c983-c68f2f9838dd"
+ "outputId": "4570dd15-5b35-4459-d152-555393c0a559"
},
"outputs": [
{
+ "output_type": "display_data",
"data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZMAAAEKCAYAAADXdbjqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nO3deXxV9Z3/8dcnJJBAyAKEnbALIiJLBKxWtO7LiB2t4lKX0dKxdnH6a6d2fm3tdJvOTH9t1XEpjlp3sS6VVqcWQdSxsoRNNpUIAgmBJEACgez5/P44JxiRkBuSm5ubvJ+Px33cc879nnM/Jze5n5zv93u+X3N3REREWiMh1gGIiEj8UzIREZFWUzIREZFWUzIREZFWUzIREZFWUzIREZFWi2oyMbMMM3vezN43s01mdpqZ9TGzhWa2OXzODMuamd1jZnlm9p6ZTW10nBvD8pvN7MZoxiwiIi0X7SuTu4G/uPt44BRgE3AnsMjdxwKLwnWAi4Cx4WMu8ACAmfUB7gJmANOBuxoSkIiIdAxRSyZmlg6cCTwM4O7V7l4KzAYeC4s9BlweLs8GHvfAUiDDzAYBFwAL3X2vu+8DFgIXRituERFpucQoHnskUAw8amanACuBbwED3L0wLLMLGBAuDwF2NNo/P9zW1PZPMbO5BFc09OrVa9r48ePb7kxERLqAlStXlrh71vHsG81kkghMBb7h7svM7G4+qdICwN3dzNpkPBd3nwfMA8jJyfHc3Ny2OKyISJdhZtuOd99otpnkA/nuvixcf54guewOq68In4vC1wuAYY32Hxpua2q7iIh0EFFLJu6+C9hhZuPCTecAG4EFQEOPrBuBl8PlBcANYa+umUBZWB32GnC+mWWGDe/nh9tERKSDiGY1F8A3gKfMrDuwBbiZIIE9Z2a3ANuAq8KyrwIXA3nAobAs7r7XzH4KrAjL/cTd90Y5bhERaQHrjEPQq81ERKTlzGylu+ccz766A15ERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpNyURERFpN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\n",
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZMAAAEKCAYAAADXdbjqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nO3deXwV9dXH8c8JZCEhEMIu+yaIKIsRVHzcF7RWVFzrQtWKba1Wu7i0tW5tH+2m1aotruBjq4gb7kVwqwuy7yBhkz1ASAiE7Of5YwaNSMiF5ObmJt/363Vfd+Z3Z+ae4YZ77vxm5vzM3REREamJhFgHICIi8U/JREREakzJREREakzJREREakzJREREakzJREREaiyqycTMMsxsopktMbPFZna0mWWa2WQzWxY+twqXNTN70MyyzWyemQ2ptJ3R4fLLzGx0NGMWEZH9F+0jk78Bb7t7P2AgsBi4FZji7n2AKeE8wBlAn/AxBngUwMwygTuAYcBQ4I7dCUhEROqHqCUTM2sJHAc8AeDuJe6eB4wExoWLjQPOCadHAuM98BmQYWYdgdOBye6e6+7bgMnAiGjFLSIi+69pFLfdA9gMPGVmA4GZwE+B9u6+IVxmI9A+nO4ErKm0/tqwrar2bzCzMQRHNKSlpR3Rr1+/2tsTEZFGYObMmVvcve2BrBvNZNIUGAJc7+7TzOxvfN2lBYC7u5nVSj0Xdx8LjAXIysryGTNm1MZmRUQaDTNbfaDrRvOcyVpgrbtPC+cnEiSXTWH3FeFzTvj6OqBLpfU7h21VtYuISD0RtSMTd99oZmvMrK+7LwVOBhaFj9HAveHzq+Eqk4CfmNlzBCfb8919g5m9A/yh0kn304DbohW3iEg0uDvPT1/DQ1OzSWxiZKYl0bp5Mq3TkmjdPInMtGTaNE8K2tOSw7YkEpvExx0c0ezmArgeeNbMkoAVwJUER0MTzOxqYDVwYbjsm8CZQDZQGC6Lu+ea2T3A9HC5u909N8pxi4jUmk3bi7j1xXm8t3QzR3RrRaeMZmzdWcya3ELmrMkjd2cJ5RV77/FvkdKUNs2Tw+QTJJ3WaUlkpCaSmZZEq9QkWqUl0So1kVZpSaQnN8XM6ngPwRpiCXqdMxGR+sDdmTR3Pb99dSHFZeXcOqIfVxzdnYSEb37ZV1Q424tK2bKjhNydJWzdUczWnSVs3VFC7s5ituwsIXdHCVt3FrN1RwnbCkuoIvfQNMHISP06ubQKk05GahKZqV8noazumbRslviNdc1sprtnHci+RvvIRESkUdq6o5jbX13Am/M3MrhrBn+5YCA92zbf67IJYQLISE2KaNsVFU5BURm5hUFi2bazhG2FpeHz7rZScgtLWLllJzNX55FXWEJZpQz0+vXH0rJTy1rZV1AyERGpdZMXbeK2l+aRv6uUm0f0Zcz/9KRpLZ77SEgwWqYm0jI1kR6kRbSOu7OjuIxtO0vZVlhCryoS24FSMhERqSXbi0q5a9IiXpy1lkM6tuCZq4dxSMcWsQ4LADMjPSWR9JREurZOrfXtK5mIiNSC/y7bws0T57KpoJjrT+rN9Sf1IalpfFyJVRuUTEREaqCwpIx731rC+E9X06ttGi/+6BgGdcmIdVh1TslEROQAzViVy89fmMvqrYVcNbwHN4/oS0pik1iHFRNKJiIi+6motJz73/2CsR+uoFNGM/59zVEc3at1rMOKKSUTEZH9sGBdPj+bMIcvNu3gkqFd+PV3+tM8WV+l+hcQEYlATkERj3+0kif/u5LMtCSeuvJITuzbLtZh1RtKJiIi+7Amt5B/fricCTPWUlZewbmDO3P7WYdEfINhY6FkIiKyF8s2FfDo+8t5de56EgxGDenMtcf3okebyG4SbGyUTEREKpm7Jo9H3s/mnYWbaJbYhNFHd+ea43rQsWWzWIdWrymZiEij5+58umIrj7y3nP9mb6FFSlNuOKk33x/eg8w0dWdFQslEROJGeYXTJKH2yqu7O1MW5/Dw+9nM/jKPNs2TufWMflw6rCvpKYnVb0C+omQiIvVaaXkFr89bz9gPV7J043Y6tmxGl8xmdGmVStfMVLpkpgbzmam0bZ4c0VgeZeUVvDF/A4++v5wlGwvo3KoZ95wzgAuO6NxobzqsKSUTEamXdhSX8dznX/Lkf1eyPr+IPu2aM+a4XmzaXsSXuYV88MVmcgqKv7FOSmICXVqFCaZVszDRfJ10EpsYL81axz8+WM7qrYX0btecv144kO8OPChuRjSsr5RMRKRe2bS9iKc+XsWz01ZTUFTGsB6Z/O7cAZxwcLtvDSpVVFrO2m2FrMndxZe5hazJLWTNtkK+zN3F9JW5FBSXfWP5pKYJlJRVMLBzS351+RGcekj7b21TDoySiYjUC8s2FTD2wxW8Mmcd5RXOGQM6Mua4ngzcR9HElMQm9G6XTu926d96zd3JKyxlTaVkk1NQxMn92jO8d+uYDG3bkCmZiEjMuDvTVuYy9sMVTF2SQ0piApcM7crVx/agW+ua3c9hZsGwtWlJHN658VXxrWtKJiJS58ornLcXbGTsh8uZuzafzLQkbjrlYC4/upsuxY1TSiYiUmd2lZTzwsw1PP7RSr7MLaR761R+d84AztdVVHFPyUREaoW7U1RaQf6uUvJ3lZJXWBI87ypl+65SNuQX8dKstWwrLGVw1wx+dWY/Tu3foVbvG5HYUTIRkWptLyrl1dnryN1ZSt6uIEnkF5Z+nTjC55Kyiiq30STBOLFvO649vidZ3VrpBHgDo2QiItX6xYS5/GfRJgCaJzelZbPErx692zUPplO/bstolhQ8h20tmiWSntxUl+E2YEomIrJPM1fn8p9Fm/jpyX34yUm9dXOf7JX+KkSkSu7OvW8toU3zZK49vqcSiVRJfxkiUqUpi3OYvmobN57Sh9QkdWRI1aKaTMxslZnNN7M5ZjYjbMs0s8lmtix8bhW2m5k9aGbZZjbPzIZU2s7ocPllZjY6mjGLSKC8wrnv7SX0aJPGRUd2iXU4Us/VxZHJie4+yN2zwvlbgSnu3geYEs4DnAH0CR9jgEchSD7AHcAwYChwx+4EJCLR8+KstSzL2cEvT++r7i2pViz+QkYC48LpccA5ldrHe+AzIMPMOgKnA5PdPdfdtwGTgRF1HbRIY1JUWs79k79gYJcMzhjQIdbhSByIdjJx4D9mNtPMxoRt7d19Qzi9EWgfTncC1lRad23YVlW7iETJuE9WsSG/iFtH9NP9IBKRaJ9RO9bd15lZO2CymS2p/KK7u5l5bbxRmKzGAHTt2rU2NinSKOUXlvLwe9mc0LctR/dqHetwJE5E9cjE3deFzznAywTnPDaF3VeEzznh4uuAymf5OodtVbXv+V5j3T3L3bPatm1b27si0mg88kE2BcVl3Hx6v1iHInEkasnEzNLMLH33NHAasACYBOy+Ims08Go4PQm4Iryq6yggP+wOewc4zcxahSfeTwvbRKSWrc/bxVMfr+LcQZ3of1CLWIcjcSSa3VztgZfD/tamwL/c/W0zmw5MMLOrgdXAheHybwJnAtlAIXAlgLvnmtk9wPRwubvdPTeKcYs0Wg+8+wU43HTqwbEOReJM1JKJu68ABu6lfStw8l7aHbiuim09CTxZ2zGKyNe+2FTAxJlruXJ4D7pkpsY6HIkzunhcRAD449tLSUtqynUn9o51KBKHlExEhOmrcnl38SZ+eEIvjXQoB0TJRKSR213MsV16MlcN7xHrcCROKZmINHKTF21i5upt3HTqwTRL0tC5cmCUTEQasbLyCv74zlJ6tk3jgiM6xzociWNKJiKN2Iuz1pKds4ObT+9HUxVzlBrQX49IIxUUc1zG4K4ZnH5o++pXENkHJRORRurpT1axcbuKOUrtUDIRaYTyCkt45L1sTu7XjmE9VcxRak7JRKQRevT95UExxxEq5ii1Q8lEpJFZn7eLpz5ZxaghnenbIT3W4UgDoWQi0sjcP/kLQMUcpXYpmYg0Iks3FvDirLV8/5judMpoFutwpAFRMhFpRP70zhLSkpvy4xN6xToUaWCUTESibEdxGevydhGMshA7n6/M5d3FOfz4hN5kpKqYo9SuaI8BL9KorcktZOTDH5O7s4T0lKb0bZ9O3w7p9OuQTt8OLejbIZ2WzRKjHkdQzHExHVqkcOXw7lF/P2l8lExEoqSwpIxrxs+grLyC28/qz8otO1i6sYBJc9fz7LSyr5br2DKFvh0qJZn2LejVLo3kprVXdPE/izYx68s87ht1GCmJKuYotU/JRCQK3J1fvjCPLzYV8NSVQzn+4LbfeG1DfhFLNxawZGMBSzduZ8nGAj7O3kJpedAV1iTB6Nkm7asE07V1GuUVFRSVVlBUWk5xWfBcVFpBcVn4XLm9rJzi0gqKwtc25hfRu11zRg1RMUeJDiUTkSh45P3lvDF/A7ee0e8biQTAzDgooxkHZTTjxH7tvmovLa9g5ZadXyWYpRsLmLMmj9fnbajyfZKaJJCcmEBy0yakJCaQktiE5KbBc0piAi2aJZKSmMDhnVvyg2N7qpijRI2SiUgte29JDn/+z1LOHngQ1x7XM+L1EpskcHD7dA5unw4DD/qqvaColA35RSQ1+WaySGqaQJME1dSS+kHJRKQWrdi8gxuem80hHVpw36jDa6WAYnpKIukp0T9JL1IT1R7zmll7M3vCzN4K5/ub2dXRD00kvhQUlXLN+BkkNklg7BVHaNRCaVQi6UB9GngH2H3c/QVwY7QCEolHFRXOTc/PYdXWQh7+3hA6t0qNdUgidSqSZNLG3ScAFQDuXgaURzUqkTjzwLtf8O7iHH57Vn+O7qWS7tL4RJJMdppZa8ABzOwoID+qUYnEkbcXbODBqdlcmNWZK47uFutwRGIikhPwPwMmAb3M7GOgLXB+VKMSiRNLNm7nZxPmMqhLBvecM0AjFkqjVW0ycfdZZnY80BcwYKm7l0Y9MpF6Lq+whDHjZ9I8uSn/vPyIWr1jXSTeVJlMzOy8Kl462Mxw95eiFJNIvVdWXsH1/57Nxvwinrv2KNq3SIl1SCIxta8jk++Gz+2AY4Cp4fyJwCdARMnEzJoAM4B17n6WmfUAngNaAzOBy929xMySgfHAEcBW4CJ3XxVu4zbgaoIT/ze4+zsR76FIFNz39hI+WraF+0YdxpCurWIdjkjMVXkC3t2vdPcrgUSgv7uPcvdRwKFhW6R+CiyuNH8fcL+79wa2ESQJwudtYfv94XKYWX/g4vB9RwCPhAlKJCZemb2Oxz5ayRVHd+OiI7vGOhyReiGSq7m6uHvl4kCbgIj+B5lZZ+A7wOPhvAEnARPDRcYB54TTI8N5wtdPDpcfCTzn7sXuvhLIBoZG8v4itW3+2nxueXEeQ3tkcvtZ/WMdjki9EcnVXFPM7B3g3+H8RcC7EW7/AeBmID2cbw3khfeqAKwFOoXTnYA1ENzLYmb54fKdgM8qbbPyOl8xszHAGICuXfVrUWrflh3FXPvMDFqnJfHIpUNIVNFEka9U+7/B3X8C/AMYGD7Guvv11a1nZmcBOe4+s8ZRRsDdx7p7lrtntW3btvoVRPZDaXkFP/6/WeQWljD2iizaNE+OdUgi9UqkhR4/AcoIblz8PMJ1hgNnm9mZQArQAvgbkGFmTcOjk87AunD5dUAXYK2ZNQVaEpyI392+W+V1ROrE3a8t4vNVufzt4kEM6NQy1uGI1DuRFHq8kCCBnA9cCEwzs2pvWnT329y9s7t3JziBPtXdLwXe4+ubHkcDr4bTk8J5wtenejBo9iTgYjNLDq8E60PkCU2kxp77/Eue+Ww11x7Xk5GDvtXDKiJEdmTya+BId88BMLO2BOdMJu5zrardAjxnZr8DZgNPhO1PAM+YWTaQS5CAcPeFZjYBWERwdHSdu6s2mNSJz1Zs5fZXF/A/fdpw84h+sQ5HpN6KJJkk7E4koa1EdhXYV9z9feD9cHoFe7kay92LgAuqWP/3wO/35z1FamrOmjyufno63Vqn8dAlgzUQlcg+RJJM3t7L1VxvRi8kkdhbsnE7o5/8nMzmSfzf1cPISE2KdUgi9Voktbl+GZZWOTZsGuvuL0c3LJHYWbllJ5c9/jkpiQn86wdH0aGlSqWIVKfaZGJmacCr7v6SmfUF+ppZooo9SkO0Lm8Xlz0+jQp3nvvBUXTJ1CBXIpGI5NzHh0CymXUC3gYuJxh9UaRB2VxQzGWPT2N7USnjrxpK73bp1a8kIkBkycTcvRA4D3jU3S8gqJMl0mDkFZZw+RPT2JhfxNNXHql7SUT2U0TJxMyOBi4F3gjbVGhRGowdxWV8/6nprNi8k8euyOKIbpmxDkkk7kRyNdeNwG3Ay+E9Hz0JbjwUiXtFpeX8YNx05q/L59FLh3BsnzaxDkkkLkVyNdcHwAeV5lcAN0QzKJG6UFJWwY+fncW0lbncf+EgTju0Q6xDEolb+xpp8QF3v9HMXiOoyfUN7n52VCMTiaLyCuemCXOYuiSHP5x7GOcMVpkUkZrY15HJM+Hzn+siEJG6UlHh3PbSPN6Yt4Ffn3kI3xumIQtEaqrKZLK7dLy7f2BmSUA/giOUpe5eUkfxidQqd+eeNxYxYcZabji5D9cc1zPWIYk0CJHctPgdgvFMlgMG9DCza939rWgHJ1Lb7p/8BU99vIqrhvfgplP6xDockQYjkqu5/gKc6O7ZAGbWi+ASYSUTiSv//GA5D07N5qKsLtx+1iEEo0KLSG2I5D6Tgt2JJLQCKIhSPCJR8ey01fzvW0s46/CO/OG8w5RIRGpZJEcmM8zsTWACwTmTC4DpYfFH3P2lKMYnUmOvzF7Hb15ZwMn92nH/RYNUSl4kCiJJJinAJuD4cH4z0Az4LkFyUTKRemvyok38/IW5HNWjNQ9fOoTEJvs1FI+IRCiSmxavrItARGrbhvxd3PT8HAYc1ILHRmeRkqgqQCLREskY8Aeb2RQzWxDOH25mv4l+aCIHzt359csLKKuo4MFLBtM8OZKDcBE5UJEc8z9GUJurFMDd5xGOzy5SX02au56pS3L4xWl96dY6LdbhiDR4kSSTVHf/fI+2smgEI1Ibtuwo5s5JCxnUJYMrh/eIdTgijUIkyWRLeG+JA5jZ+cCGqEYlUgN3vbaIHcVl/PH8w3XllkgdiaQj+TpgLNDPzNYBKwnGNhGpdyYv2sRrc9fzs1MP5uD2GilRpK5EcjXXCuCUcCz4BHfXDYtSL+XvKuXXL8+nX4d0fnh8r1iHI9KoRHyJi7vvjGYgIjX1hzcWs2VHMY+PziKpqe4nEalL+h8nDcLH2Vt4fsYarjmuJ4d3zoh1OCKNzj6TiZklmNkxdRWMyIEoLCnj1pfm0aNNGjedcnCswxFplPaZTNy9Ani4jmIROSB/emcpa3J3ce95h+kud5EYiaSba4qZjbL9LLNqZilm9rmZzTWzhWZ2V9jew8ymmVm2mT0fDryFmSWH89nh690rbeu2sH2pmZ2+P3FIwzZzdS5Pf7KKy4/qxrCerWMdjkijFUkyuRZ4ASgxs+1mVmBm2yNYrxg4yd0HAoOAEWZ2FHAfcL+79wa2AVeHy18NbAvb7w+Xw8z6E9xxfygwAnjEzPTzUygqLefmifM4qGUzbjmjX6zDEWnUqk0m7p7u7gnunujuLcL5FhGs5+6+I5xNDB8OnARMDNvHAeeE0yPDecLXTw6PhkYCz7l7sbuvBLKBoRHunzRgf5+azfLNO/n9uQNUe0skxiIp9GhmdpmZ3R7OdzGziL7MzayJmc0BcoDJBEP/5rn77nIsa4FO4XQnYA1A+Ho+0Lpy+17WqfxeY8xshpnN2Lx5cyThSRxbuD6fRz9YznlDOnFC33axDkek0Yukm+sR4Gjge+H8DiI8Ke/u5e4+COhMcDQRtb4Idx/r7lnuntW2bdtovY3UA2XlFdw8cR6tUpP47Vn9Yx2OiBBZMhnm7tcBRQDuvg1I2p83cfc84D2CpJRhZrv7JDoD68LpdUAXgPD1lsDWyu17WUcaobEfrWDh+u3cM/JQMlL3609RRKIkkmRSGp7w3l3osS1QUd1KZtbWzDLC6WbAqcBigqRyfrjYaODVcHpSOE/4+lR397D94vBqrx5AH2DPKsbSSCzfvIMH3l3GGQM6cMZhHWMdjoiEIjlr+SDwMtDezH5P8EUfyeBYHYFxYSJKACa4++tmtgh4zsx+B8wGngiXfwJ4xsyygVzCMVPcfaGZTQAWEZS+v87dyyPeQ2kwKiqcWybOo1liE+4aeWiswxGRSiIp9Pismc0ETg6bznH3xRGsNw8YvJf2Fezlaix3LwIuqGJbvwd+X917SsP2zGermbF6G3++YCDt0lNiHY6IVBLp9ZSpwO6urmbRC0dk79bkFnLf20s4/uC2jBryrYv5RCTGIrk0+LcE939kAm2ApzQGvNQld+dXL8/HgN+fO4D9LMYgInUgkiOTS4GBYTcUZnYvMAf4XTQDE9lt4sy1fLRsC3ePPJTOrVJjHY6I7EUkV3OtByp3UCejS3OljuRsL+Ke1xcxtHsmlw3rFutwRKQKkRyZ5AMLzWwywTmTU4HPzexBAHe/IYrxSSNVVl5BbmEJv3llAcVlFdw76jASNJ67SL0VSTJ5OXzs9n50QpGGrKLCydtVSu7OYrbsKGHrjpKvp3cWk7uzJGwPprcVln617i0j+tGzbfMYRi8i1Ynk0uBx1S0jsid355H3l/Pa3PVs2VHCtsISyit8r8u2Sk0kMy2J1s2T6dshndZpyWSmJdGmeRKdM1M5vo/K44jUdyq1KrXO3bn79UU89fEqhvXIZHDXDFqnJdO6eVKYJL6ezkxNomkTjR4tEu+UTKRWVVQ4t7+6gGenfclVw3tw+1mH6FJekUZAyURqTXmFc8uL85g4cy0/OqEXN5/eV4lEpJGoMpmY2WuExR33xt3PjkpEEpfKyiv42YS5TJq7nhtP6cNPT+6jRCLSiOzryOTP4fN5QAfg/8L5S4BN0QxK4ktJWQU/fW42by3YyC0j+vGjE3rFOiQRqWNVJhN3/wDAzP7i7lmVXnrNzGZEPTKJC0Wl5Vz37CymLMnht2f156pje8Q6JBGJgUguo0kzs567Z8IxRdKiF5LEi10l5VwzfgZTluTwu3MGKJGINGKRnIC/EXjfzFYABnQDxkQ1Kqn3dhaX8YNxM/hs5Vb+eP7hXJjVpfqVRKTB2mcyMbMEguFz+/D1+O1L3L042oFJ/VVQVMqVT01n9po8HrhoECMHqSS8SGO3z24ud68Abnb3YnefGz6USBqx/MJSLnvic+asyeOhSwYrkYgIENk5k3fN7Bdm1sXMMnc/oh6Z1Du5O0u45LHPWLx+O/+47AjO1BjsIhKK5JzJReHzdZXaHOi5l2WlgdpcUMylj3/G6q2FPDY6i+MPVr0sEflaJIUedYlOI7cxv4jvPf4ZG/KKeOrKIzmmV5tYhyQi9UxE5VTMbADQn0qDZLn7+GgFJfXH2m2FfO+xaeTuLGH81UM5srt6OEXk26pNJmZ2B3ACQTJ5EzgD+C+gZNLArd66k+89No2ColL+7wfDGNQlI9YhiUg9FckJ+POBk4GN7n4lMJDgcmFpwHIKirjon59RWFLGv645SolERPYpkm6uXe5eYWZlZtYCyAF0h1oD5u7c+uJ8thWW8PKPh9P/oBaxDklE6rlIkskMM8sAHgNmAjuAT6MalcTU89PXMHVJDnd+t78SiYhEJJKruX4cTv7DzN4GWrj7vOiGJbGyJreQe15fxDG9WnPF0d1jHY6IxIlITsA/A3wIfOTuS6IfksRKeYXz8wlzSTDjTxcMJCFB45GISGQiOQH/JNAReMjMVpjZi2b20+pWCu+Yf8/MFpnZwt3rhHfQTzazZeFzq7DdzOxBM8s2s3lmNqTStkaHyy8zs9EHuK9SjSf/u5LPV+Vy59mH0imjWazDEZE4Um0ycff3gN8DtxOcN8kCfhTBtsuAn7t7f+Ao4Doz6w/cCkxx9z7AlHAegkuO+4SPMcCjECQf4A5gGDAUuGN3ApLas3RjAX96Zymn9W/PeUNUb0tE9k+1ycTMpgAfE5RVWQoc6e799r0WuPsGd58VThcAi4FOwEhgXLjYOOCccHokMN4DnwEZZtYROB2Y7O657r4NmAyM2I99lGqUlFXwswlzSE9pyh/OO0zD7YrIfoukm2seUAIMAA4HBpjZfvWBmFl3YDAwDWjv7hvClzYC7cPpTsCaSqutDduqat/zPcaY2Qwzm7F58+b9Ca/R+/vUZSxcv53/Pe8w2jRPjnU4IhKHIunmusndjyMYC34r8BSQF+kbmFlz4EXgRnffvse2naBoZI25+1h3z3L3rLZtVYQwUrO/3MbD7y9n1JDOnHZoh1iHIyJxKpJurp+Y2fPAbIKuqCcJzm9Uy8wSCRLJs+7+Uti8Key+InzOCdvX8c2bITuHbVW1Sw3tKinn5xPm0j49mTvO7h/rcEQkjkXSzZUC/BXo5+6nuPtd7j61upUs6Hh/Aljs7n+t9NIkYPcVWaOBVyu1XxFe1XUUkB92h70DnGZmrcIT76eFbVJD9729hBVbdvLnCwbSIiUx1uGISByLpJvrz0AicDmAmbU1s0jK0g8P1znJzOaEjzOBe4FTzWwZcEo4D0ERyRVANsFVYz8O3z8XuAeYHj7uDtukBj7O3sLTn6ziyuHdOaa3SsqLSM1YcNpiHwsEVYOzgL7ufrCZHQS84O7D6yLAA5GVleUzZsyIdRj1Vv6uUkY88CHNkprw5g3/Q0pik1iHJCL1gJnNdPesA1k3km6uc4GzgZ0A7r4eSD+QN5P64a7XFpJTUMxfLxykRCIitSKSZFJS+aorM0uLbkgSTW8v2MhLs9Zx3Ym9VVZeRGpNJMlkgpn9k+AmwmuAdwnOaUic2bKjmF+/PJ8BnVpw/Um9Yx2OiDQg+yz0GF6R9TzQD9gO9AV+6+6T6yA2qUXuzm0vzaeguIx/XziIxCaR/I4QEYnMPpOJu7uZvenuhxGUMZE4NXHmWiYv2sRvvnMIB7fXKS8RqV2R/DydZWZHRj0SiZq12wq567VFDO2RyVXDI7mqW0Rk/0Qy0uIw4FIzW01wRZcRHLQcHtXIpFZUVDi/fGEe7s5fNEaJiA8EanUAABC3SURBVERJJMnk9KhHIVHz9Cer+HTFVu4bdRhdMlNjHY6INFCRDNu7ui4CkdqXnVPAfW8v4eR+7bgwq0v1K4iIHCBd0tNAlZZX8LMJc0lNasL/jtIYJSISXZF0c0mcySss4a7XFjFvbT6PXDqEdukpsQ5JRBo4JZMGpKLCmThzLfe+vYT8XaVcf1JvzjysY6zDEpFGQMmkgVi4Pp/bX1nArC/zyOrWinvOGcAhHVvEOiwRaSSUTOLc9qJS/vqfLxj/6SpapSbxp/MPZ9SQzroEWETqlJJJnHJ3Xpmzjt+/sYStO4u5bFg3fnFaX1qmapArEal7SiZx6ItNBdz+ygKmrcxlYJcMnvr+kRzWuWWswxKRRkzJJI7sLC7jb1OW8eR/V5KW3JQ/nHsYFx/ZRV1aIhJzSiZxwN15a8FG7nl9ERvyi7goqwu3nNGPzLSkWIcmIgIomdR7Kzbv4I5JC/lo2Rb6d2zB3783hCO6tYp1WCIi36BkUk/tKinn4feyGfvhCpKbJnDnd/tz2VHdaKpxSESkHlIyqSfcneWbd/D5ym1MX5XLf7O3sLmgmHMHd+K2M/vpLnYRqdeUTGKkrLyCheu3M31VLp+vzGXG6m3k7iwBoE3zJI7snsnoY7pzVM/WMY5URKR6SiZ1ZFdJObPXbGN6eOQx68ttFJaUA9A1M5UT+7ZjaI9WHNk9kx5t0lSYUUTiipJJlOQVljB91bavjjwWrMunrMIxg34dWnDBEZ05skcmR3bPpH0LdWGJSHxTMomCh6Ys4y+TvwAgqUkCh3duyTXH9WRo90yGdGtFy2a6S11EGhYlk1r26px1/GXyF3znsI5ccXQ3BnbJICWxSazDEhGJKiWTWjR3TR43T5zH0O6Z3H/RIJKa6jJeEWkcovZtZ2ZPmlmOmS2o1JZpZpPNbFn43CpsNzN70MyyzWyemQ2ptM7ocPllZjY6WvHW1Mb8Iq4ZP4O26ck8etkQJRIRaVSi+Y33NDBij7ZbgSnu3geYEs4DnAH0CR9jgEchSD7AHcAwYChwx+4EVJ8UlZYz5pkZ7Cwu4/HRWbRunhzrkERE6lTUkom7fwjk7tE8EhgXTo8DzqnUPt4DnwEZZtYROB2Y7O657r4NmMy3E1RMuTs3T5zH/HX5PHDxYPp10IBUItL41HVfTHt33xBObwTah9OdgDWVllsbtlXVXm888v5yJs1dzy9P78up/dtXv4KISAMUs459d3fAa2t7ZjbGzGaY2YzNmzfX1mb36e0FG/nTO0s5Z9BB/Oj4XnXyniIi9VFdJ5NNYfcV4XNO2L4O6FJpuc5hW1Xt3+LuY909y92z2rZtW+uB72nR+u38bMIcBnbJ4N5Rh+uOdRFp1Oo6mUwCdl+RNRp4tVL7FeFVXUcB+WF32DvAaWbWKjzxflrYFlNbdhRzzfgZtEhJ5LHLj9B9JCLS6EXtPhMz+zdwAtDGzNYSXJV1LzDBzK4GVgMXhou/CZwJZAOFwJUA7p5rZvcA08Pl7nb3PU/q16nisnJ++MxMtu4s5oVrj6GdSqGIiEQvmbj7JVW8dPJelnXguiq28yTwZC2GdsDcnd+8vIAZq7fx0CWDNe66iEhId9bthyf+u5IXZq7lhpN6892BB8U6HBGRekPJJELvLc3hD28uZsShHbjxlINjHY6ISL2iZBKB7JwCbvjXbPp2aMFfLxpIQoKu3BIRqUzJpBp5hSVcPW4GyYkJPD46i9Qk1cYUEdmTvhn3obS8guv+NYsNeUX8e8wwOmU0i3VIIiL1kpLJPtzz+iI+zt7Kn84/nCO6ZcY6HBGRekvdXFV45rPVjP90NWOO68kFWV2qX0FEpBFTMtmLT7K3cOekhZzYty23jOgX63BEROo9JZM9bC4o5rp/zaJHmzQevGQwTXTllohItXTOZA93TFrAzuJyJlw7hPSUxFiHIyISF3RkUslb8zfw5vyN/PSUPvRpnx7rcERE4oaSSSivsITbX11I/44tGHNcz1iHIyISV9TNFbr79UXkFZYw7qojSWyiHCsisj/0rUlQd+ulWev44fG9OPQgVQIWEdlfjT6ZFBSV8uuX5tO7XXOuP7l3rMMREYlLjb6b6963lrBhexEv/ugYkptqxEQRkQPRqI9MPl2+lWenfclVw3swpGurWIcjIhK3Gm0y2VVSzq0vzaNrZiq/OK1vrMMREYlrjbab6y//WcrqrYX865phNEtS95aISE00yiOT2V9u48mPV/K9YV05plebWIcjIhL3Gl0yKS4r5+aJ82jfIoXbzlARRxGR2tDourn+PjWbZTk7eOr7R6r2lohILWlURyaL1m/n0feXc97gTpzYr12swxERaTAaTTIpK6/g5hfnkpGayO1n9Y91OCIiDUqj6eYa+9EKFqzbzqOXDqFVWlKswxERaVAaxZFJds4OHnh3GWcM6MAZh3WMdTgiIg1Og08m5RXOLS/Oo1liE+4aeWiswxERaZAafDIZ/+kqZq7exh3f7U+79JRYhyMi0iDFTTIxsxFmttTMss3s1kjW+XJrIX98eykn9G3LuYM7RTtEEZFGKy6SiZk1AR4GzgD6A5eY2T4vyXJ3bnt5Hk0SjD+cexhmVhehiog0SnGRTIChQLa7r3D3EuA5YOS+Vnh++ho+zt7KrWf046CMZnUSpIhIY2XuHusYqmVm5wMj3P0H4fzlwDB3/0mlZcYAY8LZAcCCOg+07rQBtsQ6iCjS/sW3hrx/DXnfAPq6e/qBrNhg7jNx97HAWAAzm+HuWTEOKWq0f/FN+xe/GvK+QbB/B7puvHRzrQO6VJrvHLaJiEg9EC/JZDrQx8x6mFkScDEwKcYxiYhIKC66udy9zMx+ArwDNAGedPeF+1hlbN1EFjPav/im/YtfDXnfoAb7Fxcn4EVEpH6Ll24uERGpx5RMRESkxuI6mVRXYsXMks3s+fD1aWbWve6jPHAR7N/3zWyzmc0JHz+IRZwHwsyeNLMcM9vr/UAWeDDc93lmNqSuY6yJCPbvBDPLr/TZ/bauYzxQZtbFzN4zs0VmttDMfrqXZeL284tw/+L580sxs8/NbG64f3ftZZn9/+5097h8EJyIXw70BJKAuUD/PZb5MfCPcPpi4PlYx13L+/d94O+xjvUA9+84YAiwoIrXzwTeAgw4CpgW65href9OAF6PdZwHuG8dgSHhdDrwxV7+NuP284tw/+L58zOgeTidCEwDjtpjmf3+7oznI5NISqyMBMaF0xOBky1+inTtdwmZeOLuHwK5+1hkJDDeA58BGWYWN4PRRLB/ccvdN7j7rHC6AFgM7FlJNW4/vwj3L26Fn8mOcDYxfOx5JdZ+f3fGczLpBKypNL+Wb3/gXy3j7mVAPtC6TqKruUj2D2BU2I0w0cy67OX1eBXp/sezo8OuhrfMLC4H2wm7PwYT/LqtrEF8fvvYP4jjz8/MmpjZHCAHmOzuVX5+kX53xnMyEXgN6O7uhwOT+fqXhNR/s4Bu7j4QeAh4Jcbx7Dczaw68CNzo7ttjHU9tq2b/4vrzc/dydx9EUE1kqJkNqOk24zmZRFJi5atlzKwp0BLYWifR1Vy1++fuW929OJx9HDiijmKrCw26hI67b9/d1eDubwKJZtYmxmFFzMwSCb5on3X3l/aySFx/ftXtX7x/fru5ex7wHjBij5f2+7sznpNJJCVWJgGjw+nzgakenlGKA9Xu3x590GcT9O02FJOAK8Krgo4C8t19Q6yDqi1m1mF3H7SZDSX4vxgXP3TCuJ8AFrv7X6tYLG4/v0j2L84/v7ZmlhFONwNOBZbssdh+f3fGRTmVvfEqSqyY2d3ADHefRPAH8YyZZROcDL04dhHvnwj37wYzOxsoI9i/78cs4P1kZv8muCKmjZmtBe4gOBGIu/8DeJPgiqBsoBC4MjaRHpgI9u984EdmVgbsAi6Oox86w4HLgflhvzvAr4Cu0CA+v0j2L54/v47AOAsGHUwAJrj76zX97lQ5FRERqbF47uYSEZF6QslERERqTMlERERqTMlERERqTMlERCTOVVdYdI9l769UoPILM8urjRiUTCRumNn/mtmJZnaOmd0W5fc6yMwmRvM9aoOZ/Wo/l/++mR0UrXgkZp7m2zce7pW73+Tug8I74B8C9nbT6X5TMpF4Mgz4DDge+DCab+Tu6939/D3bw7uB65P9SiYE9yIpmTQweyssama9zOxtM5tpZh+ZWb+9rHoJ8O/aiEHJROo9M/uTmc0DjgQ+BX4APLq3MSTCu3tfNLPp4WN42H5n2BXwvpmtMLMbwvZ7zey6SuvfaWa/MLPuu7sMwl/zk8xsKjDFzDLN7JWwwOZnZnZ4Ne/R3cyWmNnTYbfCs2Z2ipl9bGbLwjuoMbO0cP3PzWy2mY2s9P4vhV8My8zsj7tjB5qF3RXP7vHv0CR8vwVmNt/MbjKz84Es4NlwnWZmdoSZfRB+4bxjYVWFcB/+Fi63oFKMx1fqIpltZum19TlLrRsLXO/uRwC/AB6p/KKZdQN6AFNr5d1iXVtfDz0ieRAkkocI7iL/eB/L/Qs4NpzuSlASA+BO4BMgGWhDUPoikaAi7AeV1l9EUJOoO+FYJAS/5tcCmeH8Q8Ad4fRJwJxq3qM7QZWCwwh+wM0EniQYV2Ik8Eq4/h+Ay8LpDIJxNNLC919BUB8pBVgNdAmX21HFv8MRBNVgd89nhM/vA1nhdGIYb9tw/iKCSgu7l3ssnD6u0r/Fa8DwcLo50DTWfxt6fPUZV/6bbU5wZ/6cSo/Feyx/C/BQbb1/fTtkF6nKEIIBwvqx7xpkpwD97euhF1pYUP0V4A0PCmMWm1kO0N7dZ5tZu/A8Qltgm7uvsW+PLDfZ3Xd3IxwLjAJw96lm1trMWlT1HmH7SnefD2BmC4Ep7u5mNp/gSwDgNOBsM/tFOJ9CWMIjXD4/XH8R0I1vlnjf0wqgp5k9BLwB/Gcvy/QFBgCTw3+vJkDl+ln/DvfxQzNrYUE9p4+Bv4ZHQi+5+9p9xCCxkwDkeXBepCoXA9ft4/X9omQi9ZqZDSI4udgZ2AKkBs02Bzja3XftsUoCwahxRXtsB6C4UlM5X//9v0BQa6kD8HwVoeyMMOSq3qNye0Wl+YpKyxgwyt2X7hH7sH1sd6/cfZuZDQROB34IXAhctcdiBix096Or2sy3N+v3mtkbBHW3Pjaz0919zyKBEmPuvt3MVprZBe7+ggX/AQ5397kA4fmTVgTdxrVC50ykXnP3OeGvqy+A/gT9u6d7cDXKnokEgl/g1++eCZNRdZ4n+JV2PkFiqc5HwKXh9k8AtnjtjOfxDnB9+B8fMxscwTqlFpRL/wYLyqEnuPuLwG8IjuwACgiGogVYCrQ1s6PDdRLtm4M8XRS2H0tQ9TffzHq5+3x3v4+gsvXeTupKHbOgsOinQF8zW2tmVxP8jV5tZnOBhXxzpNaLgec87O+qDToykXrPzHZ3P1WYWT93X7SPxW8AHg5P2DcluOrrh/vavgfVmNOBdR5ZmfQ7gSfD9yjk61LdNXUP8AAwz8wSgJXAWdWsMzZcfpa7X1qpvRPwVLgdgN2XUj8N/MPMdgFHEyTQB82sJcG/1wMEXzwARWY2m+Dcyu6jmhvN7ESCI6qFBOO8S4y5+yVVvLTXy4Xd/c7ajkFVg0XkW8zsfeAX7j4j1rFIfFA3l4iI1JiOTEREpMZ0ZCIiIjWmZCIiIjWmZCIiIjWmZCIiIjWmZCIiIjX2/4r6j95yTgqPAAAAAElFTkSuQmCC\n",
"text/plain": [
- "\u003cFigure size 432x288 with 1 Axes\u003e"
+ ""
]
},
"metadata": {
"needs_background": "light"
- },
- "output_type": "display_data"
+ }
},
{
- "name": "stdout",
"output_type": "stream",
+ "name": "stdout",
"text": [
- "time to jit: 0:01:25.539043\n",
- "time to train: 0:01:27.168924\n"
+ "time to jit: 0:01:07.299997\n",
+ "time to train: 0:01:25.539139\n"
]
}
],
@@ -287,16 +282,16 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 4,
"metadata": {
"id": "fgB52sgjDhvi"
},
"outputs": [],
"source": [
"model.save_params('/tmp/params', params)\n",
- "empty_params, inference_fn = ppo.make_params_and_inference_fn(\n",
+ "inference_fn = ppo.make_inference_fn(\n",
" env.observation_size, env.action_size, True)\n",
- "params = model.load_params('/tmp/params', empty_params)"
+ "params = model.load_params('/tmp/params')"
]
},
{
@@ -312,60 +307,55 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 5,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 480
},
"id": "RNMLEyaTspEM",
- "outputId": "6befbca0-18ce-49dc-c2d8-08f3caa7f5b8"
+ "outputId": "e2f9cd70-d9a4-4642-ddaa-5d97eb7a6600"
},
"outputs": [
{
+ "output_type": "execute_result",
"data": {
"text/html": [
"\n",
- "\u003chtml\u003e\n",
- "\n",
- " \u003chead\u003e\n",
- " \u003ctitle\u003ebrax visualizer\u003c/title\u003e\n",
- " \u003cstyle\u003e\n",
+ "\n",
+ " \n",
+ " brax visualizer\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ "\n"
],
"text/plain": [
- "\u003cIPython.core.display.HTML object\u003e"
+ ""
]
},
- "execution_count": 5,
"metadata": {},
- "output_type": "execute_result"
+ "execution_count": 5
}
],
"source": [
@@ -414,4 +404,4 @@
},
"nbformat": 4,
"nbformat_minor": 0
-}
+}
\ No newline at end of file