Instructions to use prosoro/ballnet with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use prosoro/ballnet with Transformers:
# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("prosoro/ballnet", dtype="auto") - Notebooks
- Google Colab
- Kaggle
Upload folder using huggingface_hub
Browse files- README.md +88 -85
- config.json +0 -0
- model.onnx +2 -2
- model.safetensors +3 -0
- modeling.py +97 -26
README.md
CHANGED
|
@@ -1,85 +1,88 @@
|
|
| 1 |
-
---
|
| 2 |
-
license: bsd-3-clause
|
| 3 |
-
pipeline_tag: robotics
|
| 4 |
-
tags:
|
| 5 |
-
- ballnet
|
| 6 |
-
- metaball
|
| 7 |
-
- multimodal
|
| 8 |
-
- onnx
|
| 9 |
-
- pytorch
|
| 10 |
-
library_name: transformers
|
| 11 |
-
datasets:
|
| 12 |
-
- han-xudong/ballnet-100k
|
| 13 |
-
---
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
}
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: bsd-3-clause
|
| 3 |
+
pipeline_tag: robotics
|
| 4 |
+
tags:
|
| 5 |
+
- ballnet
|
| 6 |
+
- metaball
|
| 7 |
+
- multimodal
|
| 8 |
+
- onnx
|
| 9 |
+
- pytorch
|
| 10 |
+
library_name: transformers
|
| 11 |
+
datasets:
|
| 12 |
+
- han-xudong/ballnet-100k
|
| 13 |
+
---
|
| 14 |
+
|
| 15 |
+
# Model Card for BallNet
|
| 16 |
+
|
| 17 |
+
## Table of Contents
|
| 18 |
+
|
| 19 |
+
- [Model Card for BallNet](#model-card-for-ballnet)
|
| 20 |
+
- [Table of Contents](#table-of-contents)
|
| 21 |
+
- [Model Description](#model-description)
|
| 22 |
+
- [Intended Use](#intended-use)
|
| 23 |
+
- [Training Data](#training-data)
|
| 24 |
+
- [Citation](#citation)
|
| 25 |
+
|
| 26 |
+
## Model Description
|
| 27 |
+
|
| 28 |
+
BallNet is an MLP model designed for the Metaball. It can predict both 6D force and 3D shape (mesh nodes) from the 6D motion of the ball.
|
| 29 |
+
|
| 30 |
+
Try it out on the [Spaces demo](https://huggingface.co/spaces/han-xudong/ballnet-demo).
|
| 31 |
+
|
| 32 |
+
- Developer: Xudong Han, Tianyu Wu, Fang Wan, and Chaoyang Song.
|
| 33 |
+
- Model type: MLP
|
| 34 |
+
- License: BSD-3-Clause
|
| 35 |
+
|
| 36 |
+
## Intended Use
|
| 37 |
+
|
| 38 |
+
This model is intended for researchers and developers working in robotics and tactile sensing. It can be used to enhance the capabilities of robotic systems by providing accurate predictions of force and shape based on tactile data.
|
| 39 |
+
|
| 40 |
+
To load the model:
|
| 41 |
+
|
| 42 |
+
```python
|
| 43 |
+
from transformers import AutoModel
|
| 44 |
+
|
| 45 |
+
model = AutoModel.from_pretrained("han-xudong/ballnet", trust_remote_code=True)
|
| 46 |
+
x = torch.zeros((1, 6)) # Example input: batch size of 1, 6D motion
|
| 47 |
+
output = model(x)
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
Or to load the ONNX version:
|
| 51 |
+
|
| 52 |
+
```python
|
| 53 |
+
# Example code to load onnx
|
| 54 |
+
import onnxruntime as ort
|
| 55 |
+
import numpy as np
|
| 56 |
+
from huggingface_hub import hf_hub_download
|
| 57 |
+
|
| 58 |
+
onnx_model_path = hf_hub_download("han-xudong/ballnet", filename="model.onnx")
|
| 59 |
+
ort_session = ort.InferenceSession(onnx_model_path)
|
| 60 |
+
|
| 61 |
+
# Example input
|
| 62 |
+
x = np.zeros((1, 6), dtype=np.float32) # Batch size of 1, 6D motion
|
| 63 |
+
output = ort_session.run(None, {"motion": x})
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
## Training Data
|
| 67 |
+
|
| 68 |
+
The model was trained on the [BallNet-100K](https://huggingface.co/datasets/han-xudong/ballnet-100k) dataset, which includes a variety of motion, force, and shape data collected by finite element simulations.
|
| 69 |
+
|
| 70 |
+
## Citation
|
| 71 |
+
|
| 72 |
+
If you use this model in your research, please cite the following papers:
|
| 73 |
+
|
| 74 |
+
```bibtex
|
| 75 |
+
@article{liu2024proprioceptive,
|
| 76 |
+
title={Proprioceptive learning with soft polyhedral networks},
|
| 77 |
+
author={Liu, Xiaobo and Han, Xudong and Hong, Wei and Wan, Fang and Song, Chaoyang},
|
| 78 |
+
journal={The International Journal of Robotics Research},
|
| 79 |
+
volume = {43},
|
| 80 |
+
number = {12},
|
| 81 |
+
pages = {1916-1935},
|
| 82 |
+
year = {2024},
|
| 83 |
+
publisher={SAGE Publications Sage UK: London, England},
|
| 84 |
+
doi = {10.1177/02783649241238765}
|
| 85 |
+
}
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
[](https://arxiv.org/abs/2308.08538)
|
config.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
model.onnx
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b543f9d911a78fdc5648eca294aa7e04e7edfeb441e43f4dfc3855a02e943f36
|
| 3 |
+
size 17347939
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:960574e99b9df54c0588506eb481c7e15ea0c4ff91813276edcac8a2864bec30
|
| 3 |
+
size 17346660
|
modeling.py
CHANGED
|
@@ -7,48 +7,119 @@ class BallNetConfig(PretrainedConfig):
|
|
| 7 |
|
| 8 |
def __init__(
|
| 9 |
self,
|
| 10 |
-
x_dim
|
| 11 |
-
y_dim
|
| 12 |
-
|
| 13 |
-
|
|
|
|
| 14 |
**kwargs,
|
| 15 |
):
|
| 16 |
super().__init__(**kwargs)
|
|
|
|
| 17 |
self.x_dim = x_dim
|
| 18 |
self.y_dim = y_dim
|
| 19 |
-
self.
|
| 20 |
-
self.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
|
| 23 |
-
class
|
| 24 |
config_class = BallNetConfig
|
|
|
|
|
|
|
| 25 |
|
| 26 |
-
def __init__(self, config):
|
| 27 |
super().__init__(config)
|
|
|
|
| 28 |
self.x_dim = config.x_dim
|
| 29 |
self.y_dim = config.y_dim
|
| 30 |
-
self.
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
-
self.model = nn.ModuleDict()
|
| 34 |
-
# Define the model architecture
|
| 35 |
for i in range(len(self.y_dim)):
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
nn.
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
|
|
|
|
|
|
| 45 |
self.post_init()
|
| 46 |
|
| 47 |
-
def forward(self, x):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
outputs = []
|
| 49 |
for i in range(len(self.y_dim)):
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
y = estimator(x)
|
| 53 |
outputs.append(y)
|
| 54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
def __init__(
|
| 9 |
self,
|
| 10 |
+
x_dim: List[int],
|
| 11 |
+
y_dim: List[int],
|
| 12 |
+
hidden_dim: List[List[int]],
|
| 13 |
+
mean: List[float],
|
| 14 |
+
std: List[float],
|
| 15 |
**kwargs,
|
| 16 |
):
|
| 17 |
super().__init__(**kwargs)
|
| 18 |
+
|
| 19 |
self.x_dim = x_dim
|
| 20 |
self.y_dim = y_dim
|
| 21 |
+
self.hidden_dim = hidden_dim
|
| 22 |
+
self.mean = mean
|
| 23 |
+
self.std = std
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
class Normalizer(nn.Module):
|
| 27 |
+
def __init__(self, mean: Tensor, std: Tensor, eps: float = 1e-8):
|
| 28 |
+
super().__init__()
|
| 29 |
+
self.register_buffer("mean", mean)
|
| 30 |
+
self.register_buffer("std", std)
|
| 31 |
+
self.eps = eps
|
| 32 |
+
|
| 33 |
+
def normalize(self, x: Tensor) -> Tensor:
|
| 34 |
+
return (x - self.mean) / (self.std + self.eps)
|
| 35 |
+
|
| 36 |
+
def denormalize(self, x: Tensor) -> Tensor:
|
| 37 |
+
return x * (self.std + self.eps) + self.mean
|
| 38 |
|
| 39 |
|
| 40 |
+
class BallNetModel(PreTrainedModel):
|
| 41 |
config_class = BallNetConfig
|
| 42 |
+
base_model_prefix = "ballnet"
|
| 43 |
+
supports_gradient_checkpointing = False
|
| 44 |
|
| 45 |
+
def __init__(self, config: BallNetConfig):
|
| 46 |
super().__init__(config)
|
| 47 |
+
|
| 48 |
self.x_dim = config.x_dim
|
| 49 |
self.y_dim = config.y_dim
|
| 50 |
+
self.hidden_dim = config.hidden_dim
|
| 51 |
+
|
| 52 |
+
# ---------- split mean / std ----------
|
| 53 |
+
x_mean, x_std = [], []
|
| 54 |
+
y_mean, y_std = [], []
|
| 55 |
+
|
| 56 |
+
data_dim = self.x_dim + self.y_dim
|
| 57 |
+
data_start = 0
|
| 58 |
+
|
| 59 |
+
for i, dim in enumerate(data_dim):
|
| 60 |
+
data_end = data_start + dim
|
| 61 |
+
if i < len(self.x_dim):
|
| 62 |
+
x_mean.append(config.mean[data_start:data_end])
|
| 63 |
+
x_std.append(config.std[data_start:data_end])
|
| 64 |
+
else:
|
| 65 |
+
y_mean.append(config.mean[data_start:data_end])
|
| 66 |
+
y_std.append(config.std[data_start:data_end])
|
| 67 |
+
data_start = data_end
|
| 68 |
+
|
| 69 |
+
# ---------- normalizers ----------
|
| 70 |
+
self.x_normalizers = nn.ModuleList(
|
| 71 |
+
[
|
| 72 |
+
Normalizer(
|
| 73 |
+
mean=torch.tensor(x_mean[i], dtype=torch.float32),
|
| 74 |
+
std=torch.clamp(
|
| 75 |
+
torch.tensor(x_std[i], dtype=torch.float32), min=1e-8
|
| 76 |
+
),
|
| 77 |
+
)
|
| 78 |
+
for i in range(len(self.x_dim))
|
| 79 |
+
]
|
| 80 |
+
)
|
| 81 |
+
|
| 82 |
+
self.y_normalizers = nn.ModuleList(
|
| 83 |
+
[
|
| 84 |
+
Normalizer(
|
| 85 |
+
mean=torch.tensor(y_mean[i], dtype=torch.float32),
|
| 86 |
+
std=torch.clamp(
|
| 87 |
+
torch.tensor(y_std[i], dtype=torch.float32), min=1e-8
|
| 88 |
+
),
|
| 89 |
+
)
|
| 90 |
+
for i in range(len(self.y_dim))
|
| 91 |
+
]
|
| 92 |
+
)
|
| 93 |
+
|
| 94 |
+
# ---------- estimators ----------
|
| 95 |
+
self.estimators = nn.ModuleList()
|
| 96 |
|
|
|
|
|
|
|
| 97 |
for i in range(len(self.y_dim)):
|
| 98 |
+
layers = []
|
| 99 |
+
in_dim = self.x_dim[0]
|
| 100 |
+
|
| 101 |
+
for out_dim in self.hidden_dim[i]:
|
| 102 |
+
layers.append(nn.Linear(in_dim, out_dim))
|
| 103 |
+
layers.append(nn.ReLU())
|
| 104 |
+
in_dim = out_dim
|
| 105 |
+
|
| 106 |
+
layers.append(nn.Linear(in_dim, self.y_dim[i]))
|
| 107 |
+
self.estimators.append(nn.Sequential(*layers))
|
| 108 |
+
|
| 109 |
self.post_init()
|
| 110 |
|
| 111 |
+
def forward(self, x: Tensor, **kwargs):
|
| 112 |
+
"""
|
| 113 |
+
x: (B, 6)
|
| 114 |
+
"""
|
| 115 |
+
x = self.x_normalizers[0].normalize(x)
|
| 116 |
+
|
| 117 |
outputs = []
|
| 118 |
for i in range(len(self.y_dim)):
|
| 119 |
+
y = self.estimators[i](x)
|
| 120 |
+
y = self.y_normalizers[i].denormalize(y)
|
|
|
|
| 121 |
outputs.append(y)
|
| 122 |
+
|
| 123 |
+
return {
|
| 124 |
+
"outputs": outputs
|
| 125 |
+
}
|