HoST-pytorch 0.0.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- host_pytorch-0.0.5/.github/workflows/python-publish.yml +36 -0
- host_pytorch-0.0.5/.gitignore +171 -0
- host_pytorch-0.0.5/LICENSE +21 -0
- host_pytorch-0.0.5/PKG-INFO +74 -0
- host_pytorch-0.0.5/README.md +29 -0
- host_pytorch-0.0.5/host_pytorch/__init__.py +6 -0
- host_pytorch-0.0.5/host_pytorch/host.py +435 -0
- host_pytorch-0.0.5/pyproject.toml +61 -0
- host_pytorch-0.0.5/rewards.png +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# This workflow will upload a Python Package using Twine when a release is created
|
|
2
|
+
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
|
|
3
|
+
|
|
4
|
+
# This workflow uses actions that are not certified by GitHub.
|
|
5
|
+
# They are provided by a third-party and are governed by
|
|
6
|
+
# separate terms of service, privacy policy, and support
|
|
7
|
+
# documentation.
|
|
8
|
+
|
|
9
|
+
name: Upload Python Package
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
release:
|
|
13
|
+
types: [published]
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
deploy:
|
|
17
|
+
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v2
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
uses: actions/setup-python@v2
|
|
24
|
+
with:
|
|
25
|
+
python-version: '3.x'
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: |
|
|
28
|
+
python -m pip install --upgrade pip
|
|
29
|
+
pip install build
|
|
30
|
+
- name: Build package
|
|
31
|
+
run: python -m build
|
|
32
|
+
- name: Publish package
|
|
33
|
+
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
|
|
34
|
+
with:
|
|
35
|
+
user: __token__
|
|
36
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py,cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
#Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
#uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
#poetry.lock
|
|
109
|
+
|
|
110
|
+
# pdm
|
|
111
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
112
|
+
#pdm.lock
|
|
113
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
114
|
+
# in version control.
|
|
115
|
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
116
|
+
.pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
121
|
+
__pypackages__/
|
|
122
|
+
|
|
123
|
+
# Celery stuff
|
|
124
|
+
celerybeat-schedule
|
|
125
|
+
celerybeat.pid
|
|
126
|
+
|
|
127
|
+
# SageMath parsed files
|
|
128
|
+
*.sage.py
|
|
129
|
+
|
|
130
|
+
# Environments
|
|
131
|
+
.env
|
|
132
|
+
.venv
|
|
133
|
+
env/
|
|
134
|
+
venv/
|
|
135
|
+
ENV/
|
|
136
|
+
env.bak/
|
|
137
|
+
venv.bak/
|
|
138
|
+
|
|
139
|
+
# Spyder project settings
|
|
140
|
+
.spyderproject
|
|
141
|
+
.spyproject
|
|
142
|
+
|
|
143
|
+
# Rope project settings
|
|
144
|
+
.ropeproject
|
|
145
|
+
|
|
146
|
+
# mkdocs documentation
|
|
147
|
+
/site
|
|
148
|
+
|
|
149
|
+
# mypy
|
|
150
|
+
.mypy_cache/
|
|
151
|
+
.dmypy.json
|
|
152
|
+
dmypy.json
|
|
153
|
+
|
|
154
|
+
# Pyre type checker
|
|
155
|
+
.pyre/
|
|
156
|
+
|
|
157
|
+
# pytype static type analyzer
|
|
158
|
+
.pytype/
|
|
159
|
+
|
|
160
|
+
# Cython debug symbols
|
|
161
|
+
cython_debug/
|
|
162
|
+
|
|
163
|
+
# PyCharm
|
|
164
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
165
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
166
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
167
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
168
|
+
#.idea/
|
|
169
|
+
|
|
170
|
+
# PyPI configuration file
|
|
171
|
+
.pypirc
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Phil Wang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: HoST-pytorch
|
|
3
|
+
Version: 0.0.5
|
|
4
|
+
Summary: Humanoid Standing Up
|
|
5
|
+
Project-URL: Homepage, https://pypi.org/project/HoST-pytorch/
|
|
6
|
+
Project-URL: Repository, https://github.com/lucidrains/HoST-pytorch
|
|
7
|
+
Author-email: Phil Wang <lucidrains@gmail.com>
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2025 Phil Wang
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Keywords: artificial intelligence,deep learning,humanoids standing,reinforcement learning,reward shaping
|
|
31
|
+
Classifier: Development Status :: 4 - Beta
|
|
32
|
+
Classifier: Intended Audience :: Developers
|
|
33
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
35
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
36
|
+
Requires-Python: >=3.9
|
|
37
|
+
Requires-Dist: einops>=0.8.1
|
|
38
|
+
Requires-Dist: einx>=0.3.0
|
|
39
|
+
Requires-Dist: hl-gauss-pytorch>=0.1.19
|
|
40
|
+
Requires-Dist: torch>=2.2
|
|
41
|
+
Provides-Extra: examples
|
|
42
|
+
Provides-Extra: test
|
|
43
|
+
Requires-Dist: pytest; extra == 'test'
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
|
|
46
|
+
<img src="./rewards.png" width="600px"></img>
|
|
47
|
+
|
|
48
|
+
## HoST - Pytorch (wip)
|
|
49
|
+
|
|
50
|
+
Implementation of Humanoid Standing Up, from the paper <a href="https://taohuang13.github.io/humanoid-standingup.github.io/">Learning Humanoid Standing-up Control across Diverse Postures</a> out of Shanghai, in Pytorch
|
|
51
|
+
|
|
52
|
+
Besides for the set of reward functions, the other contribution is validating [an approach using multiple critics](https://openreview.net/forum?id=rJvY_5OzoI) out of Boston University
|
|
53
|
+
|
|
54
|
+
## Citations
|
|
55
|
+
|
|
56
|
+
```bibtex
|
|
57
|
+
@article{huang2025host,
|
|
58
|
+
title = {Learning Humanoid Standing-up Control across Diverse Postures},
|
|
59
|
+
author = {Huang, Tao and Ren, Junli and Wang, Huayi and Wang, Zirui and Ben, Qingwei and Wen, Muning and Chen, Xiao and Li, Jianan and Pang, Jiangmiao},
|
|
60
|
+
journal = {arXiv preprint arXiv:2502.08378},
|
|
61
|
+
year = {2025},
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```bibtex
|
|
66
|
+
@article{Farebrother2024StopRT,
|
|
67
|
+
title = {Stop Regressing: Training Value Functions via Classification for Scalable Deep RL},
|
|
68
|
+
author = {Jesse Farebrother and Jordi Orbay and Quan Ho Vuong and Adrien Ali Taiga and Yevgen Chebotar and Ted Xiao and Alex Irpan and Sergey Levine and Pablo Samuel Castro and Aleksandra Faust and Aviral Kumar and Rishabh Agarwal},
|
|
69
|
+
journal = {ArXiv},
|
|
70
|
+
year = {2024},
|
|
71
|
+
volume = {abs/2403.03950},
|
|
72
|
+
url = {https://api.semanticscholar.org/CorpusID:268253088}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<img src="./rewards.png" width="600px"></img>
|
|
2
|
+
|
|
3
|
+
## HoST - Pytorch (wip)
|
|
4
|
+
|
|
5
|
+
Implementation of Humanoid Standing Up, from the paper <a href="https://taohuang13.github.io/humanoid-standingup.github.io/">Learning Humanoid Standing-up Control across Diverse Postures</a> out of Shanghai, in Pytorch
|
|
6
|
+
|
|
7
|
+
Besides for the set of reward functions, the other contribution is validating [an approach using multiple critics](https://openreview.net/forum?id=rJvY_5OzoI) out of Boston University
|
|
8
|
+
|
|
9
|
+
## Citations
|
|
10
|
+
|
|
11
|
+
```bibtex
|
|
12
|
+
@article{huang2025host,
|
|
13
|
+
title = {Learning Humanoid Standing-up Control across Diverse Postures},
|
|
14
|
+
author = {Huang, Tao and Ren, Junli and Wang, Huayi and Wang, Zirui and Ben, Qingwei and Wen, Muning and Chen, Xiao and Li, Jianan and Pang, Jiangmiao},
|
|
15
|
+
journal = {arXiv preprint arXiv:2502.08378},
|
|
16
|
+
year = {2025},
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```bibtex
|
|
21
|
+
@article{Farebrother2024StopRT,
|
|
22
|
+
title = {Stop Regressing: Training Value Functions via Classification for Scalable Deep RL},
|
|
23
|
+
author = {Jesse Farebrother and Jordi Orbay and Quan Ho Vuong and Adrien Ali Taiga and Yevgen Chebotar and Ted Xiao and Alex Irpan and Sergey Levine and Pablo Samuel Castro and Aleksandra Faust and Aviral Kumar and Rishabh Agarwal},
|
|
24
|
+
journal = {ArXiv},
|
|
25
|
+
year = {2024},
|
|
26
|
+
volume = {abs/2403.03950},
|
|
27
|
+
url = {https://api.semanticscholar.org/CorpusID:268253088}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import torch
|
|
4
|
+
from torch import tensor, stack
|
|
5
|
+
import torch.nn.functional as F
|
|
6
|
+
from torch.distributions import Categorical
|
|
7
|
+
from torch.nn import Module, ModuleList, Linear
|
|
8
|
+
|
|
9
|
+
from hl_gauss_pytorch import HLGaussLoss
|
|
10
|
+
|
|
11
|
+
import einx
|
|
12
|
+
from einops import repeat, rearrange, reduce
|
|
13
|
+
from einops.layers.torch import EinMix as Mix
|
|
14
|
+
|
|
15
|
+
# helper functions
|
|
16
|
+
|
|
17
|
+
def exists(v):
|
|
18
|
+
return v is not None
|
|
19
|
+
|
|
20
|
+
def default(v, d):
|
|
21
|
+
return v if exists(v) else d
|
|
22
|
+
|
|
23
|
+
# sampling related
|
|
24
|
+
|
|
25
|
+
def log(t, eps = 1e-20):
|
|
26
|
+
return torch.log(t.clamp(min = eps))
|
|
27
|
+
|
|
28
|
+
def calc_entropy(prob, eps = 1e-20, dim = -1):
|
|
29
|
+
return -(prob * log(prob, eps)).sum(dim = dim)
|
|
30
|
+
|
|
31
|
+
def gumbel_noise(t):
|
|
32
|
+
noise = torch.zeros_like(t).uniform_(0, 1)
|
|
33
|
+
return -log(-log(noise))
|
|
34
|
+
|
|
35
|
+
def gumbel_sample(t, temperature = 1., dim = -1, keepdim = True):
|
|
36
|
+
return ((t / max(temperature, 1e-10)) + gumbel_noise(t)).argmax(dim = dim, keepdim = keepdim)
|
|
37
|
+
|
|
38
|
+
# === reward functions === table 6 - they have a mistake where they redefine ankle parallel reward twice
|
|
39
|
+
|
|
40
|
+
# task rewards - It specifies the high-level task objectives.
|
|
41
|
+
|
|
42
|
+
def reward_head_height(state):
|
|
43
|
+
""" The head of robot head in the world frame """
|
|
44
|
+
raise NotImplementedError
|
|
45
|
+
|
|
46
|
+
def reward_base_orientation(state):
|
|
47
|
+
""" The orientation of the robot base represented by projected gravity vector. """
|
|
48
|
+
raise NotImplementedError
|
|
49
|
+
|
|
50
|
+
# style rewards - It specifies the style of standing-up motion.
|
|
51
|
+
|
|
52
|
+
def reward_waist_yaw_deviation(state):
|
|
53
|
+
""" It penalizes the large joint angle of the waist yaw. """
|
|
54
|
+
raise NotImplementedError
|
|
55
|
+
|
|
56
|
+
def reward_hip_roll_yaw_deviation(state):
|
|
57
|
+
""" It penalizes the large joint angle of hip roll/yaw joints. """
|
|
58
|
+
raise NotImplementedError
|
|
59
|
+
|
|
60
|
+
def reward_shoulder_roll_deviation(state):
|
|
61
|
+
""" It penalizes the large joint angle of shoulder roll joint. """
|
|
62
|
+
raise NotImplementedError
|
|
63
|
+
|
|
64
|
+
def reward_foot_displacement(state):
|
|
65
|
+
""" It encourages robot CoM locates in support polygon, inspired by https://ieeexplore.ieee.org/document/1308858 """
|
|
66
|
+
raise NotImplementedError
|
|
67
|
+
|
|
68
|
+
def reward_ankle_parallel(state):
|
|
69
|
+
""" It encourages the ankles to be parallel to the ground via ankle keypoints. """
|
|
70
|
+
raise NotImplementedError
|
|
71
|
+
|
|
72
|
+
def reward_foot_distance(state):
|
|
73
|
+
""" It penalizes a far distance between feet. """
|
|
74
|
+
raise NotImplementedError
|
|
75
|
+
|
|
76
|
+
def reward_foot_stumble(state):
|
|
77
|
+
""" It penalizes a horizontal contact force with the environment. """
|
|
78
|
+
raise NotImplementedError
|
|
79
|
+
|
|
80
|
+
def reward_shank_orientation(state):
|
|
81
|
+
""" It encourages the left/right shank to be perpendicular to the ground. """
|
|
82
|
+
raise NotImplementedError
|
|
83
|
+
|
|
84
|
+
def reward_waist_yaw_deviation(state):
|
|
85
|
+
""" It penalizes the large joint angle of the waist yaw. """
|
|
86
|
+
raise NotImplementedError
|
|
87
|
+
|
|
88
|
+
def reward_base_angular_velocity(state):
|
|
89
|
+
""" It encourages low angular velocity of the during rising up. """
|
|
90
|
+
raise NotImplementedError
|
|
91
|
+
|
|
92
|
+
# regularization rewards - It specifies the regulariztaion on standing-up motion.
|
|
93
|
+
|
|
94
|
+
def reward_joint_acceleration(state):
|
|
95
|
+
""" It penalizes the high joint accelrations. """
|
|
96
|
+
raise NotImplementedError
|
|
97
|
+
|
|
98
|
+
def reward_action_rate(state):
|
|
99
|
+
""" It penalizes the high changing speed of action. """
|
|
100
|
+
raise NotImplementedError
|
|
101
|
+
|
|
102
|
+
def reward_smoothness(state):
|
|
103
|
+
""" It penalizes the discrepancy between consecutive actions. """
|
|
104
|
+
raise NotImplementedError
|
|
105
|
+
|
|
106
|
+
def reward_torques(state):
|
|
107
|
+
""" It penalizes the high joint torques. """
|
|
108
|
+
raise NotImplementedError
|
|
109
|
+
|
|
110
|
+
def reward_joint_power(state):
|
|
111
|
+
""" It penalizes the high joint power """
|
|
112
|
+
raise NotImplementedError
|
|
113
|
+
|
|
114
|
+
def reward_joint_velocity(state):
|
|
115
|
+
""" It penalizes the high joint velocity. """
|
|
116
|
+
raise NotImplementedError
|
|
117
|
+
|
|
118
|
+
def reward_joint_tracking_error(state):
|
|
119
|
+
""" It penalizes the error between PD target (Eq. (1)) and actual joint position. """
|
|
120
|
+
raise NotImplementedError
|
|
121
|
+
|
|
122
|
+
def reward_joint_pos_limits(state):
|
|
123
|
+
""" It penalizes the joint position that beyond limits. """
|
|
124
|
+
raise NotImplementedError
|
|
125
|
+
|
|
126
|
+
def reward_joint_vel_limits(state):
|
|
127
|
+
""" It penalizes the joint velocity that beyond limits. """
|
|
128
|
+
raise NotImplementedError
|
|
129
|
+
|
|
130
|
+
# post task reward - It specifies the desired behaviors after a successful standing up.
|
|
131
|
+
|
|
132
|
+
def reward_base_angular_velocity(state):
|
|
133
|
+
""" It encourages low angular velocity of robot base after standing up. """
|
|
134
|
+
raise NotImplementedError
|
|
135
|
+
|
|
136
|
+
def reward_base_linear_velocity(state):
|
|
137
|
+
""" It encourages low linear velocity of robot base after standing up. """
|
|
138
|
+
raise NotImplementedError
|
|
139
|
+
|
|
140
|
+
def reward_base_orientation(state):
|
|
141
|
+
""" It encourages the robot base to be perpendicular to the ground. """
|
|
142
|
+
raise NotImplementedError
|
|
143
|
+
|
|
144
|
+
def reward_base_height(state):
|
|
145
|
+
""" It encourages the robot base to reach a target height. """
|
|
146
|
+
raise NotImplementedError
|
|
147
|
+
|
|
148
|
+
def reward_upper_body_posture(state):
|
|
149
|
+
""" It encourages the robot to track a target upper body postures. """
|
|
150
|
+
raise NotImplementedError
|
|
151
|
+
|
|
152
|
+
def reward_feet_parallel(state):
|
|
153
|
+
""" In encourages the feet to be parallel to each other. """
|
|
154
|
+
raise NotImplementedError
|
|
155
|
+
|
|
156
|
+
# reward config with all the weights
|
|
157
|
+
|
|
158
|
+
REWARD_CONFIG = [
|
|
159
|
+
('task', 2.5, [
|
|
160
|
+
(reward_head_height, 1),
|
|
161
|
+
(reward_base_orientation, 1),
|
|
162
|
+
]),
|
|
163
|
+
('style', 1., [
|
|
164
|
+
(reward_waist_yaw_deviation, -10),
|
|
165
|
+
(reward_hip_roll_yaw_deviation, -10 / 10),
|
|
166
|
+
(reward_shoulder_roll_deviation, -0.25 / -10),
|
|
167
|
+
(reward_foot_displacement, -2.5),
|
|
168
|
+
(reward_ankle_parallel, 2.5 / 2.5),
|
|
169
|
+
(reward_foot_distance, 20),
|
|
170
|
+
(reward_foot_stumble, -10),
|
|
171
|
+
(reward_shank_orientation, 0 / -25), # do not understand this 0(G) / -25(PSW)
|
|
172
|
+
(reward_waist_yaw_deviation, 10),
|
|
173
|
+
(reward_base_angular_velocity, 1),
|
|
174
|
+
]),
|
|
175
|
+
('regularization', 0.1, [
|
|
176
|
+
(reward_joint_acceleration, -2.5e-7),
|
|
177
|
+
(reward_action_rate, -1e-2),
|
|
178
|
+
(reward_smoothness, -1e-2),
|
|
179
|
+
(reward_torques, -2.5e-6),
|
|
180
|
+
(reward_joint_power, -2.5e-5),
|
|
181
|
+
(reward_joint_velocity, -1e-4),
|
|
182
|
+
(reward_joint_tracking_error, -2.5e-1),
|
|
183
|
+
(reward_joint_pos_limits, -1e2),
|
|
184
|
+
(reward_joint_vel_limits, -1.),
|
|
185
|
+
]),
|
|
186
|
+
('post_task', 1, [
|
|
187
|
+
(reward_base_angular_velocity, 10),
|
|
188
|
+
(reward_base_linear_velocity, 10),
|
|
189
|
+
(reward_base_orientation, 10),
|
|
190
|
+
(reward_base_height, 10),
|
|
191
|
+
(reward_upper_body_posture, 10),
|
|
192
|
+
(reward_feet_parallel, 2.5),
|
|
193
|
+
])
|
|
194
|
+
]
|
|
195
|
+
|
|
196
|
+
class RewardShapingWrapper(Module):
|
|
197
|
+
def __init__(
|
|
198
|
+
self,
|
|
199
|
+
config = REWARD_CONFIG,
|
|
200
|
+
critics_kwargs: dict = dict()
|
|
201
|
+
):
|
|
202
|
+
super().__init__()
|
|
203
|
+
|
|
204
|
+
self.config = config
|
|
205
|
+
|
|
206
|
+
# based on the reward group config
|
|
207
|
+
# can instantiate the critics automatically
|
|
208
|
+
|
|
209
|
+
num_reward_groups = len(config)
|
|
210
|
+
critics_weights = [reward_group_weight for _, reward_group_weight, _ in config]
|
|
211
|
+
|
|
212
|
+
self.critics = Critics(
|
|
213
|
+
critics_weights,
|
|
214
|
+
num_critics = num_reward_groups,
|
|
215
|
+
**critics_kwargs
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# then store the weights of the individual reward shaping functions, per group
|
|
219
|
+
|
|
220
|
+
num_reward_fns = [len(reward_group_fns) for _, _, reward_group_fns in config]
|
|
221
|
+
self.split_dims = num_reward_fns
|
|
222
|
+
|
|
223
|
+
reward_fn_weights = tensor([weight for _, _, reward_group_fns in config for _, weight in reward_group_fns])
|
|
224
|
+
self.register_buffer('reward_weights', reward_fn_weights)
|
|
225
|
+
|
|
226
|
+
self.reward_fns = [lambda state: state.sum() for _, _, reward_group_fns in config for reward_fn, _ in reward_group_fns]
|
|
227
|
+
|
|
228
|
+
def forward(
|
|
229
|
+
self,
|
|
230
|
+
state
|
|
231
|
+
):
|
|
232
|
+
rewards = tensor([reward_fn(state) for reward_fn in self.reward_fns])
|
|
233
|
+
|
|
234
|
+
weighted_rewards = rewards * self.reward_weights
|
|
235
|
+
|
|
236
|
+
weighted_rewards_by_groups = weighted_rewards.split(self.split_dims)
|
|
237
|
+
|
|
238
|
+
rewards = stack([reward_group.sum() for reward_group in weighted_rewards_by_groups])
|
|
239
|
+
|
|
240
|
+
return rewards
|
|
241
|
+
|
|
242
|
+
# === networks ===
|
|
243
|
+
|
|
244
|
+
# simple mlp for actor
|
|
245
|
+
|
|
246
|
+
class MLP(Module):
|
|
247
|
+
def __init__(
|
|
248
|
+
self,
|
|
249
|
+
*dims
|
|
250
|
+
):
|
|
251
|
+
super().__init__()
|
|
252
|
+
assert len(dims) >= 2, 'must have at least two dimensions'
|
|
253
|
+
|
|
254
|
+
dim_pairs = tuple(zip(dims[:-1], dims[1:]))
|
|
255
|
+
|
|
256
|
+
layers = ModuleList([Linear(dim_in, dim_out) for dim_in, dim_out in dim_pairs])
|
|
257
|
+
|
|
258
|
+
self.layers = layers
|
|
259
|
+
|
|
260
|
+
def forward(
|
|
261
|
+
self,
|
|
262
|
+
x
|
|
263
|
+
):
|
|
264
|
+
|
|
265
|
+
for ind, layer in enumerate(self.layers, start = 1):
|
|
266
|
+
is_last = ind == len(self.layers)
|
|
267
|
+
|
|
268
|
+
x = layer(x)
|
|
269
|
+
|
|
270
|
+
if not is_last:
|
|
271
|
+
x = F.silu(x)
|
|
272
|
+
|
|
273
|
+
return x
|
|
274
|
+
|
|
275
|
+
# actor
|
|
276
|
+
|
|
277
|
+
class Actor(Module):
|
|
278
|
+
def __init__(
|
|
279
|
+
self,
|
|
280
|
+
num_actions,
|
|
281
|
+
dims: tuple[int, ...] = (512, 256, 128),
|
|
282
|
+
eps_clip = 0.2,
|
|
283
|
+
beta_s = .01,
|
|
284
|
+
):
|
|
285
|
+
super().__init__()
|
|
286
|
+
|
|
287
|
+
dims = (*dims, num_actions)
|
|
288
|
+
|
|
289
|
+
self.net = MLP(*dims)
|
|
290
|
+
|
|
291
|
+
# ppo loss related
|
|
292
|
+
|
|
293
|
+
self.eps_clip = eps_clip
|
|
294
|
+
self.beta_s = beta_s
|
|
295
|
+
|
|
296
|
+
def forward_for_loss(
|
|
297
|
+
self,
|
|
298
|
+
state,
|
|
299
|
+
actions,
|
|
300
|
+
old_log_probs,
|
|
301
|
+
advantages
|
|
302
|
+
):
|
|
303
|
+
clip = self.eps_clip
|
|
304
|
+
logits = self.net(state)
|
|
305
|
+
|
|
306
|
+
prob = logits.softmax(dim = -1)
|
|
307
|
+
|
|
308
|
+
distribution = Categorical(prob)
|
|
309
|
+
|
|
310
|
+
log_probs = distribution.log_prob(actions)
|
|
311
|
+
|
|
312
|
+
ratios = (log_probs - old_log_probs).exp()
|
|
313
|
+
|
|
314
|
+
# classic clipped surrogate objective from ppo
|
|
315
|
+
|
|
316
|
+
surr1 = ratios * advantages
|
|
317
|
+
surr2 = ratios.clamp(1. - clip, 1. + clip) * advantages
|
|
318
|
+
loss = -torch.min(surr1, surr2) - self.beta_s * calc_entropy(prob)
|
|
319
|
+
|
|
320
|
+
return loss.sum()
|
|
321
|
+
|
|
322
|
+
def forward(
|
|
323
|
+
self,
|
|
324
|
+
state,
|
|
325
|
+
sample = False,
|
|
326
|
+
sample_return_log_prob = True
|
|
327
|
+
):
|
|
328
|
+
|
|
329
|
+
logits = self.net(state)
|
|
330
|
+
|
|
331
|
+
prob = logits.softmax(dim = -1)
|
|
332
|
+
|
|
333
|
+
if not sample:
|
|
334
|
+
return prob
|
|
335
|
+
|
|
336
|
+
distribution = Categorical(prob)
|
|
337
|
+
|
|
338
|
+
actions = distribution.sample()
|
|
339
|
+
|
|
340
|
+
log_prob = distribution.log_prob(actions)
|
|
341
|
+
|
|
342
|
+
if not sample_return_log_prob:
|
|
343
|
+
return sampled_actions
|
|
344
|
+
|
|
345
|
+
return actions, log_prob
|
|
346
|
+
|
|
347
|
+
# grouped mlp
|
|
348
|
+
# for multiple critics in one forward pass
|
|
349
|
+
# all critics must share the same MLP network structure
|
|
350
|
+
|
|
351
|
+
class GroupedMLP(Module):
|
|
352
|
+
def __init__(
|
|
353
|
+
self,
|
|
354
|
+
*dims,
|
|
355
|
+
num_mlps = 1,
|
|
356
|
+
):
|
|
357
|
+
super().__init__()
|
|
358
|
+
|
|
359
|
+
assert len(dims) >= 2, 'must have at least two dimensions'
|
|
360
|
+
|
|
361
|
+
dim_pairs = list(zip(dims[:-1], dims[1:]))
|
|
362
|
+
|
|
363
|
+
# handle first layer as no grouped dimension yet
|
|
364
|
+
|
|
365
|
+
first_dim_in, first_dim_out = dim_pairs.pop(0)
|
|
366
|
+
|
|
367
|
+
first_layer = Mix('b ... i -> b ... g o', weight_shape = 'g i o', bias_shape = 'g o', g = num_mlps, i = first_dim_in, o = first_dim_out)
|
|
368
|
+
|
|
369
|
+
# rest of the layers
|
|
370
|
+
|
|
371
|
+
layers = [Mix('b ... g i -> b ... g o', weight_shape = 'g i o', bias_shape = 'g o', g = num_mlps, i = dim_in, o = dim_out) for dim_in, dim_out in dim_pairs]
|
|
372
|
+
|
|
373
|
+
self.layers = ModuleList([first_layer, *layers])
|
|
374
|
+
self.num_mlps = num_mlps
|
|
375
|
+
|
|
376
|
+
def forward(
|
|
377
|
+
self,
|
|
378
|
+
x
|
|
379
|
+
):
|
|
380
|
+
|
|
381
|
+
for ind, layer in enumerate(self.layers, start = 1):
|
|
382
|
+
is_last = ind == len(self.layers)
|
|
383
|
+
|
|
384
|
+
x = layer(x)
|
|
385
|
+
|
|
386
|
+
if not is_last:
|
|
387
|
+
x = F.silu(x)
|
|
388
|
+
|
|
389
|
+
return x
|
|
390
|
+
|
|
391
|
+
# critics
|
|
392
|
+
|
|
393
|
+
class Critics(Module):
|
|
394
|
+
def __init__(
|
|
395
|
+
self,
|
|
396
|
+
weights: tuple[float, ...],
|
|
397
|
+
dims: tuple[int, ...] = (512, 256),
|
|
398
|
+
num_critics = 4,
|
|
399
|
+
):
|
|
400
|
+
super().__init__()
|
|
401
|
+
dims = (*dims, 1)
|
|
402
|
+
|
|
403
|
+
self.mlps = GroupedMLP(*dims, num_mlps = num_critics)
|
|
404
|
+
|
|
405
|
+
assert len(weights) == num_critics
|
|
406
|
+
self.register_buffer('weights', tensor(weights))
|
|
407
|
+
|
|
408
|
+
@torch.no_grad()
|
|
409
|
+
def calc_advantages(
|
|
410
|
+
self,
|
|
411
|
+
values,
|
|
412
|
+
rewards
|
|
413
|
+
):
|
|
414
|
+
batch = values.shape[0]
|
|
415
|
+
|
|
416
|
+
advantages = rewards - values
|
|
417
|
+
|
|
418
|
+
advantages = rearrange(advantages, 'b g -> g b')
|
|
419
|
+
norm_advantages = F.layer_norm(advantages, (batch,))
|
|
420
|
+
|
|
421
|
+
weighted_norm_advantages = einx.multiply('g b, g', norm_advantages, self.weights)
|
|
422
|
+
return reduce(weighted_norm_advantages, 'g b -> b', 'sum')
|
|
423
|
+
|
|
424
|
+
def forward(
|
|
425
|
+
self,
|
|
426
|
+
state,
|
|
427
|
+
rewards = None # Float['b g']
|
|
428
|
+
):
|
|
429
|
+
values = self.mlps(state)
|
|
430
|
+
values = rearrange(values, '... 1 -> ...')
|
|
431
|
+
|
|
432
|
+
if not exists(rewards):
|
|
433
|
+
return values
|
|
434
|
+
|
|
435
|
+
return F.mse_loss(rewards, values)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "HoST-pytorch"
|
|
3
|
+
version = "0.0.5"
|
|
4
|
+
description = "Humanoid Standing Up"
|
|
5
|
+
authors = [
|
|
6
|
+
{ name = "Phil Wang", email = "lucidrains@gmail.com" }
|
|
7
|
+
]
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">= 3.9"
|
|
10
|
+
license = { file = "LICENSE" }
|
|
11
|
+
keywords = [
|
|
12
|
+
'artificial intelligence',
|
|
13
|
+
'deep learning',
|
|
14
|
+
'reinforcement learning',
|
|
15
|
+
'reward shaping',
|
|
16
|
+
'humanoids standing'
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
classifiers=[
|
|
20
|
+
'Development Status :: 4 - Beta',
|
|
21
|
+
'Intended Audience :: Developers',
|
|
22
|
+
'Topic :: Scientific/Engineering :: Artificial Intelligence',
|
|
23
|
+
'License :: OSI Approved :: MIT License',
|
|
24
|
+
'Programming Language :: Python :: 3.9',
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
dependencies = [
|
|
28
|
+
"einx>=0.3.0",
|
|
29
|
+
"einops>=0.8.1",
|
|
30
|
+
"hl-gauss-pytorch>=0.1.19",
|
|
31
|
+
"torch>=2.2",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://pypi.org/project/HoST-pytorch/"
|
|
36
|
+
Repository = "https://github.com/lucidrains/HoST-pytorch"
|
|
37
|
+
|
|
38
|
+
[project.optional-dependencies]
|
|
39
|
+
examples = []
|
|
40
|
+
test = [
|
|
41
|
+
"pytest"
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[tool.pytest.ini_options]
|
|
45
|
+
pythonpath = [
|
|
46
|
+
"."
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
[build-system]
|
|
50
|
+
requires = ["hatchling"]
|
|
51
|
+
build-backend = "hatchling.build"
|
|
52
|
+
|
|
53
|
+
[tool.rye]
|
|
54
|
+
managed = true
|
|
55
|
+
dev-dependencies = []
|
|
56
|
+
|
|
57
|
+
[tool.hatch.metadata]
|
|
58
|
+
allow-direct-references = true
|
|
59
|
+
|
|
60
|
+
[tool.hatch.build.targets.wheel]
|
|
61
|
+
packages = ["HoST_pytorch"]
|
|
Binary file
|