From c9308d7e5eaf7e49012531565920587fd580fd56 Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 30 Oct 2025 15:25:47 -0400 Subject: [PATCH 01/26] Change colab ubuntu version. --- .github/workflows/colab.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/colab.yml b/.github/workflows/colab.yml index 7946adfd5d..4ece61ca6a 100644 --- a/.github/workflows/colab.yml +++ b/.github/workflows/colab.yml @@ -16,7 +16,7 @@ on: jobs: colab: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest env: COLAB_ALWAYS_INSTALL_XVFB: 1 QLEARNING_NUM_TRAINING_STEPS: 5 From bd3c61988fa2501a2f121fa1a7ca0716bc1b51c0 Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 30 Oct 2025 15:59:11 -0400 Subject: [PATCH 02/26] Add timeout parameter. --- .github/workflows/colab.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/colab.yml b/.github/workflows/colab.yml index 4ece61ca6a..e3ce570986 100644 --- a/.github/workflows/colab.yml +++ b/.github/workflows/colab.yml @@ -54,7 +54,7 @@ jobs: python -m pip install --progress-bar=off -e ./ml-agents python -m pip install --progress-bar=off -r colab_requirements.txt - name: Execute notebook - run: jupyter nbconvert --to notebook --execute --log-level=DEBUG --ExecutePreprocessor.kernel_name=python3 --output output-${{ matrix.notebook_path }} colab/${{ matrix.notebook_path }} + run: jupyter nbconvert --to notebook --execute --log-level=DEBUG --ExecutePreprocessor.kernel_name=python3 --ExecutePreprocessor.timeout=600 --output output-${{ matrix.notebook_path }} colab/${{ matrix.notebook_path }} - name: Upload colab results uses: actions/upload-artifact@v4 with: From 88f53945c3bc6760f3fe01ca565bf703cf3f9b9b Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 30 Oct 2025 16:25:32 -0400 Subject: [PATCH 03/26] Move timeout to colab --- .github/workflows/colab.yml | 4 ++-- colab/Colab_UnityEnvironment_1_Run.ipynb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/colab.yml b/.github/workflows/colab.yml index e3ce570986..7946adfd5d 100644 --- a/.github/workflows/colab.yml +++ b/.github/workflows/colab.yml @@ -16,7 +16,7 @@ on: jobs: colab: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 env: COLAB_ALWAYS_INSTALL_XVFB: 1 QLEARNING_NUM_TRAINING_STEPS: 5 @@ -54,7 +54,7 @@ jobs: python -m pip install --progress-bar=off -e ./ml-agents python -m pip install --progress-bar=off -r colab_requirements.txt - name: Execute notebook - run: jupyter nbconvert --to notebook --execute --log-level=DEBUG --ExecutePreprocessor.kernel_name=python3 --ExecutePreprocessor.timeout=600 --output output-${{ matrix.notebook_path }} colab/${{ matrix.notebook_path }} + run: jupyter nbconvert --to notebook --execute --log-level=DEBUG --ExecutePreprocessor.kernel_name=python3 --output output-${{ matrix.notebook_path }} colab/${{ matrix.notebook_path }} - name: Upload colab results uses: actions/upload-artifact@v4 with: diff --git a/colab/Colab_UnityEnvironment_1_Run.ipynb b/colab/Colab_UnityEnvironment_1_Run.ipynb index e70dca7b8a..471a598abf 100644 --- a/colab/Colab_UnityEnvironment_1_Run.ipynb +++ b/colab/Colab_UnityEnvironment_1_Run.ipynb @@ -217,7 +217,7 @@ "\n", "from mlagents_envs.registry import default_registry\n", "\n", - "env = default_registry[env_id].make()" + "env = default_registry[env_id].make(timeout_wait=120)" ], "execution_count": 3, "outputs": [ From ef463fb394b8a87380a9ae11fd8ab70f416b587b Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 30 Oct 2025 16:36:24 -0400 Subject: [PATCH 04/26] Bump to latest --- .github/workflows/colab.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/colab.yml b/.github/workflows/colab.yml index 7946adfd5d..4ece61ca6a 100644 --- a/.github/workflows/colab.yml +++ b/.github/workflows/colab.yml @@ -16,7 +16,7 @@ on: jobs: colab: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest env: COLAB_ALWAYS_INSTALL_XVFB: 1 QLEARNING_NUM_TRAINING_STEPS: 5 From 9c63f168c5f1b6b4ac8f02c68aa878b6c83db5e0 Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 30 Oct 2025 16:45:52 -0400 Subject: [PATCH 05/26] Remove upper bound limit --- .github/workflows/colab.yml | 2 +- colab/Colab_UnityEnvironment_1_Run.ipynb | 2 +- ml-agents/setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/colab.yml b/.github/workflows/colab.yml index 4ece61ca6a..7946adfd5d 100644 --- a/.github/workflows/colab.yml +++ b/.github/workflows/colab.yml @@ -16,7 +16,7 @@ on: jobs: colab: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 env: COLAB_ALWAYS_INSTALL_XVFB: 1 QLEARNING_NUM_TRAINING_STEPS: 5 diff --git a/colab/Colab_UnityEnvironment_1_Run.ipynb b/colab/Colab_UnityEnvironment_1_Run.ipynb index 471a598abf..e70dca7b8a 100644 --- a/colab/Colab_UnityEnvironment_1_Run.ipynb +++ b/colab/Colab_UnityEnvironment_1_Run.ipynb @@ -217,7 +217,7 @@ "\n", "from mlagents_envs.registry import default_registry\n", "\n", - "env = default_registry[env_id].make(timeout_wait=120)" + "env = default_registry[env_id].make()" ], "execution_count": 3, "outputs": [ diff --git a/ml-agents/setup.py b/ml-agents/setup.py index 2aec4e2cd6..16be25d8b3 100644 --- a/ml-agents/setup.py +++ b/ml-agents/setup.py @@ -62,7 +62,7 @@ def run(self): "Pillow>=4.2.1", "protobuf>=3.6,<3.21", "pyyaml>=3.1.0", - "torch>=2.1.1,<=2.8.0", + "torch>=2.1.1", "tensorboard>=2.14", # adding six explicit dependency since tensorboard needs it but doesn't declare it as a dep "six>=1.16", From fc5fea4b82aaa1939cca20cb27eca0bdbe2e8d68 Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 30 Oct 2025 17:24:23 -0400 Subject: [PATCH 06/26] Test --- .github/workflows/colab.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/colab.yml b/.github/workflows/colab.yml index 7946adfd5d..7e26a39798 100644 --- a/.github/workflows/colab.yml +++ b/.github/workflows/colab.yml @@ -54,7 +54,7 @@ jobs: python -m pip install --progress-bar=off -e ./ml-agents python -m pip install --progress-bar=off -r colab_requirements.txt - name: Execute notebook - run: jupyter nbconvert --to notebook --execute --log-level=DEBUG --ExecutePreprocessor.kernel_name=python3 --output output-${{ matrix.notebook_path }} colab/${{ matrix.notebook_path }} + run: jupyter nbconvert --to notebook --execute --log-level=DEBUG --ExecutePreprocessor.kernel_name=python3 --ExecutePreprocessor.timeout=120 --output output-${{ matrix.notebook_path }} colab/${{ matrix.notebook_path }} - name: Upload colab results uses: actions/upload-artifact@v4 with: From f1c7d05d8bfa532bd76a69fba8b6a559e414ac88 Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 30 Oct 2025 17:34:11 -0400 Subject: [PATCH 07/26] Change versions --- .github/workflows/colab.yml | 2 +- ml-agents/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/colab.yml b/.github/workflows/colab.yml index 7e26a39798..f8b5af3d6d 100644 --- a/.github/workflows/colab.yml +++ b/.github/workflows/colab.yml @@ -16,7 +16,7 @@ on: jobs: colab: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest env: COLAB_ALWAYS_INSTALL_XVFB: 1 QLEARNING_NUM_TRAINING_STEPS: 5 diff --git a/ml-agents/setup.py b/ml-agents/setup.py index 16be25d8b3..2aec4e2cd6 100644 --- a/ml-agents/setup.py +++ b/ml-agents/setup.py @@ -62,7 +62,7 @@ def run(self): "Pillow>=4.2.1", "protobuf>=3.6,<3.21", "pyyaml>=3.1.0", - "torch>=2.1.1", + "torch>=2.1.1,<=2.8.0", "tensorboard>=2.14", # adding six explicit dependency since tensorboard needs it but doesn't declare it as a dep "six>=1.16", From d48d4a25f20c4e7708aa4271aca8f1ad991d54bc Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 30 Oct 2025 17:49:21 -0400 Subject: [PATCH 08/26] Test --- colab/Colab_UnityEnvironment_1_Run.ipynb | 55 ++---------------------- 1 file changed, 3 insertions(+), 52 deletions(-) diff --git a/colab/Colab_UnityEnvironment_1_Run.ipynb b/colab/Colab_UnityEnvironment_1_Run.ipynb index e70dca7b8a..4db8560620 100644 --- a/colab/Colab_UnityEnvironment_1_Run.ipynb +++ b/colab/Colab_UnityEnvironment_1_Run.ipynb @@ -206,58 +206,9 @@ "end_time": "2023-10-04T12:52:26.115543Z" } }, - "source": [ - "# -----------------\n", - "# This code is used to close an env that might not have been closed before\n", - "try:\n", - " env.close()\n", - "except:\n", - " pass\n", - "# -----------------\n", - "\n", - "from mlagents_envs.registry import default_registry\n", - "\n", - "env = default_registry[env_id].make()" - ], - "execution_count": 3, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[UnityMemory] Configuration Parameters - Can be set up in boot.config\n", - " \"memorysetup-bucket-allocator-granularity=16\"\n", - " \"memorysetup-bucket-allocator-bucket-count=8\"\n", - " \"memorysetup-bucket-allocator-block-size=4194304\"\n", - " \"memorysetup-bucket-allocator-block-count=1\"\n", - " \"memorysetup-main-allocator-block-size=16777216\"\n", - " \"memorysetup-thread-allocator-block-size=16777216\"\n", - " \"memorysetup-gfx-main-allocator-block-size=16777216\"\n", - " \"memorysetup-gfx-thread-allocator-block-size=16777216\"\n", - " \"memorysetup-cache-allocator-block-size=4194304\"\n", - " \"memorysetup-typetree-allocator-block-size=2097152\"\n", - " \"memorysetup-profiler-bucket-allocator-granularity=16\"\n", - " \"memorysetup-profiler-bucket-allocator-bucket-count=8\"\n", - " \"memorysetup-profiler-bucket-allocator-block-size=4194304\"\n", - " \"memorysetup-profiler-bucket-allocator-block-count=1\"\n", - " \"memorysetup-profiler-allocator-block-size=16777216\"\n", - " \"memorysetup-profiler-editor-allocator-block-size=1048576\"\n", - " \"memorysetup-temp-allocator-size-main=4194304\"\n", - " \"memorysetup-job-temp-allocator-block-size=2097152\"\n", - " \"memorysetup-job-temp-allocator-block-size-background=1048576\"\n", - " \"memorysetup-job-temp-allocator-reduction-small-platforms=262144\"\n", - " \"memorysetup-allocator-temp-initial-block-size-main=262144\"\n", - " \"memorysetup-allocator-temp-initial-block-size-worker=262144\"\n", - " \"memorysetup-temp-allocator-size-background-worker=32768\"\n", - " \"memorysetup-temp-allocator-size-job-worker=262144\"\n", - " \"memorysetup-temp-allocator-size-preload-manager=262144\"\n", - " \"memorysetup-temp-allocator-size-nav-mesh-worker=65536\"\n", - " \"memorysetup-temp-allocator-size-audio-worker=65536\"\n", - " \"memorysetup-temp-allocator-size-cloud-worker=32768\"\n", - " \"memorysetup-temp-allocator-size-gfx=262144\"\n" - ] - } - ] + "source": "# -----------------\n# This code is used to close an env that might not have been closed before\ntry:\n env.close()\nexcept:\n pass\n# -----------------\n\nfrom mlagents_envs.registry import default_registry\n\nenv = default_registry[env_id].make(timeout_wait=120)", + "execution_count": null, + "outputs": [] }, { "cell_type": "markdown", From bf39b06951a18a0937f3ab10cdcc13239c3d42c1 Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 30 Oct 2025 17:57:00 -0400 Subject: [PATCH 09/26] Increase cell timeout --- .github/workflows/colab.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/colab.yml b/.github/workflows/colab.yml index f8b5af3d6d..ad2c4a48f4 100644 --- a/.github/workflows/colab.yml +++ b/.github/workflows/colab.yml @@ -54,7 +54,7 @@ jobs: python -m pip install --progress-bar=off -e ./ml-agents python -m pip install --progress-bar=off -r colab_requirements.txt - name: Execute notebook - run: jupyter nbconvert --to notebook --execute --log-level=DEBUG --ExecutePreprocessor.kernel_name=python3 --ExecutePreprocessor.timeout=120 --output output-${{ matrix.notebook_path }} colab/${{ matrix.notebook_path }} + run: jupyter nbconvert --to notebook --execute --log-level=DEBUG --ExecutePreprocessor.kernel_name=python3 --ExecutePreprocessor.timeout=300 --output output-${{ matrix.notebook_path }} colab/${{ matrix.notebook_path }} - name: Upload colab results uses: actions/upload-artifact@v4 with: From 9bf77e4d03004e0220d7239739348a94f78bbf0e Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 30 Oct 2025 18:06:56 -0400 Subject: [PATCH 10/26] Increase Unity timeout --- colab/Colab_UnityEnvironment_1_Run.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/colab/Colab_UnityEnvironment_1_Run.ipynb b/colab/Colab_UnityEnvironment_1_Run.ipynb index 4db8560620..3aa18bb4e7 100644 --- a/colab/Colab_UnityEnvironment_1_Run.ipynb +++ b/colab/Colab_UnityEnvironment_1_Run.ipynb @@ -206,7 +206,7 @@ "end_time": "2023-10-04T12:52:26.115543Z" } }, - "source": "# -----------------\n# This code is used to close an env that might not have been closed before\ntry:\n env.close()\nexcept:\n pass\n# -----------------\n\nfrom mlagents_envs.registry import default_registry\n\nenv = default_registry[env_id].make(timeout_wait=120)", + "source": "# -----------------\n# This code is used to close an env that might not have been closed before\ntry:\n env.close()\nexcept:\n pass\n# -----------------\n\nfrom mlagents_envs.registry import default_registry\n\nenv = default_registry[env_id].make(timeout_wait=180)", "execution_count": null, "outputs": [] }, From 8a3cf12f198357341c87eaf91fdce66d89f326ec Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 30 Oct 2025 18:16:52 -0400 Subject: [PATCH 11/26] Set no_graphics to True --- colab/Colab_UnityEnvironment_1_Run.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/colab/Colab_UnityEnvironment_1_Run.ipynb b/colab/Colab_UnityEnvironment_1_Run.ipynb index 3aa18bb4e7..ec3aa10f01 100644 --- a/colab/Colab_UnityEnvironment_1_Run.ipynb +++ b/colab/Colab_UnityEnvironment_1_Run.ipynb @@ -206,7 +206,7 @@ "end_time": "2023-10-04T12:52:26.115543Z" } }, - "source": "# -----------------\n# This code is used to close an env that might not have been closed before\ntry:\n env.close()\nexcept:\n pass\n# -----------------\n\nfrom mlagents_envs.registry import default_registry\n\nenv = default_registry[env_id].make(timeout_wait=180)", + "source": "# -----------------\n# This code is used to close an env that might not have been closed before\ntry:\n env.close()\nexcept:\n pass\n# -----------------\n\nfrom mlagents_envs.registry import default_registry\n\nenv = default_registry[env_id].make( no_graphics=True)", "execution_count": null, "outputs": [] }, From 3a83fef37dd7fea6cdb264545ef8a8abca9c294a Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 30 Oct 2025 18:26:50 -0400 Subject: [PATCH 12/26] Clean --- .github/workflows/colab.yml | 2 +- colab/Colab_UnityEnvironment_1_Run.ipynb | 55 ++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/.github/workflows/colab.yml b/.github/workflows/colab.yml index ad2c4a48f4..4ece61ca6a 100644 --- a/.github/workflows/colab.yml +++ b/.github/workflows/colab.yml @@ -54,7 +54,7 @@ jobs: python -m pip install --progress-bar=off -e ./ml-agents python -m pip install --progress-bar=off -r colab_requirements.txt - name: Execute notebook - run: jupyter nbconvert --to notebook --execute --log-level=DEBUG --ExecutePreprocessor.kernel_name=python3 --ExecutePreprocessor.timeout=300 --output output-${{ matrix.notebook_path }} colab/${{ matrix.notebook_path }} + run: jupyter nbconvert --to notebook --execute --log-level=DEBUG --ExecutePreprocessor.kernel_name=python3 --output output-${{ matrix.notebook_path }} colab/${{ matrix.notebook_path }} - name: Upload colab results uses: actions/upload-artifact@v4 with: diff --git a/colab/Colab_UnityEnvironment_1_Run.ipynb b/colab/Colab_UnityEnvironment_1_Run.ipynb index ec3aa10f01..ded77696ad 100644 --- a/colab/Colab_UnityEnvironment_1_Run.ipynb +++ b/colab/Colab_UnityEnvironment_1_Run.ipynb @@ -206,9 +206,58 @@ "end_time": "2023-10-04T12:52:26.115543Z" } }, - "source": "# -----------------\n# This code is used to close an env that might not have been closed before\ntry:\n env.close()\nexcept:\n pass\n# -----------------\n\nfrom mlagents_envs.registry import default_registry\n\nenv = default_registry[env_id].make( no_graphics=True)", - "execution_count": null, - "outputs": [] + "source": [ + "# -----------------\n", + "# This code is used to close an env that might not have been closed before\n", + "try:\n", + " env.close()\n", + "except:\n", + " pass\n", + "# -----------------\n", + "\n", + "from mlagents_envs.registry import default_registry\n", + "\n", + "env = default_registry[env_id].make(no_graphics=True)" + ], + "execution_count": 3, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[UnityMemory] Configuration Parameters - Can be set up in boot.config\n", + " \"memorysetup-bucket-allocator-granularity=16\"\n", + " \"memorysetup-bucket-allocator-bucket-count=8\"\n", + " \"memorysetup-bucket-allocator-block-size=4194304\"\n", + " \"memorysetup-bucket-allocator-block-count=1\"\n", + " \"memorysetup-main-allocator-block-size=16777216\"\n", + " \"memorysetup-thread-allocator-block-size=16777216\"\n", + " \"memorysetup-gfx-main-allocator-block-size=16777216\"\n", + " \"memorysetup-gfx-thread-allocator-block-size=16777216\"\n", + " \"memorysetup-cache-allocator-block-size=4194304\"\n", + " \"memorysetup-typetree-allocator-block-size=2097152\"\n", + " \"memorysetup-profiler-bucket-allocator-granularity=16\"\n", + " \"memorysetup-profiler-bucket-allocator-bucket-count=8\"\n", + " \"memorysetup-profiler-bucket-allocator-block-size=4194304\"\n", + " \"memorysetup-profiler-bucket-allocator-block-count=1\"\n", + " \"memorysetup-profiler-allocator-block-size=16777216\"\n", + " \"memorysetup-profiler-editor-allocator-block-size=1048576\"\n", + " \"memorysetup-temp-allocator-size-main=4194304\"\n", + " \"memorysetup-job-temp-allocator-block-size=2097152\"\n", + " \"memorysetup-job-temp-allocator-block-size-background=1048576\"\n", + " \"memorysetup-job-temp-allocator-reduction-small-platforms=262144\"\n", + " \"memorysetup-allocator-temp-initial-block-size-main=262144\"\n", + " \"memorysetup-allocator-temp-initial-block-size-worker=262144\"\n", + " \"memorysetup-temp-allocator-size-background-worker=32768\"\n", + " \"memorysetup-temp-allocator-size-job-worker=262144\"\n", + " \"memorysetup-temp-allocator-size-preload-manager=262144\"\n", + " \"memorysetup-temp-allocator-size-nav-mesh-worker=65536\"\n", + " \"memorysetup-temp-allocator-size-audio-worker=65536\"\n", + " \"memorysetup-temp-allocator-size-cloud-worker=32768\"\n", + " \"memorysetup-temp-allocator-size-gfx=262144\"\n" + ] + } + ] }, { "cell_type": "markdown", From 1ad3d438dde8ca503842c971bab6cca2f6aa6950 Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 30 Oct 2025 18:28:56 -0400 Subject: [PATCH 13/26] Clean up --- colab/Colab_UnityEnvironment_1_Run.ipynb | 102 +++++++++++------------ 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/colab/Colab_UnityEnvironment_1_Run.ipynb b/colab/Colab_UnityEnvironment_1_Run.ipynb index ded77696ad..9ac80f920f 100644 --- a/colab/Colab_UnityEnvironment_1_Run.ipynb +++ b/colab/Colab_UnityEnvironment_1_Run.ipynb @@ -207,57 +207,57 @@ } }, "source": [ - "# -----------------\n", - "# This code is used to close an env that might not have been closed before\n", - "try:\n", - " env.close()\n", - "except:\n", - " pass\n", - "# -----------------\n", - "\n", - "from mlagents_envs.registry import default_registry\n", - "\n", - "env = default_registry[env_id].make(no_graphics=True)" - ], - "execution_count": 3, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[UnityMemory] Configuration Parameters - Can be set up in boot.config\n", - " \"memorysetup-bucket-allocator-granularity=16\"\n", - " \"memorysetup-bucket-allocator-bucket-count=8\"\n", - " \"memorysetup-bucket-allocator-block-size=4194304\"\n", - " \"memorysetup-bucket-allocator-block-count=1\"\n", - " \"memorysetup-main-allocator-block-size=16777216\"\n", - " \"memorysetup-thread-allocator-block-size=16777216\"\n", - " \"memorysetup-gfx-main-allocator-block-size=16777216\"\n", - " \"memorysetup-gfx-thread-allocator-block-size=16777216\"\n", - " \"memorysetup-cache-allocator-block-size=4194304\"\n", - " \"memorysetup-typetree-allocator-block-size=2097152\"\n", - " \"memorysetup-profiler-bucket-allocator-granularity=16\"\n", - " \"memorysetup-profiler-bucket-allocator-bucket-count=8\"\n", - " \"memorysetup-profiler-bucket-allocator-block-size=4194304\"\n", - " \"memorysetup-profiler-bucket-allocator-block-count=1\"\n", - " \"memorysetup-profiler-allocator-block-size=16777216\"\n", - " \"memorysetup-profiler-editor-allocator-block-size=1048576\"\n", - " \"memorysetup-temp-allocator-size-main=4194304\"\n", - " \"memorysetup-job-temp-allocator-block-size=2097152\"\n", - " \"memorysetup-job-temp-allocator-block-size-background=1048576\"\n", - " \"memorysetup-job-temp-allocator-reduction-small-platforms=262144\"\n", - " \"memorysetup-allocator-temp-initial-block-size-main=262144\"\n", - " \"memorysetup-allocator-temp-initial-block-size-worker=262144\"\n", - " \"memorysetup-temp-allocator-size-background-worker=32768\"\n", - " \"memorysetup-temp-allocator-size-job-worker=262144\"\n", - " \"memorysetup-temp-allocator-size-preload-manager=262144\"\n", - " \"memorysetup-temp-allocator-size-nav-mesh-worker=65536\"\n", - " \"memorysetup-temp-allocator-size-audio-worker=65536\"\n", - " \"memorysetup-temp-allocator-size-cloud-worker=32768\"\n", - " \"memorysetup-temp-allocator-size-gfx=262144\"\n" - ] - } - ] + "# -----------------\n", + "# This code is used to close an env that might not have been closed before\n", + "try:\n", + " env.close()\n", + "except:\n", + " pass\n", + "# -----------------\n", + "\n", + "from mlagents_envs.registry import default_registry\n", + "\n", + "env = default_registry[env_id].make(no_graphics=True)" + ], + "execution_count": 3, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[UnityMemory] Configuration Parameters - Can be set up in boot.config\n", + " \"memorysetup-bucket-allocator-granularity=16\"\n", + " \"memorysetup-bucket-allocator-bucket-count=8\"\n", + " \"memorysetup-bucket-allocator-block-size=4194304\"\n", + " \"memorysetup-bucket-allocator-block-count=1\"\n", + " \"memorysetup-main-allocator-block-size=16777216\"\n", + " \"memorysetup-thread-allocator-block-size=16777216\"\n", + " \"memorysetup-gfx-main-allocator-block-size=16777216\"\n", + " \"memorysetup-gfx-thread-allocator-block-size=16777216\"\n", + " \"memorysetup-cache-allocator-block-size=4194304\"\n", + " \"memorysetup-typetree-allocator-block-size=2097152\"\n", + " \"memorysetup-profiler-bucket-allocator-granularity=16\"\n", + " \"memorysetup-profiler-bucket-allocator-bucket-count=8\"\n", + " \"memorysetup-profiler-bucket-allocator-block-size=4194304\"\n", + " \"memorysetup-profiler-bucket-allocator-block-count=1\"\n", + " \"memorysetup-profiler-allocator-block-size=16777216\"\n", + " \"memorysetup-profiler-editor-allocator-block-size=1048576\"\n", + " \"memorysetup-temp-allocator-size-main=4194304\"\n", + " \"memorysetup-job-temp-allocator-block-size=2097152\"\n", + " \"memorysetup-job-temp-allocator-block-size-background=1048576\"\n", + " \"memorysetup-job-temp-allocator-reduction-small-platforms=262144\"\n", + " \"memorysetup-allocator-temp-initial-block-size-main=262144\"\n", + " \"memorysetup-allocator-temp-initial-block-size-worker=262144\"\n", + " \"memorysetup-temp-allocator-size-background-worker=32768\"\n", + " \"memorysetup-temp-allocator-size-job-worker=262144\"\n", + " \"memorysetup-temp-allocator-size-preload-manager=262144\"\n", + " \"memorysetup-temp-allocator-size-nav-mesh-worker=65536\"\n", + " \"memorysetup-temp-allocator-size-audio-worker=65536\"\n", + " \"memorysetup-temp-allocator-size-cloud-worker=32768\"\n", + " \"memorysetup-temp-allocator-size-gfx=262144\"\n" + ] + } + ] }, { "cell_type": "markdown", From 4c2ffb64111cdef9ac6598c0f771cfe36c11c171 Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 4 Dec 2025 15:52:11 -0500 Subject: [PATCH 14/26] Update MLA version --- com.unity.ml-agents/CHANGELOG.md | 3 ++- com.unity.ml-agents/Runtime/Academy.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/com.unity.ml-agents/CHANGELOG.md b/com.unity.ml-agents/CHANGELOG.md index d0b4d9dd15..ee971215da 100755 --- a/com.unity.ml-agents/CHANGELOG.md +++ b/com.unity.ml-agents/CHANGELOG.md @@ -6,9 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [4.0.1] - 2025-12-04 ### Minor Changes #### com.unity.ml-agents (C#) +- Upgraded to Inference Engine 2.4.1 (#) - Fixed tensor indexing to use correct CHW layout (#6239) - Updated the installation doc (#6242) diff --git a/com.unity.ml-agents/Runtime/Academy.cs b/com.unity.ml-agents/Runtime/Academy.cs index 3cdc15f64c..612caa8352 100644 --- a/com.unity.ml-agents/Runtime/Academy.cs +++ b/com.unity.ml-agents/Runtime/Academy.cs @@ -107,7 +107,7 @@ public class Academy : IDisposable /// Unity package version of com.unity.ml-agents. /// This must match the version string in package.json and is checked in a unit test. /// - internal const string k_PackageVersion = "4.0.0"; + internal const string k_PackageVersion = "4.0.1"; const int k_EditorTrainingPort = 5004; From 732ff2c505bbe45381a85a312e8dcd6bdc06184a Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 4 Dec 2025 16:17:00 -0500 Subject: [PATCH 15/26] Update Changelog --- com.unity.ml-agents/CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/com.unity.ml-agents/CHANGELOG.md b/com.unity.ml-agents/CHANGELOG.md index ee971215da..8e17cc71f0 100755 --- a/com.unity.ml-agents/CHANGELOG.md +++ b/com.unity.ml-agents/CHANGELOG.md @@ -9,7 +9,6 @@ and this project adheres to ## [4.0.1] - 2025-12-04 ### Minor Changes #### com.unity.ml-agents (C#) -- Upgraded to Inference Engine 2.4.1 (#) - Fixed tensor indexing to use correct CHW layout (#6239) - Updated the installation doc (#6242) From 7937a913edcc74e243cad4b940bec1a4efa4ade0 Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 4 Dec 2025 16:38:00 -0500 Subject: [PATCH 16/26] Add CONTRIBUTING.md to the doc --- .../Documentation~/Reference-Support.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/com.unity.ml-agents/Documentation~/Reference-Support.md b/com.unity.ml-agents/Documentation~/Reference-Support.md index 922e65c79d..7bc6fa7b19 100644 --- a/com.unity.ml-agents/Documentation~/Reference-Support.md +++ b/com.unity.ml-agents/Documentation~/Reference-Support.md @@ -3,10 +3,12 @@ The Reference & Support section contains essential documentation for ongoing ML-Agents development. -| **Resource** | **Description** | -|--------------------------------------|--------------------------------------------------------------| -| [FAQ](FAQ.md) | Frequently asked questions and common issues with solutions. | -| [Limitations](Limitations.md) | Known limitations and constraints of the ML-Agents Toolkit. | -| [Migrating](Migrating.md) | Migration guides for updating between ML-Agents versions. | -| [Versioning](Versioning.md) | Information about ML-Agents versioning and release notes. | -| [ML-Agents Glossary](Glossary.md) | Glossary of terms and concepts used in ML-Agents. | +| **Resource** | **Description** | +|--------------------------------------------|--------------------------------------------------------------| +| [FAQ](FAQ.md) | Frequently asked questions and common issues with solutions. | +| [Limitations](Limitations.md) | Known limitations and constraints of the ML-Agents Toolkit. | +| [Migrating](Migrating.md) | Migration guides for updating between ML-Agents versions. | +| [Versioning](Versioning.md) | Information about ML-Agents versioning and release notes. | +| [ML-Agents Glossary](Glossary.md) | Glossary of terms and concepts used in ML-Agents. | +| [Contribution guidelines](CONTRIBUTING.md) | How to Contribute to ML-Agents. | + From 52b6a22089e12e6b8150d6fcfefe82298db2a487 Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 4 Dec 2025 16:39:01 -0500 Subject: [PATCH 17/26] Remove extra line --- com.unity.ml-agents/Documentation~/Reference-Support.md | 1 - 1 file changed, 1 deletion(-) diff --git a/com.unity.ml-agents/Documentation~/Reference-Support.md b/com.unity.ml-agents/Documentation~/Reference-Support.md index 7bc6fa7b19..8c891229f9 100644 --- a/com.unity.ml-agents/Documentation~/Reference-Support.md +++ b/com.unity.ml-agents/Documentation~/Reference-Support.md @@ -11,4 +11,3 @@ The Reference & Support section contains essential documentation for ongoing ML- | [Versioning](Versioning.md) | Information about ML-Agents versioning and release notes. | | [ML-Agents Glossary](Glossary.md) | Glossary of terms and concepts used in ML-Agents. | | [Contribution guidelines](CONTRIBUTING.md) | How to Contribute to ML-Agents. | - From f9ffd6733b33f022a68e292177526eaf9b71e73e Mon Sep 17 00:00:00 2001 From: Bob Donovan Date: Wed, 10 Dec 2025 15:13:29 -0500 Subject: [PATCH 18/26] Fixing crash when Editor Application is quitting in Runtime Mode Dispose was not called when editor was quitting resulting in a crash in the Job system when CPU Workers were disposed in finalizers by the garbage collector on the wrong thread. --- com.unity.ml-agents/Runtime/Academy.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/com.unity.ml-agents/Runtime/Academy.cs b/com.unity.ml-agents/Runtime/Academy.cs index 612caa8352..9957e91f43 100644 --- a/com.unity.ml-agents/Runtime/Academy.cs +++ b/com.unity.ml-agents/Runtime/Academy.cs @@ -261,6 +261,7 @@ protected Academy() LazyInitialize(); #if UNITY_EDITOR + EditorApplication.quitting += Dispose; EditorApplication.playModeStateChanged += HandleOnPlayModeChanged; #endif } From cc3981279bda3cdde8679a45247f6a58723c75d2 Mon Sep 17 00:00:00 2001 From: Bob Donovan Date: Thu, 11 Dec 2025 16:40:06 -0500 Subject: [PATCH 19/26] trunk test are unstable changing to 6.3 --- .yamato/com.unity.ml-agents-test.yml | 2 +- .yamato/test_versions.metafile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.yamato/com.unity.ml-agents-test.yml b/.yamato/com.unity.ml-agents-test.yml index 6a62b4b85c..dc0aeca828 100644 --- a/.yamato/com.unity.ml-agents-test.yml +++ b/.yamato/com.unity.ml-agents-test.yml @@ -8,7 +8,7 @@ test_editors: enableNoDefaultPackages: !!bool true trunk_editor: - - version: trunk + - version: 6000.4 testProject: DevProject test_platforms: diff --git a/.yamato/test_versions.metafile b/.yamato/test_versions.metafile index abcec74931..2d4a1ee5d3 100644 --- a/.yamato/test_versions.metafile +++ b/.yamato/test_versions.metafile @@ -7,5 +7,5 @@ test_editors: extra_test: gym - version: 6000.0 extra_test: sensor - - version: trunk + - version: 6000.3 extra_test: llapi From 419c11beba695301c1323453ff76a8b1e8a42e0a Mon Sep 17 00:00:00 2001 From: Bob Donovan Date: Wed, 10 Dec 2025 15:27:23 -0500 Subject: [PATCH 20/26] Adding entry in change log --- com.unity.ml-agents/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/com.unity.ml-agents/CHANGELOG.md b/com.unity.ml-agents/CHANGELOG.md index 8e17cc71f0..a2b7b7d1fb 100755 --- a/com.unity.ml-agents/CHANGELOG.md +++ b/com.unity.ml-agents/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to #### com.unity.ml-agents (C#) - Fixed tensor indexing to use correct CHW layout (#6239) - Updated the installation doc (#6242) +- Fixed Unity Editor crashing when quitting in play mode (#6267) #### ml-agents / ml-agents-envs - Set the Torch version constraint to 2.8 (#6251) From 19e8d47f51979ae866f33d402b765b1d6c4edbcc Mon Sep 17 00:00:00 2001 From: Bob Donovan Date: Tue, 16 Dec 2025 13:22:53 -0500 Subject: [PATCH 21/26] Fixing Issue #6268 --- ml-agents-envs/mlagents_envs/registry/unity_env_registry.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ml-agents-envs/mlagents_envs/registry/unity_env_registry.py b/ml-agents-envs/mlagents_envs/registry/unity_env_registry.py index 896c71ac94..0b281206e3 100644 --- a/ml-agents-envs/mlagents_envs/registry/unity_env_registry.py +++ b/ml-agents-envs/mlagents_envs/registry/unity_env_registry.py @@ -121,6 +121,6 @@ def __iter__(self) -> Iterator[Any]: default_registry = UnityEnvRegistry() # TODO restore when a new registry is available. -default_registry.register_from_yaml( - "https://storage.googleapis.com/mlagents-test-environments/1.1.0/manifest.yaml" -) # noqa E501 +#default_registry.register_from_yaml( +# "https://storage.googleapis.com/mlagents-test-environments/1.1.0/manifest.yaml" +#) # noqa E501 From 08aacb2a7f364e30b14986cc462860c6128413a6 Mon Sep 17 00:00:00 2001 From: Bob Donovan Date: Tue, 16 Dec 2025 13:47:47 -0500 Subject: [PATCH 22/26] Fixing pre-commit Fixing Pre-commit Changing order of operations in pre-commit Still fixing pre-commit stuff Fixing python formatting with black removing --no-restore flag --- .github/workflows/pre-commit.yml | 15 +- .pre-commit-config.yaml | 3 +- CLAUDE.md | 178 ++++++++++++++++++ .../registry/unity_env_registry.py | 4 +- 4 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 CLAUDE.md diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index d1422573e8..1a77b13354 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -13,7 +13,11 @@ jobs: pre-commit: runs-on: ubuntu-24.04 env: - DOTNET_NOLOGO: 1 + DOTNET_NOLOGO: 1 + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: "1" + DOTNET_CLI_HOME: "${{ github.workspace }}/.dotnet" + NUGET_PACKAGES: "${{ github.workspace }}/.nuget/packages" + TMPDIR: "${{ github.workspace }}/.tmp" steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 @@ -25,15 +29,20 @@ jobs: with: ruby-version: '2.7' bundler-cache: true # runs 'bundle install' and caches installed gems automatically + - name: Create writable dirs + run: | + mkdir -p "$DOTNET_CLI_HOME" "$NUGET_PACKAGES" "$TMPDIR" - uses: actions/setup-dotnet@v4 with: dotnet-version: '8.0.202' - - name: Clean dotnet shared memory - run: sudo rm -rf /tmp/.dotnet/shm - name: Install manual dependencies run: | python -m pip install pre-commit pre-commit install + - name: Pre-warm dotnet + run: | + dotnet --info + dotnet restore || true - name: Run pre-commit run: | pre-commit run --all-files diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 08a8e33e72..2ab764c102 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -94,7 +94,8 @@ repos: - id: dotnet-format name: dotnet-format language: system - entry: dotnet format whitespace --folder --include + entry: dotnet format whitespace --folder --include . --verify-no-changes + pass_filenames: false types_or: ["c#"] - id: markdown-link-check name: markdown-link-check diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..f4c88f2094 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,178 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +The Unity ML-Agents Toolkit is a sophisticated machine learning infrastructure project that bridges Unity game development (C#) with Python-based ML training. It enables games and simulations to serve as environments for training intelligent agents using reinforcement learning, imitation learning, and other ML techniques. + +This is a **monorepo** with multiple interconnected packages: +- `com.unity.ml-agents/` - Unity Package (C# SDK) +- `ml-agents/` - Python Trainer Package +- `ml-agents-envs/` - Python Environment Interface +- `ml-agents-trainer-plugin/` - Plugin framework +- `protobuf-definitions/` - Communication protocol definitions +- `config/` - Training configuration examples +- `Project/` and `DevProject/` - Example Unity projects + +## Common Development Commands + +### Python Package Installation (Development Mode) +```bash +# Install packages in editable mode for development +pip install -e ./ml-agents-envs +pip install -e ./ml-agents +pip install -e ./ml-agents-trainer-plugin +pip install -e ./ml-agents-plugin-examples + +# Install test dependencies +pip install -r test_requirements.txt +``` + +### Testing +```bash +# Run all tests except slow ones (default for development) +pytest -m "not slow" + +# Run tests with parallel execution (8 workers) +pytest -m "not slow" -n 8 + +# Run tests with coverage reporting +pytest --cov=ml-agents --cov=ml-agents-envs --cov-report html + +# Run slow tests (training-related, takes much longer) +pytest -m slow + +# Run specific test file +pytest ml-agents/mlagents/trainers/tests/test_buffer.py + +# Run specific test function +pytest ml-agents/mlagents/trainers/tests/test_buffer.py::test_buffer_functionality +``` + +### Code Quality and Formatting +```bash +# Run pre-commit hooks on all files +pre-commit run --all-files + +# Run specific hooks +pre-commit run black --all-files +pre-commit run mypy --all-files +pre-commit run flake8 --all-files + +# Format C# code +dotnet format whitespace --folder --include + +# Check markdown links (manual stage) +pre-commit run --hook-stage manual markdown-link-check +``` + +### Training Commands +```bash +# Basic training command +mlagents-learn config/ppo/3DBall.yaml --env=Project/3DBall --run-id=my_run + +# Training with curriculum learning +mlagents-learn config/curricula/Wall.yaml --env=Project/WallJump --run-id=wall_curriculum + +# Resume training from checkpoint +mlagents-learn config/ppo/3DBall.yaml --env=Project/3DBall --run-id=my_run --resume + +# Push trained model to Hugging Face +mlagents-push-to-hf --run-id=my_run --repo-name=my-org/my-model +``` + +### Building and Unity Integration +```bash +# Unity Package Manager operations (from Unity Editor) +# Window > Package Manager > + > Add package from git URL +# https://github.com/Unity-Technologies/ml-agents.git?path=com.unity.ml-agents + +# Build Unity project (from Unity Editor or command line) +Unity -batchmode -quit -projectPath ./Project -buildTarget StandaloneLinux64 +``` + +## Architecture Overview + +### Communication Flow +The system uses a **gRPC-based architecture**: +``` +Unity Environment ←→ gRPC ←→ Python Trainer + (C# SDK) (PyTorch/ML) +``` + +### Key Components + +**Python Side:** +- **Trainers** (`ml-agents/mlagents/trainers/`): Core ML algorithms (PPO, SAC, MA-POCA, GAIL, BC) +- **Environment Interface** (`ml-agents-envs/`): Communication with Unity environments +- **Plugin System**: Extensible trainer types and stats writers via entry points + +**Unity Side:** +- **Agent** (`com.unity.ml-agents/Runtime/Agent.cs`): Base class for trainable agents +- **Sensors**: Observation collection (vision, raycast, grid sensors) +- **Actuators**: Action execution (continuous/discrete) +- **Communicator**: gRPC communication layer + +### Multi-Package Structure + +The project uses **separate Python packages** with careful version management: +- Packages can be installed independently +- Version constraints are strictly managed (see `setup.py` files) +- Plugin system uses entry points for extensibility + +## Development Workflow + +### Code Quality Standards +- **Python**: Black formatting (120 char line length), mypy type checking, flake8 linting +- **C#**: dotnet-format for whitespace formatting +- **Testing**: pytest with 60% minimum coverage requirement +- **Pre-commit hooks**: Enforced via `.pre-commit-config.yaml` + +### Important Constraints +- **Python Version**: 3.10.1-3.10.12 only +- **PyTorch**: ≤2.8.0 (strict constraint to prevent ONNX breaking changes) +- **Unity**: 6000.0+ (Unity 6) +- **Banned modules**: Direct tensorflow/torch imports (use utils instead) + +### Testing Strategy +- **Parallel execution**: Tests run with 8 workers using pytest-xdist +- **Port allocation**: Custom `base_port` fixture prevents port collisions +- **Slow tests**: Training-related tests marked with `@pytest.mark.slow` +- **Coverage**: HTML reports available via `--cov-report html` + +### Plugin Development +Extend functionality via entry points in `setup.py`: +```python +entry_points={ + ML_AGENTS_STATS_WRITER: ["custom_writer=my_package:MyStatsWriter"], + ML_AGENTS_TRAINER_TYPE: ["custom_trainer=my_package:MyTrainer"] +} +``` + +## Key Files for Development + +**Configuration:** +- `config/` - Training configuration YAML files for different algorithms +- `.pre-commit-config.yaml` - Code quality enforcement +- `pytest.ini`, `setup.cfg` - Test and coverage configuration + +**Architecture Entry Points:** +- `ml-agents/mlagents/trainers/learn.py` - Main training script +- `ml-agents-envs/mlagents_envs/environment.py` - Environment interface +- `com.unity.ml-agents/Runtime/Agent.cs` - Unity agent base class + +**Documentation:** +- Primary docs: [Unity Package Documentation](https://docs.unity3d.com/Packages/com.unity.ml-agents@latest) +- Legacy docs: `docs/` directory (deprecated) + +## Release and Versioning + +- **Main branch**: `develop` (unstable development) +- **Release branch pattern**: `release_XX` +- **Version validation**: Pre-commit hooks ensure version consistency across packages +- **Git tags**: Must match `__release_tag__` in `__init__.py` files + +## Port Management + +Tests use a **file-lock based port allocation system** (`conftest.py`) to enable parallel execution without port conflicts. Ports are dynamically allocated starting from a base port calculated per test file. \ No newline at end of file diff --git a/ml-agents-envs/mlagents_envs/registry/unity_env_registry.py b/ml-agents-envs/mlagents_envs/registry/unity_env_registry.py index 0b281206e3..6542d2f441 100644 --- a/ml-agents-envs/mlagents_envs/registry/unity_env_registry.py +++ b/ml-agents-envs/mlagents_envs/registry/unity_env_registry.py @@ -121,6 +121,6 @@ def __iter__(self) -> Iterator[Any]: default_registry = UnityEnvRegistry() # TODO restore when a new registry is available. -#default_registry.register_from_yaml( +# default_registry.register_from_yaml( # "https://storage.googleapis.com/mlagents-test-environments/1.1.0/manifest.yaml" -#) # noqa E501 +# ) # noqa E501 From 7d82fc12d7d007f060ab31e4ffbdb6ec7569db0c Mon Sep 17 00:00:00 2001 From: Bob Donovan Date: Wed, 17 Dec 2025 15:33:12 -0500 Subject: [PATCH 23/26] Bumping the version to 4.0.1 --- com.unity.ml-agents/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.ml-agents/package.json b/com.unity.ml-agents/package.json index 394fd72689..7467cb4ac8 100755 --- a/com.unity.ml-agents/package.json +++ b/com.unity.ml-agents/package.json @@ -1,7 +1,7 @@ { "name": "com.unity.ml-agents", "displayName": "ML Agents", - "version": "4.0.0", + "version": "4.0.1", "unity": "6000.0", "description": "Use state-of-the-art machine learning to create intelligent character behaviors in any Unity environment (games, robotics, film, etc.).", "dependencies": { From 6dd8ba20460ed3afebefa23ea80e1833301a94af Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 18 Dec 2025 16:10:42 -0500 Subject: [PATCH 24/26] Undo unnecessary changes. --- CLAUDE.md | 178 ----------- colab/Colab_UnityEnvironment_1_Run.ipynb | 366 ++++++++++++----------- 2 files changed, 184 insertions(+), 360 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index f4c88f2094..0000000000 --- a/CLAUDE.md +++ /dev/null @@ -1,178 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Project Overview - -The Unity ML-Agents Toolkit is a sophisticated machine learning infrastructure project that bridges Unity game development (C#) with Python-based ML training. It enables games and simulations to serve as environments for training intelligent agents using reinforcement learning, imitation learning, and other ML techniques. - -This is a **monorepo** with multiple interconnected packages: -- `com.unity.ml-agents/` - Unity Package (C# SDK) -- `ml-agents/` - Python Trainer Package -- `ml-agents-envs/` - Python Environment Interface -- `ml-agents-trainer-plugin/` - Plugin framework -- `protobuf-definitions/` - Communication protocol definitions -- `config/` - Training configuration examples -- `Project/` and `DevProject/` - Example Unity projects - -## Common Development Commands - -### Python Package Installation (Development Mode) -```bash -# Install packages in editable mode for development -pip install -e ./ml-agents-envs -pip install -e ./ml-agents -pip install -e ./ml-agents-trainer-plugin -pip install -e ./ml-agents-plugin-examples - -# Install test dependencies -pip install -r test_requirements.txt -``` - -### Testing -```bash -# Run all tests except slow ones (default for development) -pytest -m "not slow" - -# Run tests with parallel execution (8 workers) -pytest -m "not slow" -n 8 - -# Run tests with coverage reporting -pytest --cov=ml-agents --cov=ml-agents-envs --cov-report html - -# Run slow tests (training-related, takes much longer) -pytest -m slow - -# Run specific test file -pytest ml-agents/mlagents/trainers/tests/test_buffer.py - -# Run specific test function -pytest ml-agents/mlagents/trainers/tests/test_buffer.py::test_buffer_functionality -``` - -### Code Quality and Formatting -```bash -# Run pre-commit hooks on all files -pre-commit run --all-files - -# Run specific hooks -pre-commit run black --all-files -pre-commit run mypy --all-files -pre-commit run flake8 --all-files - -# Format C# code -dotnet format whitespace --folder --include - -# Check markdown links (manual stage) -pre-commit run --hook-stage manual markdown-link-check -``` - -### Training Commands -```bash -# Basic training command -mlagents-learn config/ppo/3DBall.yaml --env=Project/3DBall --run-id=my_run - -# Training with curriculum learning -mlagents-learn config/curricula/Wall.yaml --env=Project/WallJump --run-id=wall_curriculum - -# Resume training from checkpoint -mlagents-learn config/ppo/3DBall.yaml --env=Project/3DBall --run-id=my_run --resume - -# Push trained model to Hugging Face -mlagents-push-to-hf --run-id=my_run --repo-name=my-org/my-model -``` - -### Building and Unity Integration -```bash -# Unity Package Manager operations (from Unity Editor) -# Window > Package Manager > + > Add package from git URL -# https://github.com/Unity-Technologies/ml-agents.git?path=com.unity.ml-agents - -# Build Unity project (from Unity Editor or command line) -Unity -batchmode -quit -projectPath ./Project -buildTarget StandaloneLinux64 -``` - -## Architecture Overview - -### Communication Flow -The system uses a **gRPC-based architecture**: -``` -Unity Environment ←→ gRPC ←→ Python Trainer - (C# SDK) (PyTorch/ML) -``` - -### Key Components - -**Python Side:** -- **Trainers** (`ml-agents/mlagents/trainers/`): Core ML algorithms (PPO, SAC, MA-POCA, GAIL, BC) -- **Environment Interface** (`ml-agents-envs/`): Communication with Unity environments -- **Plugin System**: Extensible trainer types and stats writers via entry points - -**Unity Side:** -- **Agent** (`com.unity.ml-agents/Runtime/Agent.cs`): Base class for trainable agents -- **Sensors**: Observation collection (vision, raycast, grid sensors) -- **Actuators**: Action execution (continuous/discrete) -- **Communicator**: gRPC communication layer - -### Multi-Package Structure - -The project uses **separate Python packages** with careful version management: -- Packages can be installed independently -- Version constraints are strictly managed (see `setup.py` files) -- Plugin system uses entry points for extensibility - -## Development Workflow - -### Code Quality Standards -- **Python**: Black formatting (120 char line length), mypy type checking, flake8 linting -- **C#**: dotnet-format for whitespace formatting -- **Testing**: pytest with 60% minimum coverage requirement -- **Pre-commit hooks**: Enforced via `.pre-commit-config.yaml` - -### Important Constraints -- **Python Version**: 3.10.1-3.10.12 only -- **PyTorch**: ≤2.8.0 (strict constraint to prevent ONNX breaking changes) -- **Unity**: 6000.0+ (Unity 6) -- **Banned modules**: Direct tensorflow/torch imports (use utils instead) - -### Testing Strategy -- **Parallel execution**: Tests run with 8 workers using pytest-xdist -- **Port allocation**: Custom `base_port` fixture prevents port collisions -- **Slow tests**: Training-related tests marked with `@pytest.mark.slow` -- **Coverage**: HTML reports available via `--cov-report html` - -### Plugin Development -Extend functionality via entry points in `setup.py`: -```python -entry_points={ - ML_AGENTS_STATS_WRITER: ["custom_writer=my_package:MyStatsWriter"], - ML_AGENTS_TRAINER_TYPE: ["custom_trainer=my_package:MyTrainer"] -} -``` - -## Key Files for Development - -**Configuration:** -- `config/` - Training configuration YAML files for different algorithms -- `.pre-commit-config.yaml` - Code quality enforcement -- `pytest.ini`, `setup.cfg` - Test and coverage configuration - -**Architecture Entry Points:** -- `ml-agents/mlagents/trainers/learn.py` - Main training script -- `ml-agents-envs/mlagents_envs/environment.py` - Environment interface -- `com.unity.ml-agents/Runtime/Agent.cs` - Unity agent base class - -**Documentation:** -- Primary docs: [Unity Package Documentation](https://docs.unity3d.com/Packages/com.unity.ml-agents@latest) -- Legacy docs: `docs/` directory (deprecated) - -## Release and Versioning - -- **Main branch**: `develop` (unstable development) -- **Release branch pattern**: `release_XX` -- **Version validation**: Pre-commit hooks ensure version consistency across packages -- **Git tags**: Must match `__release_tag__` in `__init__.py` files - -## Port Management - -Tests use a **file-lock based port allocation system** (`conftest.py`) to enable parallel execution without port conflicts. Ports are dynamically allocated starting from a base port calculated per test file. \ No newline at end of file diff --git a/colab/Colab_UnityEnvironment_1_Run.ipynb b/colab/Colab_UnityEnvironment_1_Run.ipynb index 9ac80f920f..cbb810138f 100644 --- a/colab/Colab_UnityEnvironment_1_Run.ipynb +++ b/colab/Colab_UnityEnvironment_1_Run.ipynb @@ -1,29 +1,4 @@ { - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Colab-UnityEnvironment-1-Run.ipynb", - "private_outputs": true, - "provenance": [], - "collapsed_sections": [], - "toc_visible": true - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "pycharm": { - "stem_cell": { - "cell_type": "raw", - "source": [], - "metadata": { - "collapsed": false - } - } - } - }, "cells": [ { "cell_type": "markdown", @@ -46,9 +21,11 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { "id": "htb-p1hSNX7D" }, + "outputs": [], "source": [ "#@title Install Rendering Dependencies { display-mode: \"form\" }\n", "#@markdown (You only need to run this code when using Colab's hosted runtime)\n", @@ -122,9 +99,7 @@ " !bash frame-buffer start\n", " os.environ[\"DISPLAY\"] = \":1\"\n", "pro_bar.update(progress(100, 100))" - ], - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", @@ -137,22 +112,14 @@ }, { "cell_type": "code", + "execution_count": 1, "metadata": { - "id": "N8yfQqkbebQ5", "ExecuteTime": { - "start_time": "2023-10-04T12:52:21.641839Z", - "end_time": "2023-10-04T12:52:21.642251Z" - } + "end_time": "2023-10-04T12:52:21.642251Z", + "start_time": "2023-10-04T12:52:21.641839Z" + }, + "id": "N8yfQqkbebQ5" }, - "source": [ - "try:\n", - " import mlagents\n", - " print(\"ml-agents already installed\")\n", - "except ImportError:\n", - " !python -m pip install -q mlagents==1.1.0\n", - " print(\"Installed ml-agents\")" - ], - "execution_count": 1, "outputs": [ { "name": "stdout", @@ -161,6 +128,14 @@ "ml-agents already installed\n" ] } + ], + "source": [ + "try:\n", + " import mlagents\n", + " print(\"ml-agents already installed\")\n", + "except ImportError:\n", + " !python -m pip install -q mlagents==1.1.0\n", + " print(\"Installed ml-agents\")" ] }, { @@ -174,19 +149,19 @@ }, { "cell_type": "code", + "execution_count": 2, "metadata": { - "id": "DpZPbRvRuLZv", "ExecuteTime": { - "start_time": "2023-10-04T12:52:23.330185Z", - "end_time": "2023-10-04T12:52:23.339236Z" - } + "end_time": "2023-10-04T12:52:23.339236Z", + "start_time": "2023-10-04T12:52:23.330185Z" + }, + "id": "DpZPbRvRuLZv" }, + "outputs": [], "source": [ "#@title Select Environment { display-mode: \"form\" }\n", "env_id = \"GridWorld\" #@param ['Basic', '3DBall', '3DBallHard', 'GridWorld', 'Hallway', 'VisualHallway', 'CrawlerDynamicTarget', 'CrawlerStaticTarget', 'Bouncer', 'SoccerTwos', 'PushBlock', 'VisualPushBlock', 'WallJump', 'Tennis', 'Reacher', 'Pyramids', 'VisualPyramids', 'Walker', 'FoodCollector', 'VisualFoodCollector', 'StrikersVsGoalie', 'WormStaticTarget', 'WormDynamicTarget']\n" - ], - "execution_count": 2, - "outputs": [] + ] }, { "cell_type": "markdown", @@ -199,27 +174,14 @@ }, { "cell_type": "code", + "execution_count": 3, "metadata": { - "id": "YSf-WhxbqtLw", "ExecuteTime": { - "start_time": "2023-10-04T12:52:25.056933Z", - "end_time": "2023-10-04T12:52:26.115543Z" - } + "end_time": "2023-10-04T12:52:26.115543Z", + "start_time": "2023-10-04T12:52:25.056933Z" + }, + "id": "YSf-WhxbqtLw" }, - "source": [ - "# -----------------\n", - "# This code is used to close an env that might not have been closed before\n", - "try:\n", - " env.close()\n", - "except:\n", - " pass\n", - "# -----------------\n", - "\n", - "from mlagents_envs.registry import default_registry\n", - "\n", - "env = default_registry[env_id].make(no_graphics=True)" - ], - "execution_count": 3, "outputs": [ { "name": "stdout", @@ -257,6 +219,19 @@ " \"memorysetup-temp-allocator-size-gfx=262144\"\n" ] } + ], + "source": [ + "# -----------------\n", + "# This code is used to close an env that might not have been closed before\n", + "try:\n", + " env.close()\n", + "except:\n", + " pass\n", + "# -----------------\n", + "\n", + "from mlagents_envs.registry import default_registry\n", + "\n", + "env = default_registry[env_id].make()" ] }, { @@ -271,18 +246,18 @@ }, { "cell_type": "code", + "execution_count": 4, "metadata": { - "id": "dhtl0mpeqxYi", "ExecuteTime": { - "start_time": "2023-10-04T12:52:40.819560Z", - "end_time": "2023-10-04T12:52:41.038983Z" - } + "end_time": "2023-10-04T12:52:41.038983Z", + "start_time": "2023-10-04T12:52:40.819560Z" + }, + "id": "dhtl0mpeqxYi" }, + "outputs": [], "source": [ "env.reset()" - ], - "execution_count": 4, - "outputs": [] + ] }, { "cell_type": "markdown", @@ -304,20 +279,14 @@ }, { "cell_type": "code", + "execution_count": 5, "metadata": { - "id": "a7KatdThq7OV", "ExecuteTime": { - "start_time": "2023-10-04T12:52:47.812858Z", - "end_time": "2023-10-04T12:52:47.820527Z" - } + "end_time": "2023-10-04T12:52:47.820527Z", + "start_time": "2023-10-04T12:52:47.812858Z" + }, + "id": "a7KatdThq7OV" }, - "source": [ - "# We will only consider the first Behavior\n", - "behavior_name = list(env.behavior_specs)[0]\n", - "print(f\"Name of the behavior : {behavior_name}\")\n", - "spec = env.behavior_specs[behavior_name]" - ], - "execution_count": 5, "outputs": [ { "name": "stdout", @@ -326,6 +295,12 @@ "Name of the behavior : GridWorld?team=0\n" ] } + ], + "source": [ + "# We will only consider the first Behavior\n", + "behavior_name = list(env.behavior_specs)[0]\n", + "print(f\"Name of the behavior : {behavior_name}\")\n", + "spec = env.behavior_specs[behavior_name]" ] }, { @@ -339,23 +314,14 @@ }, { "cell_type": "code", + "execution_count": 6, "metadata": { - "id": "PqDTV5mSrJF5", "ExecuteTime": { - "start_time": "2023-10-04T12:52:50.586284Z", - "end_time": "2023-10-04T12:52:50.596936Z" - } + "end_time": "2023-10-04T12:52:50.596936Z", + "start_time": "2023-10-04T12:52:50.586284Z" + }, + "id": "PqDTV5mSrJF5" }, - "source": [ - "# Examine the number of observations per Agent\n", - "print(\"Number of observations : \", len(spec.observation_specs))\n", - "\n", - "# Is there a visual observation ?\n", - "# Visual observation have 3 dimensions: Height, Width and number of channels\n", - "vis_obs = any(len(spec.shape) == 3 for spec in spec.observation_specs)\n", - "print(\"Is there a visual observation ?\", vis_obs)" - ], - "execution_count": 6, "outputs": [ { "name": "stdout", @@ -365,6 +331,15 @@ "Is there a visual observation ? True\n" ] } + ], + "source": [ + "# Examine the number of observations per Agent\n", + "print(\"Number of observations : \", len(spec.observation_specs))\n", + "\n", + "# Is there a visual observation ?\n", + "# Visual observation have 3 dimensions: Height, Width and number of channels\n", + "vis_obs = any(len(spec.shape) == 3 for spec in spec.observation_specs)\n", + "print(\"Is there a visual observation ?\", vis_obs)" ] }, { @@ -378,13 +353,24 @@ }, { "cell_type": "code", + "execution_count": 7, "metadata": { - "id": "M9zk1-az1L-G", "ExecuteTime": { - "start_time": "2023-10-04T12:52:52.411887Z", - "end_time": "2023-10-04T12:52:52.456259Z" - } + "end_time": "2023-10-04T12:52:52.456259Z", + "start_time": "2023-10-04T12:52:52.411887Z" + }, + "id": "M9zk1-az1L-G" }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "There are 1 discrete actions\n", + "Action number 0 has 5 different options\n" + ] + } + ], "source": [ "# Is the Action continuous or multi-discrete ?\n", "if spec.action_spec.continuous_size > 0:\n", @@ -401,17 +387,6 @@ " for action, branch_size in enumerate(spec.action_spec.discrete_branches):\n", " print(f\"Action number {action} has {branch_size} different options\")\n", "\n" - ], - "execution_count": 7, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "There are 1 discrete actions\n", - "Action number 0 has 5 different options\n" - ] - } ] }, { @@ -436,18 +411,18 @@ }, { "cell_type": "code", + "execution_count": 8, "metadata": { - "id": "ePZtcHXUrjyf", "ExecuteTime": { - "start_time": "2023-10-04T12:52:55.105403Z", - "end_time": "2023-10-04T12:52:55.111994Z" - } + "end_time": "2023-10-04T12:52:55.111994Z", + "start_time": "2023-10-04T12:52:55.105403Z" + }, + "id": "ePZtcHXUrjyf" }, + "outputs": [], "source": [ "decision_steps, terminal_steps = env.get_steps(behavior_name)" - ], - "execution_count": 8, - "outputs": [] + ] }, { "cell_type": "markdown", @@ -461,18 +436,18 @@ }, { "cell_type": "code", + "execution_count": 9, "metadata": { - "id": "KB-nxfbw337g", "ExecuteTime": { - "start_time": "2023-10-04T12:52:56.360968Z", - "end_time": "2023-10-04T12:52:56.368561Z" - } + "end_time": "2023-10-04T12:52:56.368561Z", + "start_time": "2023-10-04T12:52:56.360968Z" + }, + "id": "KB-nxfbw337g" }, + "outputs": [], "source": [ "env.set_actions(behavior_name, spec.action_spec.empty_action(len(decision_steps)))" - ], - "execution_count": 9, - "outputs": [] + ] }, { "cell_type": "markdown", @@ -486,18 +461,18 @@ }, { "cell_type": "code", + "execution_count": 10, "metadata": { - "id": "nl3K40ZR4bh2", "ExecuteTime": { - "start_time": "2023-10-04T12:52:57.609971Z", - "end_time": "2023-10-04T12:52:57.664885Z" - } + "end_time": "2023-10-04T12:52:57.664885Z", + "start_time": "2023-10-04T12:52:57.609971Z" + }, + "id": "nl3K40ZR4bh2" }, + "outputs": [], "source": [ "env.step()" - ], - "execution_count": 10, - "outputs": [] + ] }, { "cell_type": "markdown", @@ -521,29 +496,14 @@ }, { "cell_type": "code", + "execution_count": 11, "metadata": { - "id": "OJpta61TsBiO", "ExecuteTime": { - "start_time": "2023-10-04T12:53:00.550680Z", - "end_time": "2023-10-04T12:53:00.862654Z" - } + "end_time": "2023-10-04T12:53:00.862654Z", + "start_time": "2023-10-04T12:53:00.550680Z" + }, + "id": "OJpta61TsBiO" }, - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "%matplotlib inline\n", - "\n", - "for index, obs_spec in enumerate(spec.observation_specs):\n", - " if len(obs_spec.shape) == 3:\n", - " print(\"Here is the first visual observation\")\n", - " plt.imshow(np.moveaxis(decision_steps.obs[index][0, :, :, :], 0, -1))\n", - " plt.show()\n", - "\n", - "for index, obs_spec in enumerate(spec.observation_specs):\n", - " if len(obs_spec.shape) == 1:\n", - " print(\"First vector observations : \", decision_steps.obs[index][0,:])" - ], - "execution_count": 11, "outputs": [ { "name": "stdout", @@ -554,8 +514,10 @@ }, { "data": { - "text/plain": "
", - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhQAAAGfCAYAAAAH5UtjAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAk3ElEQVR4nO3df3BU1f3/8dduyG6iwEZQNkQSjD+DP6AYNKxgWzEtQx0rhVq12OKP6mgD8sNWiQpoq8bqVPFHxGox1FGaEUdQbIXaKOFrGxAiqGgbUalEYYPWZgMomww53z/8uOPCXuXmbNzN5vmYuTPm3LMn75OLm1fu3nOvxxhjBAAAYMGb6gIAAEDPR6AAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADW+nTXwNXV1brrrrsUDoc1YsQI3X///Tr99NO/9nWdnZ3avn27+vXrJ4/H013lAQCAr2GM0a5du1RQUCCv92vOQZhuUFtba3w+n3n00UfNm2++aa644gqTl5dnWlpavva1zc3NRhIbGxsbGxtbmmzNzc1f+/vbY0zyHw5WVlam0047TQ888ICkz886FBYWavr06ZozZ85XvjYSiSgvL08Xnz9Rvuzs/fYmvVQAABAT/8lAe0eHHl+6XK2trQoEAl/5yqR/5NHe3q7GxkZVVlbG2rxer8rLy9XQ0HBA/2g0qmg0Gvt6165dkiRfdrZ8PgIFAADfnMSXGhzMJQhJvyjz448/1r59+xQMBuPag8GgwuHwAf2rqqoUCARiW2FhYbJLAgAA3SzlqzwqKysViURiW3Nzc6pLAgAALiX9I4/DDz9cWVlZamlpiWtvaWlRfn7+Af39fr/8fn+Ckb64FgQAAHwz9v+9e/C/h5N+hsLn86m0tFR1dXWxts7OTtXV1SkUCiX72wEAgDTQLfehmD17tqZOnapRo0bp9NNP14IFC7Rnzx5deuml3fHtAABAinVLoLjgggv00Ucfad68eQqHw/rWt76llStXHnChJgAAyAzddqfMadOmadq0ad01PAAASCMpX+UBAAB6PgIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYM11oFizZo3OPfdcFRQUyOPxaPny5XH7jTGaN2+eBg8erNzcXJWXl2vLli3JqhcAAKQh14Fiz549GjFihKqrqxPuv/POO3XffffpoYce0rp163TooYdq/Pjx2rt3r3WxAAAgPfVx+4IJEyZowoQJCfcZY7RgwQLddNNNOu+88yRJjz32mILBoJYvX64LL7zwgNdEo1FFo9HY121tbW5LAgAAKZbUayi2bt2qcDis8vLyWFsgEFBZWZkaGhoSvqaqqkqBQCC2FRYWJrMkAADwDUhqoAiHw5KkYDAY1x4MBmP79ldZWalIJBLbmpubk1kSAAD4Brj+yCPZ/H6//H5/qssAAAAWknqGIj8/X5LU0tIS197S0hLbBwAAMk9SA0VxcbHy8/NVV1cXa2tra9O6desUCoWS+a0AAEAacf2Rx+7du/XOO+/Evt66das2bdqkAQMGqKioSDNnztStt96q4447TsXFxZo7d64KCgo0ceLEZNYNAADSiOtAsWHDBp111lmxr2fPni1Jmjp1qhYvXqzrrrtOe/bs0ZVXXqnW1laNHTtWK1euVE5OTvKqBgAAacVjjDGpLuLL2traFAgEdNlPfyyfLzvV5QAA0Gu1t3fo0SVPKRKJqH///l/Zl2d5AAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwFqfVBcA9DR9g0cnbPckaDMux040RrcP7jBOombH+hx4sxL/zeLxuB0p4SjWvZNTR3J88kFTqksArHCGAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1VnkALrlcLJEUxsXgjvU5juG048CRnHp6vU5/mzhUk5QflsMgTj8Az4E1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du0yGzduNBs3bjSSzN133202btxo3n//fWPM58t88vLyzDPPPGNef/11c9555/W4JVtXX321CQQCZvXq1XFLtz799NNYn6uuusoUFRWZF1980WzYsMGEQiETCoVSWLV7c+bMMfX19Wbr1q3m9ddfN3PmzDEej8f87W9/M8ZkxhwT+fIqD2MyY57XXnutWb16tdm6dav5xz/+YcrLy83hhx9udu7caYzJjDka8/nS3z59+pjbbrvNbNmyxTzxxBPmkEMOMY8//nisTya8Bxnz+arAoqIic/311x+wLxOO59SpU82RRx4ZWzb69NNPm8MPP9xcd911sT6pOJZpGyiMMeb+++83RUVFxufzmdNPP92sXbs21SVZeemll4ykA7apU6caYz5f6jN37lwTDAaN3+83Z599tmlqakpt0S4lmp8kU1NTE+vz2WefmV/+8pfmsMMOM4cccoj50Y9+ZHbs2JG6orvgsssuM0OHDjU+n88cccQR5uyzz46FCWMyY46J7B8oMmGeF1xwgRk8eLDx+XzmyCOPNBdccEHcvRkyYY5fWLFihTn55JON3+83JSUl5uGHH47bnwnvQcYYs2rVKiMpYe2ZcDzb2trMjBkzTFFRkcnJyTFHH320ufHGG000Go31ScWx9BjzpVtrAQAAdEFaXkMBAAB6FgIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADW/j+eh66m08pdXQAAAABJRU5ErkJggg==" + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhQAAAGfCAYAAAAH5UtjAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAk3ElEQVR4nO3df3BU1f3/8dduyG6iwEZQNkQSjD+DP6AYNKxgWzEtQx0rhVq12OKP6mgD8sNWiQpoq8bqVPFHxGox1FGaEUdQbIXaKOFrGxAiqGgbUalEYYPWZgMomww53z/8uOPCXuXmbNzN5vmYuTPm3LMn75OLm1fu3nOvxxhjBAAAYMGb6gIAAEDPR6AAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADW+nTXwNXV1brrrrsUDoc1YsQI3X///Tr99NO/9nWdnZ3avn27+vXrJ4/H013lAQCAr2GM0a5du1RQUCCv92vOQZhuUFtba3w+n3n00UfNm2++aa644gqTl5dnWlpavva1zc3NRhIbGxsbGxtbmmzNzc1f+/vbY0zyHw5WVlam0047TQ888ICkz886FBYWavr06ZozZ85XvjYSiSgvL08Xnz9Rvuzs/fYmvVQAABAT/8lAe0eHHl+6XK2trQoEAl/5yqR/5NHe3q7GxkZVVlbG2rxer8rLy9XQ0HBA/2g0qmg0Gvt6165dkiRfdrZ8PgIFAADfnMSXGhzMJQhJvyjz448/1r59+xQMBuPag8GgwuHwAf2rqqoUCARiW2FhYbJLAgAA3SzlqzwqKysViURiW3Nzc6pLAgAALiX9I4/DDz9cWVlZamlpiWtvaWlRfn7+Af39fr/8fn+Ckb64FgQAAHwz9v+9e/C/h5N+hsLn86m0tFR1dXWxts7OTtXV1SkUCiX72wEAgDTQLfehmD17tqZOnapRo0bp9NNP14IFC7Rnzx5deuml3fHtAABAinVLoLjgggv00Ucfad68eQqHw/rWt76llStXHnChJgAAyAzddqfMadOmadq0ad01PAAASCMpX+UBAAB6PgIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYM11oFizZo3OPfdcFRQUyOPxaPny5XH7jTGaN2+eBg8erNzcXJWXl2vLli3JqhcAAKQh14Fiz549GjFihKqrqxPuv/POO3XffffpoYce0rp163TooYdq/Pjx2rt3r3WxAAAgPfVx+4IJEyZowoQJCfcZY7RgwQLddNNNOu+88yRJjz32mILBoJYvX64LL7zwgNdEo1FFo9HY121tbW5LAgAAKZbUayi2bt2qcDis8vLyWFsgEFBZWZkaGhoSvqaqqkqBQCC2FRYWJrMkAADwDUhqoAiHw5KkYDAY1x4MBmP79ldZWalIJBLbmpubk1kSAAD4Brj+yCPZ/H6//H5/qssAAAAWknqGIj8/X5LU0tIS197S0hLbBwAAMk9SA0VxcbHy8/NVV1cXa2tra9O6desUCoWS+a0AAEAacf2Rx+7du/XOO+/Evt66das2bdqkAQMGqKioSDNnztStt96q4447TsXFxZo7d64KCgo0ceLEZNYNAADSiOtAsWHDBp111lmxr2fPni1Jmjp1qhYvXqzrrrtOe/bs0ZVXXqnW1laNHTtWK1euVE5OTvKqBgAAacVjjDGpLuLL2traFAgEdNlPfyyfLzvV5QAA0Gu1t3fo0SVPKRKJqH///l/Zl2d5AAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwFqfVBcA9DR9g0cnbPckaDMux040RrcP7jBOombH+hx4sxL/zeLxuB0p4SjWvZNTR3J88kFTqksArHCGAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1VnkALrlcLJEUxsXgjvU5juG048CRnHp6vU5/mzhUk5QflsMgTj8Az4E1Jm0VDgDOUAAAAHsECgAAYI1AAQAArBEoAACANQIFAACwxioPwKVkLFBIxkoR12M4LfNwep5Fgv7erCxXQzh9T+NquYS7tRVe52Ksxz749TBA78MZCgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWWOWBXqNf8GhX/ZOymuPgF1B89TiJxnDq7Liaw11/b9bB/73hdj5ufrgeh86Ozw9xtRQjOU9gMQ4/XDerPwYMOSEptXzyQVNSxgHc4gwFAACwRqAAAADWCBQAAMAagQIAAFhzFSiqqqp02mmnqV+/fho0aJAmTpyopqb4C4D27t2riooKDRw4UH379tXkyZPV0tKS1KIBAEB6cRUo6uvrVVFRobVr1+qFF15QR0eHvv/972vPnj2xPrNmzdKKFSu0dOlS1dfXa/v27Zo0aVLSCwdc8yTejBJvDt2dh/d4DtgcB3ccI/GWcAhjEm8OnLp7vd6Em8MoiTenwZOwebzehJvTj9bxR+72BW6Om8MG9Caulo2uXLky7uvFixdr0KBBamxs1Le//W1FIhEtWrRIS5Ys0bhx4yRJNTU1GjZsmNauXavRo0cnr3IAAJA2rK6hiEQikqQBAwZIkhobG9XR0aHy8vJYn5KSEhUVFamhoSHhGNFoVG1tbXEbAADoWbocKDo7OzVz5kyNGTNGJ598siQpHA7L5/MpLy8vrm8wGFQ4HE44TlVVlQKBQGwrLCzsakkAACBFuhwoKioqtHnzZtXW1loVUFlZqUgkEtuam5utxgMAAN+8Lt16e9q0aXruuee0Zs0aDRkyJNaen5+v9vZ2tba2xp2laGlpUX5+fsKx/H6//H5/V8oA3HF7R2qHdk8S7qfteggXYzv1zHK80PLgB/qKSz7dje0gy5uVYGiXB85B4lHc3TLbw6WWgCNX7zDGGE2bNk3Lli3Tiy++qOLi4rj9paWlys7OVl1dXaytqalJ27ZtUygUSk7FAAAg7bg6Q1FRUaElS5bomWeeUb9+/WLXRQQCAeXm5ioQCOjyyy/X7NmzNWDAAPXv31/Tp09XKBRihQcAABnMVaBYuHChJOm73/1uXHtNTY0uueQSSdI999wjr9eryZMnKxqNavz48XrwwQeTUiwAAEhPrgKFOYjPcXNyclRdXa3q6uouFwUAAHoWnuUBAACsdWmVB9AjuVxa4XXob9ysaHAYY823futQi8MwbqK/ywUXjt3dTDPB4oyUcTjMrn6GLp218ZbuGxzoIThDAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAaqzzQizg8zcHrsJrD5WqJRM/4cLx3Szeu5kjGqg2n/p7ufsdwU6PTz4rHbQApwRkKAABgjUABAACsESgAAIA1AgUAALBGoAAAANZY5YFew+O0hMJhJYbzYoGDf8aH06IFt8+VOHPj3ITfMWEdLldz/L8RtyZsT7SiY8yGGxL2zcpyeitxtxRlzcgEzzhxOBDffnVewvZEq20kyeuwmieR1SNvPui+AD7HGQoAAGCNQAEAAKwRKAAAgDUCBQAAsEagAAAA1ljlgV7E6QEaLkdxWkXh9lkZrsZIsILE9bM5HFazZB18LVnexJ0dn1niVqJj4fBnj9Nhc7OaA0DycIYCAABYI1AAAABrBAoAAGCNQAEAAKxxUSZ6kVRcfenu1tOuS3HROdGtwb96HBdjON5j/ODHluTqTxyv1+lW6gc/hhxu0w3APc5QAAAAawQKAABgjUABAACsESgAAIA1AgUAALDGKg/0Gm4XHLiVaByvx+V9o13cHdzpdteOa1O6cdGKY3cXtxJ3O77b4+ZJsKKDNR5A8nCGAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1VnkASXjGhSR5vQnWDCRnaK351q0HtDktIHE9uIvuier4ylqS8CeL09j1p95sPziApOEMBQAAsEagAAAA1ggUAADAGoECAABYI1AAAABrrPJAr+H22Q9O/T1epxyerKeCJPieWS6+nWPhDt1djNOdqzk+/wZJGgfAN44zFAAAwBqBAgAAWCNQAAAAawQKAABgzdVFmQsXLtTChQv1n//8R5J00kknad68eZowYYIkae/evbr22mtVW1uraDSq8ePH68EHH1QwGEx64UDSON1K25P4CkFXl146jOE0iNNFj2MbbzygzevQ2TgN7tDseDvtBBeCjt1wYB2S5HW4UNWp3fEW46W3OOw50FkbD76vWy+NnN9tYwOZytUZiiFDhuiOO+5QY2OjNmzYoHHjxum8887Tm2++KUmaNWuWVqxYoaVLl6q+vl7bt2/XpEmTuqVwAACQPlydoTj33HPjvr7tttu0cOFCrV27VkOGDNGiRYu0ZMkSjRs3TpJUU1OjYcOGae3atRo9enTyqgYAAGmly9dQ7Nu3T7W1tdqzZ49CoZAaGxvV0dGh8vLyWJ+SkhIVFRWpoaHBcZxoNKq2tra4DQAA9CyuA8Ubb7yhvn37yu/366qrrtKyZct04oknKhwOy+fzKS8vL65/MBhUOBx2HK+qqkqBQCC2FRYWup4EAABILdeB4oQTTtCmTZu0bt06XX311Zo6dareeuutLhdQWVmpSCQS25qbm7s8FgAASA3Xt972+Xw69thjJUmlpaVav3697r33Xl1wwQVqb29Xa2tr3FmKlpYW5efnO47n9/vl9/vdVw4kicfr8n7PTis0EqzocLyttcso7/UeuOTCOA3ueOvtxPNMeFtvKeFtsJO1mqM7b1MOIDWs70PR2dmpaDSq0tJSZWdnq66uLravqalJ27ZtUygUsv02AAAgjbk6Q1FZWakJEyaoqKhIu3bt0pIlS7R69WqtWrVKgUBAl19+uWbPnq0BAwaof//+mj59ukKhECs8AADIcK4Cxc6dO/Xzn/9cO3bsUCAQ0PDhw7Vq1Sp973vfkyTdc8898nq9mjx5ctyNrQAAQGZzFSgWLVr0lftzcnJUXV2t6upqq6IAAEDPwrM8AACANderPICeKtEqjK/ksIrC+Rkf3bly4eDHdpqnY30ufizJWs3hNA6Anov/qwEAgDUCBQAAsEagAAAA1ggUAADAGoECAABYY5UHeg3HRR6Oz9twyNuOD+g48Bt43K78cFGj46oVx/rsJWs1h8fN0hIAPQJnKAAAgDUCBQAAsEagAAAA1ggUAADAGoECAABYY5UHej3nZ184vcCh3c1KDJeLHNac+tuDH8PtahYnCcZZU3qLy0G6z0sj56e6BABfwhkKAABgjUABAACsESgAAIA1AgUAALDGRZnoNTwep/yc+GpFj8NFjI433k50AWayboPdjdHf8ccCAC7wVgIAAKwRKAAAgDUCBQAAsEagAAAA1ggUAADAGqs8AJc8Dve2Triew+Uttp36f+fVA28z7XxXb3e3Eq8/9eavLesLZ23s3ltvu7mddnfWwm29Afc4QwEAAKwRKAAAgDUCBQAAsEagAAAA1ggUAADAGqs8AKelFW4f5pFwZMelGK54Ey3pcBojSY8PAQA3OEMBAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqrPAC3XD1DI/GSC6fncLj9nq6GcP1NAeDgcYYCAABYI1AAAABrBAoAAGCNQAEAAKxxUSZ6Dfd3qu6hFzE6XHzZQ2cDoIfgDAUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAa1arPO644w5VVlZqxowZWrBggSRp7969uvbaa1VbW6toNKrx48frwQcfVDAYTEa9wDfG7aoIh5ts2xciafXIm5Myjq2XRs5PdQkx6VQLAIszFOvXr9cf/vAHDR8+PK591qxZWrFihZYuXar6+npt375dkyZNsi4UAACkry4Fit27d2vKlCl65JFHdNhhh8XaI5GIFi1apLvvvlvjxo1TaWmpampq9M9//lNr165NWtEAACC9dClQVFRU6JxzzlF5eXlce2Njozo6OuLaS0pKVFRUpIaGhoRjRaNRtbW1xW0AAKBncX0NRW1trV599VWtX7/+gH3hcFg+n095eXlx7cFgUOFwOOF4VVVVuuWWW9yWAQAA0oirMxTNzc2aMWOGnnjiCeXk5CSlgMrKSkUikdjW3NyclHEBAMA3x9UZisbGRu3cuVOnnnpqrG3fvn1as2aNHnjgAa1atUrt7e1qbW2NO0vR0tKi/Pz8hGP6/X75/f6uVQ8kQbKeccGzMgD0Zq4Cxdlnn6033ngjru3SSy9VSUmJrr/+ehUWFio7O1t1dXWaPHmyJKmpqUnbtm1TKBRKXtUAACCtuAoU/fr108knnxzXduihh2rgwIGx9ssvv1yzZ8/WgAED1L9/f02fPl2hUEijR49OXtUAACCtJP3x5ffcc4+8Xq8mT54cd2MrAACQuawDxerVq+O+zsnJUXV1taqrq22HBgAAPQTP8gAAANaS/pEHgK931kbuvQIgs3CGAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwFqfVBcAfFM++aApKeMMGHJCUsYBvixZ/z6BVOEMBQAAsEagAAAA1ggUAADAGoECAABYI1AAAABrBAoAAGCNQAEAAKwRKAAAgDUCBQAAsEagAAAA1ggUAADAGoECAABYI1AAAABrBAoAAGCNQAEAAKwRKAAAgLU+qS4A6Gk++aAp1SUAQNrhDAUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwJqrQHHzzTfL4/HEbSUlJbH9e/fuVUVFhQYOHKi+fftq8uTJamlpSXrRAAAgvbg+Q3HSSSdpx44dse3ll1+O7Zs1a5ZWrFihpUuXqr6+Xtu3b9ekSZOSWjAAAEg/rp822qdPH+Xn5x/QHolEtGjRIi1ZskTjxo2TJNXU1GjYsGFau3atRo8enXC8aDSqaDQa+7qtrc1tSQAAIMVcn6HYsmWLCgoKdPTRR2vKlCnatm2bJKmxsVEdHR0qLy+P9S0pKVFRUZEaGhocx6uqqlIgEIhthYWFXZgGAABIJVeBoqysTIsXL9bKlSu1cOFCbd26VWeeeaZ27dqlcDgsn8+nvLy8uNcEg0GFw2HHMSsrKxWJRGJbc3NzlyYCAABSx9VHHhMmTIj99/Dhw1VWVqahQ4fqySefVG5ubpcK8Pv98vv9XXotAABID1bLRvPy8nT88cfrnXfeUX5+vtrb29Xa2hrXp6WlJeE1FwAAIHNYBYrdu3fr3Xff1eDBg1VaWqrs7GzV1dXF9jc1NWnbtm0KhULWhQIAgPTl6iOPX/3qVzr33HM1dOhQbd++XfPnz1dWVpYuuugiBQIBXX755Zo9e7YGDBig/v37a/r06QqFQo4rPAAAQGZwFSg++OADXXTRRfrvf/+rI444QmPHjtXatWt1xBFHSJLuueceeb1eTZ48WdFoVOPHj9eDDz7YLYUDAID04THGmFQX8WVtbW0KBAK67Kc/ls+XnepyAADotdrbO/TokqcUiUTUv3//r+zLszwAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAa64DxYcffqiLL75YAwcOVG5urk455RRt2LAhtt8Yo3nz5mnw4MHKzc1VeXm5tmzZktSiAQBAenEVKP73v/9pzJgxys7O1vPPP6+33npLv//973XYYYfF+tx5552677779NBDD2ndunU69NBDNX78eO3duzfpxQMAgPTQx03n3/3udyosLFRNTU2srbi4OPbfxhgtWLBAN910k8477zxJ0mOPPaZgMKjly5frwgsvTFLZAAAgnbg6Q/Hss89q1KhROv/88zVo0CCNHDlSjzzySGz/1q1bFQ6HVV5eHmsLBAIqKytTQ0NDwjGj0aja2triNgAA0LO4ChTvvfeeFi5cqOOOO06rVq3S1VdfrWuuuUZ/+tOfJEnhcFiSFAwG414XDAZj+/ZXVVWlQCAQ2woLC7syDwAAkEKuAkVnZ6dOPfVU3X777Ro5cqSuvPJKXXHFFXrooYe6XEBlZaUikUhsa25u7vJYAAAgNVwFisGDB+vEE0+Maxs2bJi2bdsmScrPz5cktbS0xPVpaWmJ7duf3+9X//794zYAANCzuAoUY8aMUVNTU1zb22+/raFDh0r6/ALN/Px81dXVxfa3tbVp3bp1CoVCSSgXAACkI1erPGbNmqUzzjhDt99+u37yk5/olVde0cMPP6yHH35YkuTxeDRz5kzdeuutOu6441RcXKy5c+eqoKBAEydO7I76AQBAGnAVKE477TQtW7ZMlZWV+s1vfqPi4mItWLBAU6ZMifW57rrrtGfPHl155ZVqbW3V2LFjtXLlSuXk5CS9eAAAkB48xhiT6iK+rK2tTYFAQJf99Mfy+bJTXQ4AAL1We3uHHl3ylCKRyNde48izPAAAgDUCBQAAsEagAAAA1ggUAADAGoECAABYI1AAAABrBAoAAGDN1Y2tvlme/9u+LK1umQEAQIbZ//fu/l874wwFAACwRqAAAADWCBQAAMAagQIAAFhLu4syv3hWWXtHR6K932wxAAD0KvEXYX7xu/hgniOadk8b/eCDD1RYWJjqMgAAwP9pbm7WkCFDvrJP2gWKzs5Obd++Xf369dOuXbtUWFio5ubmr31sak/W1tbGPDNEb5ijxDwzTW+YZ2+Yo5T8eRpjtGvXLhUUFMjr/eqrJNLuIw+v1xtLQR7P56de+vfvn9H/AL7APDNHb5ijxDwzTW+YZ2+Yo5TceQYCgYPqx0WZAADAGoECAABYS+tA4ff7NX/+fPn9/lSX0q2YZ+boDXOUmGem6Q3z7A1zlFI7z7S7KBMAAPQ8aX2GAgAA9AwECgAAYI1AAQAArBEoAACANQIFAACwltaBorq6WkcddZRycnJUVlamV155JdUlWVmzZo3OPfdcFRQUyOPxaPny5XH7jTGaN2+eBg8erNzcXJWXl2vLli2pKbaLqqqqdNppp6lfv34aNGiQJk6cqKamprg+e/fuVUVFhQYOHKi+fftq8uTJamlpSVHFXbNw4UINHz48dje6UCik559/PrY/E+a4vzvuuEMej0czZ86MtWXCPG+++WZ5PJ64raSkJLY/E+b4hQ8//FAXX3yxBg4cqNzcXJ1yyinasGFDbH8mvAcdddRRBxxPj8ejiooKSZlxPPft26e5c+equLhYubm5OuaYY/Tb3/427gFeKTmWJk3V1tYan89nHn30UfPmm2+aK664wuTl5ZmWlpZUl9Zlf/3rX82NN95onn76aSPJLFu2LG7/HXfcYQKBgFm+fLl57bXXzA9/+ENTXFxsPvvss9QU3AXjx483NTU1ZvPmzWbTpk3mBz/4gSkqKjK7d++O9bnqqqtMYWGhqaurMxs2bDCjR482Z5xxRgqrdu/ZZ581f/nLX8zbb79tmpqazA033GCys7PN5s2bjTGZMccve+WVV8xRRx1lhg8fbmbMmBFrz4R5zp8/35x00klmx44dse2jjz6K7c+EORpjzCeffGKGDh1qLrnkErNu3Trz3nvvmVWrVpl33nkn1icT3oN27twZdyxfeOEFI8m89NJLxpjMOJ633XabGThwoHnuuefM1q1bzdKlS03fvn3NvffeG+uTimOZtoHi9NNPNxUVFbGv9+3bZwoKCkxVVVUKq0qe/QNFZ2enyc/PN3fddVesrbW11fj9fvPnP/85BRUmx86dO40kU19fb4z5fE7Z2dlm6dKlsT7/+te/jCTT0NCQqjKT4rDDDjN//OMfM26Ou3btMscdd5x54YUXzHe+851YoMiUec6fP9+MGDEi4b5MmaMxxlx//fVm7Nixjvsz9T1oxowZ5phjjjGdnZ0ZczzPOeccc9lll8W1TZo0yUyZMsUYk7pjmZYfebS3t6uxsVHl5eWxNq/Xq/LycjU0NKSwsu6zdetWhcPhuDkHAgGVlZX16DlHIhFJ0oABAyRJjY2N6ujoiJtnSUmJioqKeuw89+3bp9raWu3Zs0ehUCjj5lhRUaFzzjknbj5SZh3LLVu2qKCgQEcffbSmTJmibdu2ScqsOT777LMaNWqUzj//fA0aNEgjR47UI488Etufie9B7e3tevzxx3XZZZfJ4/FkzPE844wzVFdXp7fffluS9Nprr+nll1/WhAkTJKXuWKbd00Yl6eOPP9a+ffsUDAbj2oPBoP7973+nqKruFQ6HJSnhnL/Y19N0dnZq5syZGjNmjE4++WRJn8/T5/MpLy8vrm9PnOcbb7yhUCikvXv3qm/fvlq2bJlOPPFEbdq0KWPmWFtbq1dffVXr168/YF+mHMuysjItXrxYJ5xwgnbs2KFbbrlFZ555pjZv3pwxc5Sk9957TwsXLtTs2bN1ww03aP369brmmmvk8/k0derUjHwPWr58uVpbW3XJJZdIypx/s3PmzFFbW5tKSkqUlZWlffv26bbbbtOUKVMkpe73SVoGCmSGiooKbd68WS+//HKqS+kWJ5xwgjZt2qRIJKKnnnpKU6dOVX19farLSprm5mbNmDFDL7zwgnJyclJdTrf54q86SRo+fLjKyso0dOhQPfnkk8rNzU1hZcnV2dmpUaNG6fbbb5ckjRw5Ups3b9ZDDz2kqVOnpri67rFo0SJNmDBBBQUFqS4lqZ588kk98cQTWrJkiU466SRt2rRJM2fOVEFBQUqPZVp+5HH44YcrKyvrgCtvW1palJ+fn6KqutcX88qUOU+bNk3PPfecXnrpJQ0ZMiTWnp+fr/b2drW2tsb174nz9Pl8OvbYY1VaWqqqqiqNGDFC9957b8bMsbGxUTt37tSpp56qPn36qE+fPqqvr9d9992nPn36KBgMZsQ895eXl6fjjz9e77zzTsYcS0kaPHiwTjzxxLi2YcOGxT7eybT3oPfff19///vf9Ytf/CLWlinH89e//rXmzJmjCy+8UKeccop+9rOfadasWaqqqpKUumOZloHC5/OptLRUdXV1sbbOzk7V1dUpFAqlsLLuU1xcrPz8/Lg5t7W1ad26dT1qzsYYTZs2TcuWLdOLL76o4uLiuP2lpaXKzs6Om2dTU5O2bdvWo+aZSGdnp6LRaMbM8eyzz9Ybb7yhTZs2xbZRo0ZpypQpsf/OhHnub/fu3Xr33Xc1ePDgjDmWkjRmzJgDlnC//fbbGjp0qKTMeQ/6Qk1NjQYNGqRzzjkn1pYpx/PTTz+V1xv/6zsrK0udnZ2SUngsu+1yT0u1tbXG7/ebxYsXm7feestceeWVJi8vz4TD4VSX1mW7du0yGzduNBs3bjSSzN133202btxo3n//fWPM58t88vLyzDPPPGNef/11c9555/W4JVtXX321CQQCZvXq1XFLtz799NNYn6uuusoUFRWZF1980WzYsMGEQiETCoVSWLV7c+bMMfX19Wbr1q3m9ddfN3PmzDEej8f87W9/M8ZkxhwT+fIqD2MyY57XXnutWb16tdm6dav5xz/+YcrLy83hhx9udu7caYzJjDka8/nS3z59+pjbbrvNbNmyxTzxxBPmkEMOMY8//nisTya8Bxnz+arAoqIic/311x+wLxOO59SpU82RRx4ZWzb69NNPm8MPP9xcd911sT6pOJZpGyiMMeb+++83RUVFxufzmdNPP92sXbs21SVZeemll4ykA7apU6caYz5f6jN37lwTDAaN3+83Z599tmlqakpt0S4lmp8kU1NTE+vz2WefmV/+8pfmsMMOM4cccoj50Y9+ZHbs2JG6orvgsssuM0OHDjU+n88cccQR5uyzz46FCWMyY46J7B8oMmGeF1xwgRk8eLDx+XzmyCOPNBdccEHcvRkyYY5fWLFihTn55JON3+83JSUl5uGHH47bnwnvQcYYs2rVKiMpYe2ZcDzb2trMjBkzTFFRkcnJyTFHH320ufHGG000Go31ScWx9BjzpVtrAQAAdEFaXkMBAAB6FgIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADW/j+eh66m08pdXQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] }, "metadata": {}, "output_type": "display_data" @@ -567,6 +529,21 @@ "First vector observations : [1. 0.]\n" ] } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "%matplotlib inline\n", + "\n", + "for index, obs_spec in enumerate(spec.observation_specs):\n", + " if len(obs_spec.shape) == 3:\n", + " print(\"Here is the first visual observation\")\n", + " plt.imshow(np.moveaxis(decision_steps.obs[index][0, :, :, :], 0, -1))\n", + " plt.show()\n", + "\n", + "for index, obs_spec in enumerate(spec.observation_specs):\n", + " if len(obs_spec.shape) == 1:\n", + " print(\"First vector observations : \", decision_steps.obs[index][0,:])" ] }, { @@ -580,13 +557,25 @@ }, { "cell_type": "code", + "execution_count": 12, "metadata": { - "id": "a2uQUsoMtIUK", "ExecuteTime": { - "start_time": "2023-10-04T12:53:02.785602Z", - "end_time": "2023-10-04T12:53:04.145406Z" - } + "end_time": "2023-10-04T12:53:04.145406Z", + "start_time": "2023-10-04T12:53:02.785602Z" + }, + "id": "a2uQUsoMtIUK" }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Total rewards for episode 0 is -1.1499999966472387\n", + "Total rewards for episode 1 is -1.5599999874830246\n", + "Total rewards for episode 2 is -1.049999998882413\n" + ] + } + ], "source": [ "for episode in range(3):\n", " env.reset()\n", @@ -617,18 +606,6 @@ " episode_rewards += terminal_steps[tracked_agent].reward\n", " done = True\n", " print(f\"Total rewards for episode {episode} is {episode_rewards}\")\n" - ], - "execution_count": 12, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Total rewards for episode 0 is -1.1499999966472387\n", - "Total rewards for episode 1 is -1.5599999874830246\n", - "Total rewards for episode 2 is -1.049999998882413\n" - ] - } ] }, { @@ -642,18 +619,14 @@ }, { "cell_type": "code", + "execution_count": 13, "metadata": { - "id": "vdWG6_SqtNtv", "ExecuteTime": { - "start_time": "2023-10-04T12:53:06.093669Z", - "end_time": "2023-10-04T12:53:06.416573Z" - } + "end_time": "2023-10-04T12:53:06.416573Z", + "start_time": "2023-10-04T12:53:06.093669Z" + }, + "id": "vdWG6_SqtNtv" }, - "source": [ - "env.close()\n", - "print(\"Closed environment\")\n" - ], - "execution_count": 13, "outputs": [ { "name": "stdout", @@ -662,7 +635,36 @@ "Closed environment\n" ] } + ], + "source": [ + "env.close()\n", + "print(\"Closed environment\")\n" ] } - ] + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "Colab-UnityEnvironment-1-Run.ipynb", + "private_outputs": true, + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "pycharm": { + "stem_cell": { + "cell_type": "raw", + "metadata": { + "collapsed": false + }, + "source": [] + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 } From d9d34f9904d965795a3d8d7aaec05120c44d0ae2 Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 18 Dec 2025 16:13:12 -0500 Subject: [PATCH 25/26] Update colab --- colab/Colab_UnityEnvironment_1_Run.ipynb | 366 +++++++++++------------ 1 file changed, 182 insertions(+), 184 deletions(-) diff --git a/colab/Colab_UnityEnvironment_1_Run.ipynb b/colab/Colab_UnityEnvironment_1_Run.ipynb index cbb810138f..9ac80f920f 100644 --- a/colab/Colab_UnityEnvironment_1_Run.ipynb +++ b/colab/Colab_UnityEnvironment_1_Run.ipynb @@ -1,4 +1,29 @@ { + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "name": "Colab-UnityEnvironment-1-Run.ipynb", + "private_outputs": true, + "provenance": [], + "collapsed_sections": [], + "toc_visible": true + }, + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3" + }, + "pycharm": { + "stem_cell": { + "cell_type": "raw", + "source": [], + "metadata": { + "collapsed": false + } + } + } + }, "cells": [ { "cell_type": "markdown", @@ -21,11 +46,9 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "id": "htb-p1hSNX7D" }, - "outputs": [], "source": [ "#@title Install Rendering Dependencies { display-mode: \"form\" }\n", "#@markdown (You only need to run this code when using Colab's hosted runtime)\n", @@ -99,7 +122,9 @@ " !bash frame-buffer start\n", " os.environ[\"DISPLAY\"] = \":1\"\n", "pro_bar.update(progress(100, 100))" - ] + ], + "execution_count": null, + "outputs": [] }, { "cell_type": "markdown", @@ -112,14 +137,22 @@ }, { "cell_type": "code", - "execution_count": 1, "metadata": { + "id": "N8yfQqkbebQ5", "ExecuteTime": { - "end_time": "2023-10-04T12:52:21.642251Z", - "start_time": "2023-10-04T12:52:21.641839Z" - }, - "id": "N8yfQqkbebQ5" + "start_time": "2023-10-04T12:52:21.641839Z", + "end_time": "2023-10-04T12:52:21.642251Z" + } }, + "source": [ + "try:\n", + " import mlagents\n", + " print(\"ml-agents already installed\")\n", + "except ImportError:\n", + " !python -m pip install -q mlagents==1.1.0\n", + " print(\"Installed ml-agents\")" + ], + "execution_count": 1, "outputs": [ { "name": "stdout", @@ -128,14 +161,6 @@ "ml-agents already installed\n" ] } - ], - "source": [ - "try:\n", - " import mlagents\n", - " print(\"ml-agents already installed\")\n", - "except ImportError:\n", - " !python -m pip install -q mlagents==1.1.0\n", - " print(\"Installed ml-agents\")" ] }, { @@ -149,19 +174,19 @@ }, { "cell_type": "code", - "execution_count": 2, "metadata": { + "id": "DpZPbRvRuLZv", "ExecuteTime": { - "end_time": "2023-10-04T12:52:23.339236Z", - "start_time": "2023-10-04T12:52:23.330185Z" - }, - "id": "DpZPbRvRuLZv" + "start_time": "2023-10-04T12:52:23.330185Z", + "end_time": "2023-10-04T12:52:23.339236Z" + } }, - "outputs": [], "source": [ "#@title Select Environment { display-mode: \"form\" }\n", "env_id = \"GridWorld\" #@param ['Basic', '3DBall', '3DBallHard', 'GridWorld', 'Hallway', 'VisualHallway', 'CrawlerDynamicTarget', 'CrawlerStaticTarget', 'Bouncer', 'SoccerTwos', 'PushBlock', 'VisualPushBlock', 'WallJump', 'Tennis', 'Reacher', 'Pyramids', 'VisualPyramids', 'Walker', 'FoodCollector', 'VisualFoodCollector', 'StrikersVsGoalie', 'WormStaticTarget', 'WormDynamicTarget']\n" - ] + ], + "execution_count": 2, + "outputs": [] }, { "cell_type": "markdown", @@ -174,14 +199,27 @@ }, { "cell_type": "code", - "execution_count": 3, "metadata": { + "id": "YSf-WhxbqtLw", "ExecuteTime": { - "end_time": "2023-10-04T12:52:26.115543Z", - "start_time": "2023-10-04T12:52:25.056933Z" - }, - "id": "YSf-WhxbqtLw" + "start_time": "2023-10-04T12:52:25.056933Z", + "end_time": "2023-10-04T12:52:26.115543Z" + } }, + "source": [ + "# -----------------\n", + "# This code is used to close an env that might not have been closed before\n", + "try:\n", + " env.close()\n", + "except:\n", + " pass\n", + "# -----------------\n", + "\n", + "from mlagents_envs.registry import default_registry\n", + "\n", + "env = default_registry[env_id].make(no_graphics=True)" + ], + "execution_count": 3, "outputs": [ { "name": "stdout", @@ -219,19 +257,6 @@ " \"memorysetup-temp-allocator-size-gfx=262144\"\n" ] } - ], - "source": [ - "# -----------------\n", - "# This code is used to close an env that might not have been closed before\n", - "try:\n", - " env.close()\n", - "except:\n", - " pass\n", - "# -----------------\n", - "\n", - "from mlagents_envs.registry import default_registry\n", - "\n", - "env = default_registry[env_id].make()" ] }, { @@ -246,18 +271,18 @@ }, { "cell_type": "code", - "execution_count": 4, "metadata": { + "id": "dhtl0mpeqxYi", "ExecuteTime": { - "end_time": "2023-10-04T12:52:41.038983Z", - "start_time": "2023-10-04T12:52:40.819560Z" - }, - "id": "dhtl0mpeqxYi" + "start_time": "2023-10-04T12:52:40.819560Z", + "end_time": "2023-10-04T12:52:41.038983Z" + } }, - "outputs": [], "source": [ "env.reset()" - ] + ], + "execution_count": 4, + "outputs": [] }, { "cell_type": "markdown", @@ -279,14 +304,20 @@ }, { "cell_type": "code", - "execution_count": 5, "metadata": { + "id": "a7KatdThq7OV", "ExecuteTime": { - "end_time": "2023-10-04T12:52:47.820527Z", - "start_time": "2023-10-04T12:52:47.812858Z" - }, - "id": "a7KatdThq7OV" + "start_time": "2023-10-04T12:52:47.812858Z", + "end_time": "2023-10-04T12:52:47.820527Z" + } }, + "source": [ + "# We will only consider the first Behavior\n", + "behavior_name = list(env.behavior_specs)[0]\n", + "print(f\"Name of the behavior : {behavior_name}\")\n", + "spec = env.behavior_specs[behavior_name]" + ], + "execution_count": 5, "outputs": [ { "name": "stdout", @@ -295,12 +326,6 @@ "Name of the behavior : GridWorld?team=0\n" ] } - ], - "source": [ - "# We will only consider the first Behavior\n", - "behavior_name = list(env.behavior_specs)[0]\n", - "print(f\"Name of the behavior : {behavior_name}\")\n", - "spec = env.behavior_specs[behavior_name]" ] }, { @@ -314,14 +339,23 @@ }, { "cell_type": "code", - "execution_count": 6, "metadata": { + "id": "PqDTV5mSrJF5", "ExecuteTime": { - "end_time": "2023-10-04T12:52:50.596936Z", - "start_time": "2023-10-04T12:52:50.586284Z" - }, - "id": "PqDTV5mSrJF5" + "start_time": "2023-10-04T12:52:50.586284Z", + "end_time": "2023-10-04T12:52:50.596936Z" + } }, + "source": [ + "# Examine the number of observations per Agent\n", + "print(\"Number of observations : \", len(spec.observation_specs))\n", + "\n", + "# Is there a visual observation ?\n", + "# Visual observation have 3 dimensions: Height, Width and number of channels\n", + "vis_obs = any(len(spec.shape) == 3 for spec in spec.observation_specs)\n", + "print(\"Is there a visual observation ?\", vis_obs)" + ], + "execution_count": 6, "outputs": [ { "name": "stdout", @@ -331,15 +365,6 @@ "Is there a visual observation ? True\n" ] } - ], - "source": [ - "# Examine the number of observations per Agent\n", - "print(\"Number of observations : \", len(spec.observation_specs))\n", - "\n", - "# Is there a visual observation ?\n", - "# Visual observation have 3 dimensions: Height, Width and number of channels\n", - "vis_obs = any(len(spec.shape) == 3 for spec in spec.observation_specs)\n", - "print(\"Is there a visual observation ?\", vis_obs)" ] }, { @@ -353,24 +378,13 @@ }, { "cell_type": "code", - "execution_count": 7, "metadata": { + "id": "M9zk1-az1L-G", "ExecuteTime": { - "end_time": "2023-10-04T12:52:52.456259Z", - "start_time": "2023-10-04T12:52:52.411887Z" - }, - "id": "M9zk1-az1L-G" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "There are 1 discrete actions\n", - "Action number 0 has 5 different options\n" - ] + "start_time": "2023-10-04T12:52:52.411887Z", + "end_time": "2023-10-04T12:52:52.456259Z" } - ], + }, "source": [ "# Is the Action continuous or multi-discrete ?\n", "if spec.action_spec.continuous_size > 0:\n", @@ -387,6 +401,17 @@ " for action, branch_size in enumerate(spec.action_spec.discrete_branches):\n", " print(f\"Action number {action} has {branch_size} different options\")\n", "\n" + ], + "execution_count": 7, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "There are 1 discrete actions\n", + "Action number 0 has 5 different options\n" + ] + } ] }, { @@ -411,18 +436,18 @@ }, { "cell_type": "code", - "execution_count": 8, "metadata": { + "id": "ePZtcHXUrjyf", "ExecuteTime": { - "end_time": "2023-10-04T12:52:55.111994Z", - "start_time": "2023-10-04T12:52:55.105403Z" - }, - "id": "ePZtcHXUrjyf" + "start_time": "2023-10-04T12:52:55.105403Z", + "end_time": "2023-10-04T12:52:55.111994Z" + } }, - "outputs": [], "source": [ "decision_steps, terminal_steps = env.get_steps(behavior_name)" - ] + ], + "execution_count": 8, + "outputs": [] }, { "cell_type": "markdown", @@ -436,18 +461,18 @@ }, { "cell_type": "code", - "execution_count": 9, "metadata": { + "id": "KB-nxfbw337g", "ExecuteTime": { - "end_time": "2023-10-04T12:52:56.368561Z", - "start_time": "2023-10-04T12:52:56.360968Z" - }, - "id": "KB-nxfbw337g" + "start_time": "2023-10-04T12:52:56.360968Z", + "end_time": "2023-10-04T12:52:56.368561Z" + } }, - "outputs": [], "source": [ "env.set_actions(behavior_name, spec.action_spec.empty_action(len(decision_steps)))" - ] + ], + "execution_count": 9, + "outputs": [] }, { "cell_type": "markdown", @@ -461,18 +486,18 @@ }, { "cell_type": "code", - "execution_count": 10, "metadata": { + "id": "nl3K40ZR4bh2", "ExecuteTime": { - "end_time": "2023-10-04T12:52:57.664885Z", - "start_time": "2023-10-04T12:52:57.609971Z" - }, - "id": "nl3K40ZR4bh2" + "start_time": "2023-10-04T12:52:57.609971Z", + "end_time": "2023-10-04T12:52:57.664885Z" + } }, - "outputs": [], "source": [ "env.step()" - ] + ], + "execution_count": 10, + "outputs": [] }, { "cell_type": "markdown", @@ -496,14 +521,29 @@ }, { "cell_type": "code", - "execution_count": 11, "metadata": { + "id": "OJpta61TsBiO", "ExecuteTime": { - "end_time": "2023-10-04T12:53:00.862654Z", - "start_time": "2023-10-04T12:53:00.550680Z" - }, - "id": "OJpta61TsBiO" + "start_time": "2023-10-04T12:53:00.550680Z", + "end_time": "2023-10-04T12:53:00.862654Z" + } }, + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "%matplotlib inline\n", + "\n", + "for index, obs_spec in enumerate(spec.observation_specs):\n", + " if len(obs_spec.shape) == 3:\n", + " print(\"Here is the first visual observation\")\n", + " plt.imshow(np.moveaxis(decision_steps.obs[index][0, :, :, :], 0, -1))\n", + " plt.show()\n", + "\n", + "for index, obs_spec in enumerate(spec.observation_specs):\n", + " if len(obs_spec.shape) == 1:\n", + " print(\"First vector observations : \", decision_steps.obs[index][0,:])" + ], + "execution_count": 11, "outputs": [ { "name": "stdout", @@ -514,10 +554,8 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhQAAAGfCAYAAAAH5UtjAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAk3ElEQVR4nO3df3BU1f3/8dduyG6iwEZQNkQSjD+DP6AYNKxgWzEtQx0rhVq12OKP6mgD8sNWiQpoq8bqVPFHxGox1FGaEUdQbIXaKOFrGxAiqGgbUalEYYPWZgMomww53z/8uOPCXuXmbNzN5vmYuTPm3LMn75OLm1fu3nOvxxhjBAAAYMGb6gIAAEDPR6AAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADW+nTXwNXV1brrrrsUDoc1YsQI3X///Tr99NO/9nWdnZ3avn27+vXrJ4/H013lAQCAr2GM0a5du1RQUCCv92vOQZhuUFtba3w+n3n00UfNm2++aa644gqTl5dnWlpavva1zc3NRhIbGxsbGxtbmmzNzc1f+/vbY0zyHw5WVlam0047TQ888ICkz886FBYWavr06ZozZ85XvjYSiSgvL08Xnz9Rvuzs/fYmvVQAABAT/8lAe0eHHl+6XK2trQoEAl/5yqR/5NHe3q7GxkZVVlbG2rxer8rLy9XQ0HBA/2g0qmg0Gvt6165dkiRfdrZ8PgIFAADfnMSXGhzMJQhJvyjz448/1r59+xQMBuPag8GgwuHwAf2rqqoUCARiW2FhYbJLAgAA3SzlqzwqKysViURiW3Nzc6pLAgAALiX9I4/DDz9cWVlZamlpiWtvaWlRfn7+Af39fr/8fn+Ckb64FgQAAHwz9v+9e/C/h5N+hsLn86m0tFR1dXWxts7OTtXV1SkUCiX72wEAgDTQLfehmD17tqZOnapRo0bp9NNP14IFC7Rnzx5deuml3fHtAABAinVLoLjgggv00Ucfad68eQqHw/rWt76llStXHnChJgAAyAzddqfMadOmadq0ad01PAAASCMpX+UBAAB6PgIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYM11oFizZo3OPfdcFRQUyOPxaPny5XH7jTGaN2+eBg8erNzcXJWXl2vLli3JqhcAAKQh14Fiz549GjFihKqrqxPuv/POO3XffffpoYce0rp163TooYdq/Pjx2rt3r3WxAAAgPfVx+4IJEyZowoQJCfcZY7RgwQLddNNNOu+88yRJjz32mILBoJYvX64LL7zwgNdEo1FFo9HY121tbW5LAgAAKZbUayi2bt2qcDis8vLyWFsgEFBZWZkaGhoSvqaqqkqBQCC2FRYWJrMkAADwDUhqoAiHw5KkYDAY1x4MBmP79ldZWalIJBLbmpubk1kSAAD4Brj+yCPZ/H6//H5/qssAAAAWknqGIj8/X5LU0tIS197S0hLbBwAAMk9SA0VxcbHy8/NVV1cXa2tra9O6desUCoWS+a0AAEAacf2Rx+7du/XOO+/Evt66das2bdqkAQMGqKioSDNnztStt96q4447TsXFxZo7d64KCgo0ceLEZNYNAADSiOtAsWHDBp111lmxr2fPni1Jmjp1qhYvXqzrrrtOe/bs0ZVXXqnW1laNHTtWK1euVE5OTvKqBgAAacVjjDGpLuLL2traFAgEdNlPfyyfLzvV5QAA0Gu1t3fo0SVPKRKJqH///l/Zl2d5AAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwFqfVBcA9DR9g0cnbPckaDMux040RrcP7jBOombH+hx4sxL/zeLxuB0p4SjWvZNTR3J88kFTqksArHCGAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1VnkALrlcLJEUxsXgjvU5juG048CRnHp6vU5/mzhUk5QflsMgTj8Az4E1Jm0VDgDOUAAAAHsECgAAYI1AAQAArBEoAACANQIFAACwxioPwKVkLFBIxkoR12M4LfNwep5Fgv7erCxXQzh9T+NquYS7tRVe52Ksxz749TBA78MZCgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWWOWBXqNf8GhX/ZOymuPgF1B89TiJxnDq7Liaw11/b9bB/73hdj5ufrgeh86Ozw9xtRQjOU9gMQ4/XDerPwYMOSEptXzyQVNSxgHc4gwFAACwRqAAAADWCBQAAMAagQIAAFhzFSiqqqp02mmnqV+/fho0aJAmTpyopqb4C4D27t2riooKDRw4UH379tXkyZPV0tKS1KIBAEB6cRUo6uvrVVFRobVr1+qFF15QR0eHvv/972vPnj2xPrNmzdKKFSu0dOlS1dfXa/v27Zo0aVLSCwdc8yTejBJvDt2dh/d4DtgcB3ccI/GWcAhjEm8OnLp7vd6Em8MoiTenwZOwebzehJvTj9bxR+72BW6Om8MG9Caulo2uXLky7uvFixdr0KBBamxs1Le//W1FIhEtWrRIS5Ys0bhx4yRJNTU1GjZsmNauXavRo0cnr3IAAJA2rK6hiEQikqQBAwZIkhobG9XR0aHy8vJYn5KSEhUVFamhoSHhGNFoVG1tbXEbAADoWbocKDo7OzVz5kyNGTNGJ598siQpHA7L5/MpLy8vrm8wGFQ4HE44TlVVlQKBQGwrLCzsakkAACBFuhwoKioqtHnzZtXW1loVUFlZqUgkEtuam5utxgMAAN+8Lt16e9q0aXruuee0Zs0aDRkyJNaen5+v9vZ2tba2xp2laGlpUX5+fsKx/H6//H5/V8oA3HF7R2qHdk8S7qfteggXYzv1zHK80PLgB/qKSz7dje0gy5uVYGiXB85B4lHc3TLbw6WWgCNX7zDGGE2bNk3Lli3Tiy++qOLi4rj9paWlys7OVl1dXaytqalJ27ZtUygUSk7FAAAg7bg6Q1FRUaElS5bomWeeUb9+/WLXRQQCAeXm5ioQCOjyyy/X7NmzNWDAAPXv31/Tp09XKBRihQcAABnMVaBYuHChJOm73/1uXHtNTY0uueQSSdI999wjr9eryZMnKxqNavz48XrwwQeTUiwAAEhPrgKFOYjPcXNyclRdXa3q6uouFwUAAHoWnuUBAACsdWmVB9AjuVxa4XXob9ysaHAYY823futQi8MwbqK/ywUXjt3dTDPB4oyUcTjMrn6GLp218ZbuGxzoIThDAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAaqzzQizg8zcHrsJrD5WqJRM/4cLx3Szeu5kjGqg2n/p7ufsdwU6PTz4rHbQApwRkKAABgjUABAACsESgAAIA1AgUAALBGoAAAANZY5YFew+O0hMJhJYbzYoGDf8aH06IFt8+VOHPj3ITfMWEdLldz/L8RtyZsT7SiY8yGGxL2zcpyeitxtxRlzcgEzzhxOBDffnVewvZEq20kyeuwmieR1SNvPui+AD7HGQoAAGCNQAEAAKwRKAAAgDUCBQAAsEagAAAA1ljlgV7E6QEaLkdxWkXh9lkZrsZIsILE9bM5HFazZB18LVnexJ0dn1niVqJj4fBnj9Nhc7OaA0DycIYCAABYI1AAAABrBAoAAGCNQAEAAKxxUSZ6kVRcfenu1tOuS3HROdGtwb96HBdjON5j/ODHluTqTxyv1+lW6gc/hhxu0w3APc5QAAAAawQKAABgjUABAACsESgAAIA1AgUAALDGKg/0Gm4XHLiVaByvx+V9o13cHdzpdteOa1O6cdGKY3cXtxJ3O77b4+ZJsKKDNR5A8nCGAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1VnkASXjGhSR5vQnWDCRnaK351q0HtDktIHE9uIvuier4ylqS8CeL09j1p95sPziApOEMBQAAsEagAAAA1ggUAADAGoECAABYI1AAAABrrPJAr+H22Q9O/T1epxyerKeCJPieWS6+nWPhDt1djNOdqzk+/wZJGgfAN44zFAAAwBqBAgAAWCNQAAAAawQKAABgzdVFmQsXLtTChQv1n//8R5J00kknad68eZowYYIkae/evbr22mtVW1uraDSq8ePH68EHH1QwGEx64UDSON1K25P4CkFXl146jOE0iNNFj2MbbzygzevQ2TgN7tDseDvtBBeCjt1wYB2S5HW4UNWp3fEW46W3OOw50FkbD76vWy+NnN9tYwOZytUZiiFDhuiOO+5QY2OjNmzYoHHjxum8887Tm2++KUmaNWuWVqxYoaVLl6q+vl7bt2/XpEmTuqVwAACQPlydoTj33HPjvr7tttu0cOFCrV27VkOGDNGiRYu0ZMkSjRs3TpJUU1OjYcOGae3atRo9enTyqgYAAGmly9dQ7Nu3T7W1tdqzZ49CoZAaGxvV0dGh8vLyWJ+SkhIVFRWpoaHBcZxoNKq2tra4DQAA9CyuA8Ubb7yhvn37yu/366qrrtKyZct04oknKhwOy+fzKS8vL65/MBhUOBx2HK+qqkqBQCC2FRYWup4EAABILdeB4oQTTtCmTZu0bt06XX311Zo6dareeuutLhdQWVmpSCQS25qbm7s8FgAASA3Xt972+Xw69thjJUmlpaVav3697r33Xl1wwQVqb29Xa2tr3FmKlpYW5efnO47n9/vl9/vdVw4kicfr8n7PTis0EqzocLyttcso7/UeuOTCOA3ueOvtxPNMeFtvKeFtsJO1mqM7b1MOIDWs70PR2dmpaDSq0tJSZWdnq66uLravqalJ27ZtUygUsv02AAAgjbk6Q1FZWakJEyaoqKhIu3bt0pIlS7R69WqtWrVKgUBAl19+uWbPnq0BAwaof//+mj59ukKhECs8AADIcK4Cxc6dO/Xzn/9cO3bsUCAQ0PDhw7Vq1Sp973vfkyTdc8898nq9mjx5ctyNrQAAQGZzFSgWLVr0lftzcnJUXV2t6upqq6IAAEDPwrM8AACANderPICeKtEqjK/ksIrC+Rkf3bly4eDHdpqnY30ufizJWs3hNA6Anov/qwEAgDUCBQAAsEagAAAA1ggUAADAGoECAABYY5UHeg3HRR6Oz9twyNuOD+g48Bt43K78cFGj46oVx/rsJWs1h8fN0hIAPQJnKAAAgDUCBQAAsEagAAAA1ggUAADAGoECAABYY5UHej3nZ184vcCh3c1KDJeLHNac+tuDH8PtahYnCcZZU3qLy0G6z0sj56e6BABfwhkKAABgjUABAACsESgAAIA1AgUAALDGRZnoNTwep/yc+GpFj8NFjI433k50AWayboPdjdHf8ccCAC7wVgIAAKwRKAAAgDUCBQAAsEagAAAA1ggUAADAGqs8AJc8Dve2Triew+Uttp36f+fVA28z7XxXb3e3Eq8/9eavLesLZ23s3ltvu7mddnfWwm29Afc4QwEAAKwRKAAAgDUCBQAAsEagAAAA1ggUAADAGqs8AKelFW4f5pFwZMelGK54Ey3pcBojSY8PAQA3OEMBAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqrPAC3XD1DI/GSC6fncLj9nq6GcP1NAeDgcYYCAABYI1AAAABrBAoAAGCNQAEAAKxxUSZ6Dfd3qu6hFzE6XHzZQ2cDoIfgDAUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAa1arPO644w5VVlZqxowZWrBggSRp7969uvbaa1VbW6toNKrx48frwQcfVDAYTEa9wDfG7aoIh5ts2xciafXIm5Myjq2XRs5PdQkx6VQLAIszFOvXr9cf/vAHDR8+PK591qxZWrFihZYuXar6+npt375dkyZNsi4UAACkry4Fit27d2vKlCl65JFHdNhhh8XaI5GIFi1apLvvvlvjxo1TaWmpampq9M9//lNr165NWtEAACC9dClQVFRU6JxzzlF5eXlce2Njozo6OuLaS0pKVFRUpIaGhoRjRaNRtbW1xW0AAKBncX0NRW1trV599VWtX7/+gH3hcFg+n095eXlx7cFgUOFwOOF4VVVVuuWWW9yWAQAA0oirMxTNzc2aMWOGnnjiCeXk5CSlgMrKSkUikdjW3NyclHEBAMA3x9UZisbGRu3cuVOnnnpqrG3fvn1as2aNHnjgAa1atUrt7e1qbW2NO0vR0tKi/Pz8hGP6/X75/f6uVQ8kQbKeccGzMgD0Zq4Cxdlnn6033ngjru3SSy9VSUmJrr/+ehUWFio7O1t1dXWaPHmyJKmpqUnbtm1TKBRKXtUAACCtuAoU/fr108knnxzXduihh2rgwIGx9ssvv1yzZ8/WgAED1L9/f02fPl2hUEijR49OXtUAACCtJP3x5ffcc4+8Xq8mT54cd2MrAACQuawDxerVq+O+zsnJUXV1taqrq22HBgAAPQTP8gAAANaS/pEHgK931kbuvQIgs3CGAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwFqfVBcAfFM++aApKeMMGHJCUsYBvixZ/z6BVOEMBQAAsEagAAAA1ggUAADAGoECAABYI1AAAABrBAoAAGCNQAEAAKwRKAAAgDUCBQAAsEagAAAA1ggUAADAGoECAABYI1AAAABrBAoAAGCNQAEAAKwRKAAAgLU+qS4A6Gk++aAp1SUAQNrhDAUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwJqrQHHzzTfL4/HEbSUlJbH9e/fuVUVFhQYOHKi+fftq8uTJamlpSXrRAAAgvbg+Q3HSSSdpx44dse3ll1+O7Zs1a5ZWrFihpUuXqr6+Xtu3b9ekSZOSWjAAAEg/rp822qdPH+Xn5x/QHolEtGjRIi1ZskTjxo2TJNXU1GjYsGFau3atRo8enXC8aDSqaDQa+7qtrc1tSQAAIMVcn6HYsmWLCgoKdPTRR2vKlCnatm2bJKmxsVEdHR0qLy+P9S0pKVFRUZEaGhocx6uqqlIgEIhthYWFXZgGAABIJVeBoqysTIsXL9bKlSu1cOFCbd26VWeeeaZ27dqlcDgsn8+nvLy8uNcEg0GFw2HHMSsrKxWJRGJbc3NzlyYCAABSx9VHHhMmTIj99/Dhw1VWVqahQ4fqySefVG5ubpcK8Pv98vv9XXotAABID1bLRvPy8nT88cfrnXfeUX5+vtrb29Xa2hrXp6WlJeE1FwAAIHNYBYrdu3fr3Xff1eDBg1VaWqrs7GzV1dXF9jc1NWnbtm0KhULWhQIAgPTl6iOPX/3qVzr33HM1dOhQbd++XfPnz1dWVpYuuugiBQIBXX755Zo9e7YGDBig/v37a/r06QqFQo4rPAAAQGZwFSg++OADXXTRRfrvf/+rI444QmPHjtXatWt1xBFHSJLuueceeb1eTZ48WdFoVOPHj9eDDz7YLYUDAID04THGmFQX8WVtbW0KBAK67Kc/ls+XnepyAADotdrbO/TokqcUiUTUv3//r+zLszwAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAa64DxYcffqiLL75YAwcOVG5urk455RRt2LAhtt8Yo3nz5mnw4MHKzc1VeXm5tmzZktSiAQBAenEVKP73v/9pzJgxys7O1vPPP6+33npLv//973XYYYfF+tx5552677779NBDD2ndunU69NBDNX78eO3duzfpxQMAgPTQx03n3/3udyosLFRNTU2srbi4OPbfxhgtWLBAN910k8477zxJ0mOPPaZgMKjly5frwgsvTFLZAAAgnbg6Q/Hss89q1KhROv/88zVo0CCNHDlSjzzySGz/1q1bFQ6HVV5eHmsLBAIqKytTQ0NDwjGj0aja2triNgAA0LO4ChTvvfeeFi5cqOOOO06rVq3S1VdfrWuuuUZ/+tOfJEnhcFiSFAwG414XDAZj+/ZXVVWlQCAQ2woLC7syDwAAkEKuAkVnZ6dOPfVU3X777Ro5cqSuvPJKXXHFFXrooYe6XEBlZaUikUhsa25u7vJYAAAgNVwFisGDB+vEE0+Maxs2bJi2bdsmScrPz5cktbS0xPVpaWmJ7duf3+9X//794zYAANCzuAoUY8aMUVNTU1zb22+/raFDh0r6/ALN/Px81dXVxfa3tbVp3bp1CoVCSSgXAACkI1erPGbNmqUzzjhDt99+u37yk5/olVde0cMPP6yHH35YkuTxeDRz5kzdeuutOu6441RcXKy5c+eqoKBAEydO7I76AQBAGnAVKE477TQtW7ZMlZWV+s1vfqPi4mItWLBAU6ZMifW57rrrtGfPHl155ZVqbW3V2LFjtXLlSuXk5CS9eAAAkB48xhiT6iK+rK2tTYFAQJf99Mfy+bJTXQ4AAL1We3uHHl3ylCKRyNde48izPAAAgDUCBQAAsEagAAAA1ggUAADAGoECAABYI1AAAABrBAoAAGDN1Y2tvlme/9u+LK1umQEAQIbZ//fu/l874wwFAACwRqAAAADWCBQAAMAagQIAAFhLu4syv3hWWXtHR6K932wxAAD0KvEXYX7xu/hgniOadk8b/eCDD1RYWJjqMgAAwP9pbm7WkCFDvrJP2gWKzs5Obd++Xf369dOuXbtUWFio5ubmr31sak/W1tbGPDNEb5ijxDwzTW+YZ2+Yo5T8eRpjtGvXLhUUFMjr/eqrJNLuIw+v1xtLQR7P56de+vfvn9H/AL7APDNHb5ijxDwzTW+YZ2+Yo5TceQYCgYPqx0WZAADAGoECAABYS+tA4ff7NX/+fPn9/lSX0q2YZ+boDXOUmGem6Q3z7A1zlFI7z7S7KBMAAPQ8aX2GAgAA9AwECgAAYI1AAQAArBEoAACANQIFAACwltaBorq6WkcddZRycnJUVlamV155JdUlWVmzZo3OPfdcFRQUyOPxaPny5XH7jTGaN2+eBg8erNzcXJWXl2vLli2pKbaLqqqqdNppp6lfv34aNGiQJk6cqKamprg+e/fuVUVFhQYOHKi+fftq8uTJamlpSVHFXbNw4UINHz48dje6UCik559/PrY/E+a4vzvuuEMej0czZ86MtWXCPG+++WZ5PJ64raSkJLY/E+b4hQ8//FAXX3yxBg4cqNzcXJ1yyinasGFDbH8mvAcdddRRBxxPj8ejiooKSZlxPPft26e5c+equLhYubm5OuaYY/Tb3/427gFeKTmWJk3V1tYan89nHn30UfPmm2+aK664wuTl5ZmWlpZUl9Zlf/3rX82NN95onn76aSPJLFu2LG7/HXfcYQKBgFm+fLl57bXXzA9/+ENTXFxsPvvss9QU3AXjx483NTU1ZvPmzWbTpk3mBz/4gSkqKjK7d++O9bnqqqtMYWGhqaurMxs2bDCjR482Z5xxRgqrdu/ZZ581f/nLX8zbb79tmpqazA033GCys7PN5s2bjTGZMccve+WVV8xRRx1lhg8fbmbMmBFrz4R5zp8/35x00klmx44dse2jjz6K7c+EORpjzCeffGKGDh1qLrnkErNu3Trz3nvvmVWrVpl33nkn1icT3oN27twZdyxfeOEFI8m89NJLxpjMOJ633XabGThwoHnuuefM1q1bzdKlS03fvn3NvffeG+uTimOZtoHi9NNPNxUVFbGv9+3bZwoKCkxVVVUKq0qe/QNFZ2enyc/PN3fddVesrbW11fj9fvPnP/85BRUmx86dO40kU19fb4z5fE7Z2dlm6dKlsT7/+te/jCTT0NCQqjKT4rDDDjN//OMfM26Ou3btMscdd5x54YUXzHe+851YoMiUec6fP9+MGDEi4b5MmaMxxlx//fVm7Nixjvsz9T1oxowZ5phjjjGdnZ0ZczzPOeccc9lll8W1TZo0yUyZMsUYk7pjmZYfebS3t6uxsVHl5eWxNq/Xq/LycjU0NKSwsu6zdetWhcPhuDkHAgGVlZX16DlHIhFJ0oABAyRJjY2N6ujoiJtnSUmJioqKeuw89+3bp9raWu3Zs0ehUCjj5lhRUaFzzjknbj5SZh3LLVu2qKCgQEcffbSmTJmibdu2ScqsOT777LMaNWqUzj//fA0aNEgjR47UI488Etufie9B7e3tevzxx3XZZZfJ4/FkzPE844wzVFdXp7fffluS9Nprr+nll1/WhAkTJKXuWKbd00Yl6eOPP9a+ffsUDAbj2oPBoP7973+nqKruFQ6HJSnhnL/Y19N0dnZq5syZGjNmjE4++WRJn8/T5/MpLy8vrm9PnOcbb7yhUCikvXv3qm/fvlq2bJlOPPFEbdq0KWPmWFtbq1dffVXr168/YF+mHMuysjItXrxYJ5xwgnbs2KFbbrlFZ555pjZv3pwxc5Sk9957TwsXLtTs2bN1ww03aP369brmmmvk8/k0derUjHwPWr58uVpbW3XJJZdIypx/s3PmzFFbW5tKSkqUlZWlffv26bbbbtOUKVMkpe73SVoGCmSGiooKbd68WS+//HKqS+kWJ5xwgjZt2qRIJKKnnnpKU6dOVX19farLSprm5mbNmDFDL7zwgnJyclJdTrf54q86SRo+fLjKyso0dOhQPfnkk8rNzU1hZcnV2dmpUaNG6fbbb5ckjRw5Ups3b9ZDDz2kqVOnpri67rFo0SJNmDBBBQUFqS4lqZ588kk98cQTWrJkiU466SRt2rRJM2fOVEFBQUqPZVp+5HH44YcrKyvrgCtvW1palJ+fn6KqutcX88qUOU+bNk3PPfecXnrpJQ0ZMiTWnp+fr/b2drW2tsb174nz9Pl8OvbYY1VaWqqqqiqNGDFC9957b8bMsbGxUTt37tSpp56qPn36qE+fPqqvr9d9992nPn36KBgMZsQ895eXl6fjjz9e77zzTsYcS0kaPHiwTjzxxLi2YcOGxT7eybT3oPfff19///vf9Ytf/CLWlinH89e//rXmzJmjCy+8UKeccop+9rOfadasWaqqqpKUumOZloHC5/OptLRUdXV1sbbOzk7V1dUpFAqlsLLuU1xcrPz8/Lg5t7W1ad26dT1qzsYYTZs2TcuWLdOLL76o4uLiuP2lpaXKzs6Om2dTU5O2bdvWo+aZSGdnp6LRaMbM8eyzz9Ybb7yhTZs2xbZRo0ZpypQpsf/OhHnub/fu3Xr33Xc1ePDgjDmWkjRmzJgDlnC//fbbGjp0qKTMeQ/6Qk1NjQYNGqRzzjkn1pYpx/PTTz+V1xv/6zsrK0udnZ2SUngsu+1yT0u1tbXG7/ebxYsXm7feestceeWVJi8vz4TD4VSX1mW7du0yGzduNBs3bjSSzN133202btxo3n//fWPM58t88vLyzDPPPGNef/11c9555/W4JVtXX321CQQCZvXq1XFLtz799NNYn6uuusoUFRWZF1980WzYsMGEQiETCoVSWLV7c+bMMfX19Wbr1q3m9ddfN3PmzDEej8f87W9/M8ZkxhwT+fIqD2MyY57XXnutWb16tdm6dav5xz/+YcrLy83hhx9udu7caYzJjDka8/nS3z59+pjbbrvNbNmyxTzxxBPmkEMOMY8//nisTya8Bxnz+arAoqIic/311x+wLxOO59SpU82RRx4ZWzb69NNPm8MPP9xcd911sT6pOJZpGyiMMeb+++83RUVFxufzmdNPP92sXbs21SVZeemll4ykA7apU6caYz5f6jN37lwTDAaN3+83Z599tmlqakpt0S4lmp8kU1NTE+vz2WefmV/+8pfmsMMOM4cccoj50Y9+ZHbs2JG6orvgsssuM0OHDjU+n88cccQR5uyzz46FCWMyY46J7B8oMmGeF1xwgRk8eLDx+XzmyCOPNBdccEHcvRkyYY5fWLFihTn55JON3+83JSUl5uGHH47bnwnvQcYYs2rVKiMpYe2ZcDzb2trMjBkzTFFRkcnJyTFHH320ufHGG000Go31ScWx9BjzpVtrAQAAdEFaXkMBAAB6FgIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADW/j+eh66m08pdXQAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] + "text/plain": "
", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhQAAAGfCAYAAAAH5UtjAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAk3ElEQVR4nO3df3BU1f3/8dduyG6iwEZQNkQSjD+DP6AYNKxgWzEtQx0rhVq12OKP6mgD8sNWiQpoq8bqVPFHxGox1FGaEUdQbIXaKOFrGxAiqGgbUalEYYPWZgMomww53z/8uOPCXuXmbNzN5vmYuTPm3LMn75OLm1fu3nOvxxhjBAAAYMGb6gIAAEDPR6AAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADW+nTXwNXV1brrrrsUDoc1YsQI3X///Tr99NO/9nWdnZ3avn27+vXrJ4/H013lAQCAr2GM0a5du1RQUCCv92vOQZhuUFtba3w+n3n00UfNm2++aa644gqTl5dnWlpavva1zc3NRhIbGxsbGxtbmmzNzc1f+/vbY0zyHw5WVlam0047TQ888ICkz886FBYWavr06ZozZ85XvjYSiSgvL08Xnz9Rvuzs/fYmvVQAABAT/8lAe0eHHl+6XK2trQoEAl/5yqR/5NHe3q7GxkZVVlbG2rxer8rLy9XQ0HBA/2g0qmg0Gvt6165dkiRfdrZ8PgIFAADfnMSXGhzMJQhJvyjz448/1r59+xQMBuPag8GgwuHwAf2rqqoUCARiW2FhYbJLAgAA3SzlqzwqKysViURiW3Nzc6pLAgAALiX9I4/DDz9cWVlZamlpiWtvaWlRfn7+Af39fr/8fn+Ckb64FgQAAHwz9v+9e/C/h5N+hsLn86m0tFR1dXWxts7OTtXV1SkUCiX72wEAgDTQLfehmD17tqZOnapRo0bp9NNP14IFC7Rnzx5deuml3fHtAABAinVLoLjgggv00Ucfad68eQqHw/rWt76llStXHnChJgAAyAzddqfMadOmadq0ad01PAAASCMpX+UBAAB6PgIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYM11oFizZo3OPfdcFRQUyOPxaPny5XH7jTGaN2+eBg8erNzcXJWXl2vLli3JqhcAAKQh14Fiz549GjFihKqrqxPuv/POO3XffffpoYce0rp163TooYdq/Pjx2rt3r3WxAAAgPfVx+4IJEyZowoQJCfcZY7RgwQLddNNNOu+88yRJjz32mILBoJYvX64LL7zwgNdEo1FFo9HY121tbW5LAgAAKZbUayi2bt2qcDis8vLyWFsgEFBZWZkaGhoSvqaqqkqBQCC2FRYWJrMkAADwDUhqoAiHw5KkYDAY1x4MBmP79ldZWalIJBLbmpubk1kSAAD4Brj+yCPZ/H6//H5/qssAAAAWknqGIj8/X5LU0tIS197S0hLbBwAAMk9SA0VxcbHy8/NVV1cXa2tra9O6desUCoWS+a0AAEAacf2Rx+7du/XOO+/Evt66das2bdqkAQMGqKioSDNnztStt96q4447TsXFxZo7d64KCgo0ceLEZNYNAADSiOtAsWHDBp111lmxr2fPni1Jmjp1qhYvXqzrrrtOe/bs0ZVXXqnW1laNHTtWK1euVE5OTvKqBgAAacVjjDGpLuLL2traFAgEdNlPfyyfLzvV5QAA0Gu1t3fo0SVPKRKJqH///l/Zl2d5AAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwBqBAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1AgUAALBGoAAAANYIFAAAwFqfVBcA9DR9g0cnbPckaDMux040RrcP7jBOombH+hx4sxL/zeLxuB0p4SjWvZNTR3J88kFTqksArHCGAgAAWCNQAAAAawQKAABgjUABAACsESgAAIA1VnkALrlcLJEUxsXgjvU5juG048CRnHp6vU5/mzhUk5QflsMgTj8Az4E1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du0yGzduNBs3bjSSzN133202btxo3n//fWPM58t88vLyzDPPPGNef/11c9555/W4JVtXX321CQQCZvXq1XFLtz799NNYn6uuusoUFRWZF1980WzYsMGEQiETCoVSWLV7c+bMMfX19Wbr1q3m9ddfN3PmzDEej8f87W9/M8ZkxhwT+fIqD2MyY57XXnutWb16tdm6dav5xz/+YcrLy83hhx9udu7caYzJjDka8/nS3z59+pjbbrvNbNmyxTzxxBPmkEMOMY8//nisTya8Bxnz+arAoqIic/311x+wLxOO59SpU82RRx4ZWzb69NNPm8MPP9xcd911sT6pOJZpGyiMMeb+++83RUVFxufzmdNPP92sXbs21SVZeemll4ykA7apU6caYz5f6jN37lwTDAaN3+83Z599tmlqakpt0S4lmp8kU1NTE+vz2WefmV/+8pfmsMMOM4cccoj50Y9+ZHbs2JG6orvgsssuM0OHDjU+n88cccQR5uyzz46FCWMyY46J7B8oMmGeF1xwgRk8eLDx+XzmyCOPNBdccEHcvRkyYY5fWLFihTn55JON3+83JSUl5uGHH47bnwnvQcYYs2rVKiMpYe2ZcDzb2trMjBkzTFFRkcnJyTFHH320ufHGG000Go31ScWx9BjzpVtrAQAAdEFaXkMBAAB6FgIFAACwRqAAAADWCBQAAMAagQIAAFgjUAAAAGsECgAAYI1AAQAArBEoAACANQIFAACwRqAAAADW/j+eh66m08pdXQAAAABJRU5ErkJggg==" }, "metadata": {}, "output_type": "display_data" @@ -529,21 +567,6 @@ "First vector observations : [1. 0.]\n" ] } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "%matplotlib inline\n", - "\n", - "for index, obs_spec in enumerate(spec.observation_specs):\n", - " if len(obs_spec.shape) == 3:\n", - " print(\"Here is the first visual observation\")\n", - " plt.imshow(np.moveaxis(decision_steps.obs[index][0, :, :, :], 0, -1))\n", - " plt.show()\n", - "\n", - "for index, obs_spec in enumerate(spec.observation_specs):\n", - " if len(obs_spec.shape) == 1:\n", - " print(\"First vector observations : \", decision_steps.obs[index][0,:])" ] }, { @@ -557,25 +580,13 @@ }, { "cell_type": "code", - "execution_count": 12, "metadata": { + "id": "a2uQUsoMtIUK", "ExecuteTime": { - "end_time": "2023-10-04T12:53:04.145406Z", - "start_time": "2023-10-04T12:53:02.785602Z" - }, - "id": "a2uQUsoMtIUK" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Total rewards for episode 0 is -1.1499999966472387\n", - "Total rewards for episode 1 is -1.5599999874830246\n", - "Total rewards for episode 2 is -1.049999998882413\n" - ] + "start_time": "2023-10-04T12:53:02.785602Z", + "end_time": "2023-10-04T12:53:04.145406Z" } - ], + }, "source": [ "for episode in range(3):\n", " env.reset()\n", @@ -606,6 +617,18 @@ " episode_rewards += terminal_steps[tracked_agent].reward\n", " done = True\n", " print(f\"Total rewards for episode {episode} is {episode_rewards}\")\n" + ], + "execution_count": 12, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Total rewards for episode 0 is -1.1499999966472387\n", + "Total rewards for episode 1 is -1.5599999874830246\n", + "Total rewards for episode 2 is -1.049999998882413\n" + ] + } ] }, { @@ -619,14 +642,18 @@ }, { "cell_type": "code", - "execution_count": 13, "metadata": { + "id": "vdWG6_SqtNtv", "ExecuteTime": { - "end_time": "2023-10-04T12:53:06.416573Z", - "start_time": "2023-10-04T12:53:06.093669Z" - }, - "id": "vdWG6_SqtNtv" + "start_time": "2023-10-04T12:53:06.093669Z", + "end_time": "2023-10-04T12:53:06.416573Z" + } }, + "source": [ + "env.close()\n", + "print(\"Closed environment\")\n" + ], + "execution_count": 13, "outputs": [ { "name": "stdout", @@ -635,36 +662,7 @@ "Closed environment\n" ] } - ], - "source": [ - "env.close()\n", - "print(\"Closed environment\")\n" ] } - ], - "metadata": { - "colab": { - "collapsed_sections": [], - "name": "Colab-UnityEnvironment-1-Run.ipynb", - "private_outputs": true, - "provenance": [], - "toc_visible": true - }, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "pycharm": { - "stem_cell": { - "cell_type": "raw", - "metadata": { - "collapsed": false - }, - "source": [] - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 + ] } From 4a1166ff3d61e1f14f36153337c85da4a37f91c1 Mon Sep 17 00:00:00 2001 From: maryam-zia Date: Thu, 18 Dec 2025 16:17:26 -0500 Subject: [PATCH 26/26] Remove no_graphics --- colab/Colab_UnityEnvironment_1_Run.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/colab/Colab_UnityEnvironment_1_Run.ipynb b/colab/Colab_UnityEnvironment_1_Run.ipynb index 9ac80f920f..e70dca7b8a 100644 --- a/colab/Colab_UnityEnvironment_1_Run.ipynb +++ b/colab/Colab_UnityEnvironment_1_Run.ipynb @@ -217,7 +217,7 @@ "\n", "from mlagents_envs.registry import default_registry\n", "\n", - "env = default_registry[env_id].make(no_graphics=True)" + "env = default_registry[env_id].make()" ], "execution_count": 3, "outputs": [