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": "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\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