TimWalter commited on
Commit
c2dd7f1
·
verified ·
1 Parent(s): 9cbc334

Create model.py

Browse files
Files changed (1) hide show
  1. model.py +105 -0
model.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import re
3
+ from pathlib import Path
4
+
5
+ import torch
6
+ import torch.nn as nn
7
+ from torch import Tensor
8
+ from jaxtyping import Float
9
+ from huggingface_hub import PyTorchModelHubMixin
10
+
11
+
12
+ class Model(nn.Module, PyTorchModelHubMixin, repo_url="https://huggingface.co/TimWalter/RAM/new/main", license="mit",):
13
+ """
14
+ RAM model that predicts reachability from a modified Denavit-Hartenberg morphology parametrisation and a pose.
15
+ """
16
+
17
+ @classmethod
18
+ def from_id(cls, model_id: int):
19
+ """
20
+ Instantiate a model from its wandb ID.
21
+
22
+ Args:
23
+ model_id: Wandb ID of the model.
24
+
25
+ Returns:
26
+ model: Instantiated model.
27
+ """
28
+
29
+ model_dir = Path(__file__).parent.parent / "trained_models"
30
+ pattern = rf"{model_id}-[a-z]+-[a-z]+"
31
+ folder = next((f for f in model_dir.iterdir() if re.match(pattern, f.name)), None)
32
+ metadata_path = model_dir / folder / 'metadata.json'
33
+ metadata = json.load(open(metadata_path, 'r'))
34
+
35
+ model = cls(**metadata["hyperparameter"])
36
+ model_folder = Path(str(model_dir / folder))
37
+ prime = model_folder / "model.pth"
38
+
39
+ if prime.exists():
40
+ old_state_dict =torch.load(prime)
41
+ else:
42
+ old_state_dict =torch.load(model_folder / "checkpoint.pth")
43
+ new_state_dict = {}
44
+ # 2. Map legacy state dict keys to your new flattened structure
45
+ for key, value in old_state_dict.items():
46
+ new_key = key
47
+ if key.startswith("encoder.lstm."):
48
+ new_key = key.replace("encoder.lstm.", "encoder.")
49
+ elif key.startswith("decoder.model."):
50
+ new_key = key.replace("decoder.model.", "decoder.")
51
+
52
+ new_state_dict[new_key] = value
53
+
54
+ # Load the corrected state dict into the model
55
+ model.load_state_dict(new_state_dict)
56
+
57
+ return model
58
+
59
+ def __init__(self,
60
+ dim_encoding: int = 128,
61
+ num_encoder_layers: int = 1,
62
+ drop_prob: float = 0.0,
63
+ dim_decoder: int = 1792,
64
+ num_decoder_layer: int = 8):
65
+ """
66
+ Initialise the model.
67
+
68
+ Args:
69
+ dim_encoding: The dimension of the latent morphology encoding.
70
+ num_encoder_layers: Number of LSTM layers.
71
+ drop_prob: Dropout probability of the LSTM.
72
+ dim_decoder: Hidden dimension of the MLP.
73
+ num_decoder_layer: Number of layers of the MLP.
74
+ """
75
+
76
+ super().__init__()
77
+ self.encoder = nn.LSTM(3, dim_encoding, num_encoder_layers, dropout=drop_prob, batch_first=True, bias=False)
78
+ self.decoder = nn.Sequential(
79
+ nn.Linear(9 + dim_encoding, dim_decoder),
80
+ nn.ReLU(),
81
+ *[nn.Sequential(nn.Linear(dim_decoder, dim_decoder), nn.ReLU())
82
+ for _ in range(num_decoder_layer)],
83
+ nn.Linear(dim_decoder, 1)
84
+ )
85
+
86
+ def forward(self, morph: Float[Tensor, "batch seq 3"], pose: Float[Tensor, "batch 9"]) -> Float[Tensor, "batch"]:
87
+ """
88
+ Predict reachability.
89
+
90
+ Args:
91
+ morph: Morphology description.
92
+ pose: Pose as vector encoded.
93
+ Returns:
94
+ Reachability logit.
95
+ """
96
+ latent = self.encoder(morph)[1][0][-1]
97
+ logit = self.decoder(torch.cat([pose, latent], dim=-1)).squeeze(-1)
98
+ return logit
99
+
100
+ @torch.inference_mode()
101
+ def predict(self, *args, **kwargs):
102
+ """
103
+ forward with inference mode
104
+ """
105
+ return self.forward(*args, **kwargs)