rlmodule 0.0.5__py3-none-any.whl
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.
- rlmodule/__init__.py +3 -0
- rlmodule/skrl/__init__.py +0 -0
- rlmodule/skrl/examples/gymnasium/skrl_gymnasium_pendulum.py +120 -0
- rlmodule/skrl/examples/gymnasium/skrl_gymnasium_pendulum_no_module.py +123 -0
- rlmodule/source/__init__.py +0 -0
- rlmodule/source/deprecated.py +378 -0
- rlmodule/source/model.py +840 -0
- rlmodule/source/modules.py +1003 -0
- rlmodule/source/rlmodel.py +771 -0
- rlmodule-0.0.5.dist-info/LICENSE +21 -0
- rlmodule-0.0.5.dist-info/METADATA +34 -0
- rlmodule-0.0.5.dist-info/RECORD +14 -0
- rlmodule-0.0.5.dist-info/WHEEL +5 -0
- rlmodule-0.0.5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,771 @@
|
|
|
1
|
+
from typing import Any, Mapping, Optional, Sequence, Tuple, Union
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import gym
|
|
5
|
+
import gymnasium
|
|
6
|
+
|
|
7
|
+
import torch
|
|
8
|
+
import torch.nn as nn
|
|
9
|
+
|
|
10
|
+
from enum import Enum
|
|
11
|
+
|
|
12
|
+
# TODO(ll): get independent of skrl
|
|
13
|
+
# also remove skrl from pyproject.toml
|
|
14
|
+
from .model import Model, Shape
|
|
15
|
+
from .deprecated import DeterministicMixin, GaussianMixin # noqa
|
|
16
|
+
|
|
17
|
+
# TODO(ll) consider moving this or part of it into skrl.models.torch
|
|
18
|
+
# TODO(ll) MultivariatGaussian, Categorical, Multicategorical
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# TODO(ll) move to base ... and call from shared as well
|
|
23
|
+
def contains_rnn_module(module: nn.Module, module_types):
|
|
24
|
+
for submodule in module.modules():
|
|
25
|
+
if isinstance(submodule, module_types):
|
|
26
|
+
return True
|
|
27
|
+
return False
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class RLModel(Model):
|
|
31
|
+
def __init__(self,
|
|
32
|
+
observation_space: Optional[Union[int, Tuple[int], gym.Space, gymnasium.Space]] = None,
|
|
33
|
+
action_space: Optional[Union[int, Tuple[int], gym.Space, gymnasium.Space]] = None,
|
|
34
|
+
input_shape: Shape = Shape.STATES,
|
|
35
|
+
device: Optional[Union[str, torch.device]] = None,
|
|
36
|
+
# TODO network, if None do pecreptron?
|
|
37
|
+
network: Optional[nn.Module] = None,
|
|
38
|
+
# TODO can be combination of various types ... mixed layer
|
|
39
|
+
# but now it is dict
|
|
40
|
+
output_layer: Optional[nn.Module] = None,
|
|
41
|
+
):
|
|
42
|
+
#TODO(ll) description
|
|
43
|
+
"""Gaussian model
|
|
44
|
+
|
|
45
|
+
:param observation_space: Observation/state space or shape (default: None).
|
|
46
|
+
If it is not None, the num_observations property will contain the size of that space
|
|
47
|
+
:type observation_space: int, tuple or list of integers, gym.Space, gymnasium.Space or None, optional
|
|
48
|
+
:param action_space: Action space or shape (default: None).
|
|
49
|
+
If it is not None, the num_actions property will contain the size of that space
|
|
50
|
+
:type action_space: int, tuple or list of integers, gym.Space, gymnasium.Space or None, optional
|
|
51
|
+
:param input_shape todo(ll)
|
|
52
|
+
:type input_shape
|
|
53
|
+
:param output_shape todo(ll)
|
|
54
|
+
:type output_shape
|
|
55
|
+
:param network todo(ll) description + optional?
|
|
56
|
+
:type network
|
|
57
|
+
:param device: Device on which a tensor/array is or will be allocated (default: ``None``).
|
|
58
|
+
If None, the device will be either ``"cuda"`` if available or ``"cpu"``
|
|
59
|
+
:type device: str or torch.device, optional
|
|
60
|
+
:param clip_actions: Flag to indicate whether the actions should be clipped (default: False)
|
|
61
|
+
:type clip_actions: bool, optional
|
|
62
|
+
:param clip_log_std: Flag to indicate whether the log standard deviations should be clipped (default: True)
|
|
63
|
+
:type clip_log_std: bool, optional
|
|
64
|
+
:param min_log_std: Minimum value of the log standard deviation (default: -20)
|
|
65
|
+
:type min_log_std: float, optional
|
|
66
|
+
:param max_log_std: Maximum value of the log standard deviation (default: 2)
|
|
67
|
+
:type max_log_std: float, optional
|
|
68
|
+
:param initial_log_std: Initial value for the log standard deviation (default: 0)
|
|
69
|
+
:type initial_log_std: float, optional
|
|
70
|
+
:param reduction: Reduction method for returning the log probability density function: (default: ``"sum"``).
|
|
71
|
+
Supported values are ``"mean"``, ``"sum"``, ``"prod"`` and ``"none"``. If "``none"``, the log probability density
|
|
72
|
+
function is returned as a tensor of shape ``(num_samples, num_actions)`` instead of ``(num_samples, 1)``
|
|
73
|
+
:type reduction: str, optional
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
super().__init__(observation_space, action_space, device)
|
|
77
|
+
# GaussianMixin.__init__(self, clip_actions, clip_log_std, min_log_std, max_log_std, reduction)
|
|
78
|
+
|
|
79
|
+
#TODO(ll) other input types ..gym, tuple?
|
|
80
|
+
#TODO(ll) ignore output scale for now because don't like, but may reintroduce
|
|
81
|
+
#TODO(ll) where is activation tanh propagated (what used to be forgotten as a bug)
|
|
82
|
+
# self.instantiator_output_scale = metadata["output_scale"]
|
|
83
|
+
|
|
84
|
+
self.input_shape = input_shape
|
|
85
|
+
|
|
86
|
+
self.net = network
|
|
87
|
+
self.output_layer = output_layer
|
|
88
|
+
|
|
89
|
+
# TODO(ll) maybe other way .. check net for lstm/rnn/gru?
|
|
90
|
+
|
|
91
|
+
self._lstm = contains_rnn_module( self, nn.LSTM)
|
|
92
|
+
self._rnn = contains_rnn_module( self, (nn.LSTM, nn.RNN, nn.GRU))
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
print("!rnn: ", self._rnn)
|
|
96
|
+
print("!lstm: ", self._lstm)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
print("!rnn: ", self._rnn)
|
|
100
|
+
print("!lstm: ", self._lstm)
|
|
101
|
+
|
|
102
|
+
# TODO(ll) one liner:
|
|
103
|
+
# self.net = nn.Sequential(network, self._get_num_units_by_shape(self.output_shape), torch.nn.Tanh())
|
|
104
|
+
|
|
105
|
+
# TODO(ll) output_units = self._get_num_units_by_shape(self.output_shape)
|
|
106
|
+
|
|
107
|
+
# TODO(ll) 512 (last hidden layer) is hardcoded.
|
|
108
|
+
#layers = [nn.Linear(512, self._get_num_units_by_shape(self.output_shape)), torch.nn.Tanh()]
|
|
109
|
+
|
|
110
|
+
# TODO(ll) propagate output activation from outside. Maybe actually propagate function, so it is easily customable and can include scaling.
|
|
111
|
+
# -- it can default to tanh here, and to identity in deterministic
|
|
112
|
+
#
|
|
113
|
+
# if metadata[0]["output_activation"] is not None:
|
|
114
|
+
# layers.append(_get_activation_function(metadata[0]["output_activation"]))
|
|
115
|
+
|
|
116
|
+
#self.mean_net = nn.Sequential(*layers)
|
|
117
|
+
|
|
118
|
+
# self.log_std_parameter = nn.Parameter(
|
|
119
|
+
# initial_log_std * torch.ones(self._get_num_units_by_shape(self.output_shape)))
|
|
120
|
+
|
|
121
|
+
#TODO(ll) only needed for LSTM, RNN, GRU .. PPO_RNN
|
|
122
|
+
#TODO(ll) consider adding it to Base model.
|
|
123
|
+
# Recurrent Neural Network (RNN) specification for RNN, LSTM and GRU layers/cells
|
|
124
|
+
def get_specification(self):
|
|
125
|
+
if self._lstm:
|
|
126
|
+
# batch size (N) is the number of envs
|
|
127
|
+
return {"rnn": {"sequence_length": self.net.sequence_length,
|
|
128
|
+
"sizes": [(self.net.num_layers, self.net.num_envs, self.net.hidden_size), # hidden states (D ∗ num_layers, N, Hout)
|
|
129
|
+
(self.net.num_layers, self.net.num_envs, self.net.hidden_size)]}} # cell states (D ∗ num_layers, N, Hcell)
|
|
130
|
+
elif self._rnn:
|
|
131
|
+
return {"rnn": {"sequence_length": self.net.sequence_length,
|
|
132
|
+
"sizes": [(self.net.num_layers, self.net.num_envs, self.net.hidden_size)]}} # hidden states (D ∗ num_layers, N, Hout)
|
|
133
|
+
else:
|
|
134
|
+
return {}
|
|
135
|
+
|
|
136
|
+
# TODO(ll) RNN & GRU has this simplier specification
|
|
137
|
+
# def get_specification(self):
|
|
138
|
+
|
|
139
|
+
# # batch size (N) is the number of envs
|
|
140
|
+
# return {"rnn": {"sequence_length": self.sequence_length,
|
|
141
|
+
# "sizes": [(self.num_layers, self.num_envs, self.hidden_size)]}} # hidden states (D ∗ num_layers, N, Hout)
|
|
142
|
+
|
|
143
|
+
def get_entropy(self, role: str = "") -> torch.Tensor:
|
|
144
|
+
"""Compute and return the entropy of the model
|
|
145
|
+
|
|
146
|
+
:return: Entropy of the model
|
|
147
|
+
:rtype: torch.Tensor
|
|
148
|
+
:param role: Role play by the model (default: ``""``)
|
|
149
|
+
:type role: str, optional
|
|
150
|
+
|
|
151
|
+
Example::
|
|
152
|
+
|
|
153
|
+
>>> entropy = model.get_entropy()
|
|
154
|
+
>>> print(entropy.shape)
|
|
155
|
+
torch.Size([4096, 8])
|
|
156
|
+
"""
|
|
157
|
+
return self.output_layer.mixin.get_entropy(role)
|
|
158
|
+
|
|
159
|
+
def distribution(self, role: str = "") -> torch.distributions.Normal:
|
|
160
|
+
"""Get the current distribution of the model
|
|
161
|
+
|
|
162
|
+
:return: Distribution of the model
|
|
163
|
+
:rtype: torch.distributions.Normal
|
|
164
|
+
:param role: Role play by the model (default: ``""``)
|
|
165
|
+
:type role: str, optional
|
|
166
|
+
|
|
167
|
+
Example::
|
|
168
|
+
|
|
169
|
+
>>> distribution = model.distribution()
|
|
170
|
+
>>> print(distribution)
|
|
171
|
+
Normal(loc: torch.Size([4096, 8]), scale: torch.Size([4096, 8]))
|
|
172
|
+
"""
|
|
173
|
+
return self.output_layer.mixin.distribution(role)
|
|
174
|
+
|
|
175
|
+
def act(self,
|
|
176
|
+
inputs: Mapping[str, Union[torch.Tensor, Any]],
|
|
177
|
+
role: str = "") -> Tuple[torch.Tensor, Union[torch.Tensor, None], Mapping[str, Union[torch.Tensor, Any]]]:
|
|
178
|
+
|
|
179
|
+
# TODO(ll) once shared model is design, you may rethink this to do by call some function pointer or whatever.
|
|
180
|
+
# or consider inheritance GaussianModelRNN
|
|
181
|
+
# TODO(ll) if one of the models is not rnn ... and PPO_RNN is called what happens?
|
|
182
|
+
if self._rnn:
|
|
183
|
+
output, output_dict = self.net(self._get_all_inputs(inputs), inputs.get('terminated', None), inputs['rnn'])
|
|
184
|
+
else:
|
|
185
|
+
|
|
186
|
+
output = self.net(self._get_all_inputs(inputs))
|
|
187
|
+
output_dict = {}
|
|
188
|
+
|
|
189
|
+
# TODO(ll) passing by independetly as together sequential has just one input in forward
|
|
190
|
+
# potentially can be done that output dict would be propagated through mean net (mean net overload forward)
|
|
191
|
+
|
|
192
|
+
return self.output_layer(output, inputs.get('taken_actions', None), output_dict)
|
|
193
|
+
|
|
194
|
+
# TODO(ll)
|
|
195
|
+
# CNN
|
|
196
|
+
# 1) changing shape if it comes in linear fashion of input, check how I was doing this.
|
|
197
|
+
# def compute(self, inputs, role):
|
|
198
|
+
# # permute (samples, width * height * channels) -> (samples, channels, width, height)
|
|
199
|
+
# return self.net(inputs["states"].view(-1, *self.observation_space.shape).permute(0, 3, 1, 2)), self.log_std_parameter, {}
|
|
200
|
+
# 2) what with that weird Shapes? search for taken_actions, who called it with this input. How should CNN be applied to such things..just in states?
|
|
201
|
+
|
|
202
|
+
# TODO(ll) output scale removed .. check that tanh where is
|
|
203
|
+
# return output * self.instantiator_output_scale, self.log_std_parameter, {}
|
|
204
|
+
return output, self.log_std_parameter, output_dict
|
|
205
|
+
|
|
206
|
+
class SharedRLModel(Model):
|
|
207
|
+
def __init__(self,
|
|
208
|
+
observation_space: Optional[Union[int, Tuple[int], gym.Space, gymnasium.Space]] = None,
|
|
209
|
+
action_space: Optional[Union[int, Tuple[int], gym.Space, gymnasium.Space]] = None,
|
|
210
|
+
input_shape: Shape = Shape.STATES, # TODO get rid of this?
|
|
211
|
+
device: Optional[Union[str, torch.device]] = None,
|
|
212
|
+
# TODO network, if None do pecreptron?
|
|
213
|
+
network: Optional[nn.Module] = None,
|
|
214
|
+
# TODO can be combination of various types ... mixed layer
|
|
215
|
+
# but now it is dict
|
|
216
|
+
output_layer: Optional[nn.Module] = None,
|
|
217
|
+
):
|
|
218
|
+
#TODO(ll) description
|
|
219
|
+
"""Gaussian model
|
|
220
|
+
|
|
221
|
+
:param observation_space: Observation/state space or shape (default: None).
|
|
222
|
+
If it is not None, the num_observations property will contain the size of that space
|
|
223
|
+
:type observation_space: int, tuple or list of integers, gym.Space, gymnasium.Space or None, optional
|
|
224
|
+
:param action_space: Action space or shape (default: None).
|
|
225
|
+
If it is not None, the num_actions property will contain the size of that space
|
|
226
|
+
:type action_space: int, tuple or list of integers, gym.Space, gymnasium.Space or None, optional
|
|
227
|
+
:param input_shape todo(ll)
|
|
228
|
+
:type input_shape
|
|
229
|
+
:param output_shape todo(ll)
|
|
230
|
+
:type output_shape
|
|
231
|
+
:param network todo(ll) description + optional?
|
|
232
|
+
:type network
|
|
233
|
+
:param device: Device on which a tensor/array is or will be allocated (default: ``None``).
|
|
234
|
+
If None, the device will be either ``"cuda"`` if available or ``"cpu"``
|
|
235
|
+
:type device: str or torch.device, optional
|
|
236
|
+
:param clip_actions: Flag to indicate whether the actions should be clipped (default: False)
|
|
237
|
+
:type clip_actions: bool, optional
|
|
238
|
+
:param clip_log_std: Flag to indicate whether the log standard deviations should be clipped (default: True)
|
|
239
|
+
:type clip_log_std: bool, optional
|
|
240
|
+
:param min_log_std: Minimum value of the log standard deviation (default: -20)
|
|
241
|
+
:type min_log_std: float, optional
|
|
242
|
+
:param max_log_std: Maximum value of the log standard deviation (default: 2)
|
|
243
|
+
:type max_log_std: float, optional
|
|
244
|
+
:param initial_log_std: Initial value for the log standard deviation (default: 0)
|
|
245
|
+
:type initial_log_std: float, optional
|
|
246
|
+
:param reduction: Reduction method for returning the log probability density function: (default: ``"sum"``).
|
|
247
|
+
Supported values are ``"mean"``, ``"sum"``, ``"prod"`` and ``"none"``. If "``none"``, the log probability density
|
|
248
|
+
function is returned as a tensor of shape ``(num_samples, num_actions)`` instead of ``(num_samples, 1)``
|
|
249
|
+
:type reduction: str, optional
|
|
250
|
+
"""
|
|
251
|
+
|
|
252
|
+
super().__init__(observation_space, action_space, device)
|
|
253
|
+
# GaussianMixin.__init__(self, clip_actions, clip_log_std, min_log_std, max_log_std, reduction)
|
|
254
|
+
|
|
255
|
+
#TODO(ll) other input types ..gym, tuple?
|
|
256
|
+
#TODO(ll) ignore output scale for now because don't like, but may reintroduce
|
|
257
|
+
#TODO(ll) where is activation tanh propagated (what used to be forgotten as a bug)
|
|
258
|
+
# self.instantiator_output_scale = metadata["output_scale"]
|
|
259
|
+
|
|
260
|
+
self.input_shape = input_shape
|
|
261
|
+
|
|
262
|
+
self.net = network
|
|
263
|
+
# self.output_layer = output_layer
|
|
264
|
+
|
|
265
|
+
self.policy_output_layer = output_layer["policy"]
|
|
266
|
+
self.value_output_layer = output_layer["value"]
|
|
267
|
+
|
|
268
|
+
self._lstm = contains_rnn_module( self, nn.LSTM)
|
|
269
|
+
self._rnn = contains_rnn_module( self, (nn.LSTM, nn.RNN, nn.GRU))
|
|
270
|
+
|
|
271
|
+
print("!rnn: ", self._rnn)
|
|
272
|
+
print("!lstm: ", self._lstm)
|
|
273
|
+
|
|
274
|
+
# caching for shared forward pass for policy and value roles
|
|
275
|
+
self._cached_states = None
|
|
276
|
+
self._cached_outputs = None
|
|
277
|
+
|
|
278
|
+
# TODO(ll) one liner:
|
|
279
|
+
# self.net = nn.Sequential(network, self._get_num_units_by_shape(self.output_shape), torch.nn.Tanh())
|
|
280
|
+
|
|
281
|
+
# TODO(ll) output_units = self._get_num_units_by_shape(self.output_shape)
|
|
282
|
+
|
|
283
|
+
# TODO(ll) 512 (last hidden layer) is hardcoded.
|
|
284
|
+
#layers = [nn.Linear(512, self._get_num_units_by_shape(self.output_shape)), torch.nn.Tanh()]
|
|
285
|
+
|
|
286
|
+
# TODO(ll) propagate output activation from outside. Maybe actually propagate function, so it is easily customable and can include scaling.
|
|
287
|
+
# -- it can default to tanh here, and to identity in deterministic
|
|
288
|
+
#
|
|
289
|
+
# if metadata[0]["output_activation"] is not None:
|
|
290
|
+
# layers.append(_get_activation_function(metadata[0]["output_activation"]))
|
|
291
|
+
|
|
292
|
+
#self.mean_net = nn.Sequential(*layers)
|
|
293
|
+
|
|
294
|
+
# self.log_std_parameter = nn.Parameter(
|
|
295
|
+
# initial_log_std * torch.ones(self._get_num_units_by_shape(self.output_shape)))
|
|
296
|
+
|
|
297
|
+
#TODO(ll) only needed for LSTM, RNN, GRU .. PPO_RNN
|
|
298
|
+
#TODO(ll) consider adding it to Base model.
|
|
299
|
+
# Recurrent Neural Network (RNN) specification for RNN, LSTM and GRU layers/cells
|
|
300
|
+
def get_specification(self):
|
|
301
|
+
if self._lstm:
|
|
302
|
+
# batch size (N) is the number of envs
|
|
303
|
+
return {"rnn": {"sequence_length": self.net.sequence_length,
|
|
304
|
+
"sizes": [(self.net.num_layers, self.net.num_envs, self.net.hidden_size), # hidden states (D ∗ num_layers, N, Hout)
|
|
305
|
+
(self.net.num_layers, self.net.num_envs, self.net.hidden_size)]}} # cell states (D ∗ num_layers, N, Hcell)
|
|
306
|
+
elif self._rnn:
|
|
307
|
+
return {"rnn": {"sequence_length": self.net.sequence_length,
|
|
308
|
+
"sizes": [(self.net.num_layers, self.net.num_envs, self.net.hidden_size)]}} # hidden states (D ∗ num_layers, N, Hout)
|
|
309
|
+
else:
|
|
310
|
+
return {}
|
|
311
|
+
|
|
312
|
+
def get_entropy(self, role: str = "") -> torch.Tensor:
|
|
313
|
+
"""Compute and return the entropy of the model
|
|
314
|
+
|
|
315
|
+
:return: Entropy of the model
|
|
316
|
+
:rtype: torch.Tensor
|
|
317
|
+
:param role: Role play by the model (default: ``""``)
|
|
318
|
+
:type role: str, optional
|
|
319
|
+
|
|
320
|
+
Example::
|
|
321
|
+
|
|
322
|
+
>>> entropy = model.get_entropy()
|
|
323
|
+
>>> print(entropy.shape)
|
|
324
|
+
torch.Size([4096, 8])
|
|
325
|
+
"""
|
|
326
|
+
return self.policy_output_layer.mixin.get_entropy(role)
|
|
327
|
+
|
|
328
|
+
def distribution(self, role: str = "") -> torch.distributions.Normal:
|
|
329
|
+
"""Get the current distribution of the model
|
|
330
|
+
|
|
331
|
+
:return: Distribution of the model
|
|
332
|
+
:rtype: torch.distributions.Normal
|
|
333
|
+
:param role: Role play by the model (default: ``""``)
|
|
334
|
+
:type role: str, optional
|
|
335
|
+
|
|
336
|
+
Example::
|
|
337
|
+
|
|
338
|
+
>>> distribution = model.distribution()
|
|
339
|
+
>>> print(distribution)
|
|
340
|
+
Normal(loc: torch.Size([4096, 8]), scale: torch.Size([4096, 8]))
|
|
341
|
+
"""
|
|
342
|
+
return self.policy_output_layer.mixin.distribution(role)
|
|
343
|
+
|
|
344
|
+
def _have_cached_states(self, states):
|
|
345
|
+
return (self._cached_states is not None
|
|
346
|
+
and torch.equal(self._cached_states, states)
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
def act(self,
|
|
350
|
+
inputs: Mapping[str, Union[torch.Tensor, Any]],
|
|
351
|
+
role: str = "") -> Tuple[torch.Tensor, Union[torch.Tensor, None], Mapping[str, Union[torch.Tensor, Any]]]:
|
|
352
|
+
|
|
353
|
+
states = self._get_all_inputs(inputs) # TODO(ll) rename to get_all_states
|
|
354
|
+
|
|
355
|
+
if not self._have_cached_states(states):
|
|
356
|
+
# TODO(ll) if one of the models is not rnn ... and PPO_RNN is called what happens?
|
|
357
|
+
if self._rnn:
|
|
358
|
+
output, output_dict = self.net(states, inputs.get('terminated', None), inputs['rnn'])
|
|
359
|
+
else:
|
|
360
|
+
output = self.net(states)
|
|
361
|
+
output_dict = {}
|
|
362
|
+
|
|
363
|
+
self._cached_states = states
|
|
364
|
+
self._cached_output = output, output_dict
|
|
365
|
+
|
|
366
|
+
output, output_dict = self._cached_output
|
|
367
|
+
|
|
368
|
+
if role == "policy":
|
|
369
|
+
return self.policy_output_layer(output, inputs.get('taken_actions', None), output_dict)
|
|
370
|
+
elif role == "value":
|
|
371
|
+
return self.value_output_layer(output, inputs.get('taken_actions', None), output_dict)
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
# TODO(ll)
|
|
377
|
+
# CNN
|
|
378
|
+
# 1) changing shape if it comes in linear fashion of input, check how I was doing this.
|
|
379
|
+
# def compute(self, inputs, role):
|
|
380
|
+
# # permute (samples, width * height * channels) -> (samples, channels, width, height)
|
|
381
|
+
# return self.net(inputs["states"].view(-1, *self.observation_space.shape).permute(0, 3, 1, 2)), self.log_std_parameter, {}
|
|
382
|
+
# 2) what with that weird Shapes? search for taken_actions, who called it with this input. How should CNN be applied to such things..just in states?
|
|
383
|
+
|
|
384
|
+
# TODO(ll) output scale removed .. check that tanh where is
|
|
385
|
+
# return output * self.instantiator_output_scale, self.log_std_parameter, {}
|
|
386
|
+
# return output, self.log_std_parameter, output_dict
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
class GaussianLayer(nn.Module):
|
|
390
|
+
def __init__(self,
|
|
391
|
+
input_size, # TODO(ll)
|
|
392
|
+
output_size, # TODO(ll) allow here the Box input type and handle or throw away shapes.
|
|
393
|
+
device,
|
|
394
|
+
output_shape: Shape = Shape.ACTIONS,
|
|
395
|
+
output_activation: nn.Module = nn.Tanh(),
|
|
396
|
+
clip_actions: bool = False,
|
|
397
|
+
clip_log_std: bool = True,
|
|
398
|
+
min_log_std: float = -20,
|
|
399
|
+
max_log_std: float = 2,
|
|
400
|
+
initial_log_std: float = 0,
|
|
401
|
+
reduction="sum",
|
|
402
|
+
):
|
|
403
|
+
"""Gaussian model
|
|
404
|
+
|
|
405
|
+
:param observation_space: Observation/state space or shape (default: None).
|
|
406
|
+
If it is not None, the num_observations property will contain the size of that space
|
|
407
|
+
:type observation_space: int, tuple or list of integers, gym.Space, gymnasium.Space or None, optional
|
|
408
|
+
:param action_space: Action space or shape (default: None).
|
|
409
|
+
If it is not None, the num_actions property will contain the size of that space
|
|
410
|
+
:type action_space: int, tuple or list of integers, gym.Space, gymnasium.Space or None, optional
|
|
411
|
+
:param input_shape todo(ll)
|
|
412
|
+
:type input_shape
|
|
413
|
+
:param output_shape todo(ll)
|
|
414
|
+
:type output_shape
|
|
415
|
+
:param network todo(ll) description + optional?
|
|
416
|
+
:type network
|
|
417
|
+
:param device: Device on which a tensor/array is or will be allocated (default: ``None``).
|
|
418
|
+
If None, the device will be either ``"cuda"`` if available or ``"cpu"``
|
|
419
|
+
:type device: str or torch.device, optional
|
|
420
|
+
:param clip_actions: Flag to indicate whether the actions should be clipped (default: False)
|
|
421
|
+
:type clip_actions: bool, optional
|
|
422
|
+
:param clip_log_std: Flag to indicate whether the log standard deviations should be clipped (default: True)
|
|
423
|
+
:type clip_log_std: bool, optional
|
|
424
|
+
:param min_log_std: Minimum value of the log standard deviation (default: -20)
|
|
425
|
+
:type min_log_std: float, optional
|
|
426
|
+
:param max_log_std: Maximum value of the log standard deviation (default: 2)
|
|
427
|
+
:type max_log_std: float, optional
|
|
428
|
+
:param initial_log_std: Initial value for the log standard deviation (default: 0)
|
|
429
|
+
:type initial_log_std: float, optional
|
|
430
|
+
:param reduction: Reduction method for returning the log probability density function: (default: ``"sum"``).
|
|
431
|
+
Supported values are ``"mean"``, ``"sum"``, ``"prod"`` and ``"none"``. If "``none"``, the log probability density
|
|
432
|
+
function is returned as a tensor of shape ``(num_samples, num_actions)`` instead of ``(num_samples, 1)``
|
|
433
|
+
:type reduction: str, optional
|
|
434
|
+
"""
|
|
435
|
+
super().__init__()
|
|
436
|
+
# GaussianMixin.__init__(self, clip_actions, clip_log_std, min_log_std, max_log_std, reduction)
|
|
437
|
+
|
|
438
|
+
self.mixin = GaussianMixin(clip_actions, clip_log_std, min_log_std, max_log_std, reduction)
|
|
439
|
+
|
|
440
|
+
#TODO(ll) !!!!!!! propagate device TODO(ll) is device used somewhere, A: it is used in Mixin and not propagated yet.
|
|
441
|
+
self.device=device
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
#TODO(ll) ignore output scale for now because don't like, but may reintroduce
|
|
445
|
+
#TODO(ll) where is activation tanh propagated (what used to be forgotten as a bug)
|
|
446
|
+
# self.instantiator_output_scale = metadata["output_scale"]
|
|
447
|
+
|
|
448
|
+
self.output_shape = output_shape
|
|
449
|
+
# self.output_activation = output_activation
|
|
450
|
+
|
|
451
|
+
# TODO(ll) propagate output activation from outside. Maybe actually propagate function, so it is easily customable and can include scaling.
|
|
452
|
+
# -- it can default to tanh here, and to identity in deterministic
|
|
453
|
+
#
|
|
454
|
+
# if metadata[0]["output_activation"] is not None:
|
|
455
|
+
# layers.append(_get_activation_function(metadata[0]["output_activation"]))
|
|
456
|
+
|
|
457
|
+
self.net = nn.Sequential(
|
|
458
|
+
nn.Linear(input_size, output_size), # self._get_num_units_by_shape(self.output_shape)),
|
|
459
|
+
output_activation)
|
|
460
|
+
|
|
461
|
+
self.log_std_parameter = nn.Parameter(
|
|
462
|
+
initial_log_std * torch.ones( output_size )) #self._get_num_units_by_shape(self.output_shape)))
|
|
463
|
+
|
|
464
|
+
# TODO(ll) this already lives in Model. move to utils
|
|
465
|
+
def _get_num_units_by_shape(self, shape: Shape) -> int:
|
|
466
|
+
"""Get the number of units in a layer by shape
|
|
467
|
+
|
|
468
|
+
:param model: Model to get the number of units for
|
|
469
|
+
:type model: Model
|
|
470
|
+
:param shape: Shape of the layer
|
|
471
|
+
:type shape: Shape or int
|
|
472
|
+
|
|
473
|
+
:return: Number of units in the layer
|
|
474
|
+
:rtype: int
|
|
475
|
+
"""
|
|
476
|
+
num_units = {Shape.ONE: 1,
|
|
477
|
+
Shape.STATES: self.num_observations,
|
|
478
|
+
Shape.ACTIONS: self.num_actions,
|
|
479
|
+
Shape.STATES_ACTIONS: self.num_observations + self.num_actions}
|
|
480
|
+
try:
|
|
481
|
+
return num_units[shape]
|
|
482
|
+
except:
|
|
483
|
+
return shape
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
def forward(self, input, taken_actions, outputs_dict):
|
|
487
|
+
|
|
488
|
+
# TODO(ll) passing by independetly as together sequential has just one input in forward
|
|
489
|
+
# potentially can be done that output dict would be propagated through mean net (mean net overload forward)
|
|
490
|
+
mean_actions = self.net(input)
|
|
491
|
+
|
|
492
|
+
#TODO
|
|
493
|
+
return self.mixin.forward(mean_actions, taken_actions, self.log_std_parameter, outputs_dict)
|
|
494
|
+
|
|
495
|
+
# TODO(ll)
|
|
496
|
+
# CNN
|
|
497
|
+
# 1) changing shape if it comes in linear fashion of input, check how I was doing this.
|
|
498
|
+
# def compute(self, inputs, role):
|
|
499
|
+
# # permute (samples, width * height * channels) -> (samples, channels, width, height)
|
|
500
|
+
# return self.net(inputs["states"].view(-1, *self.observation_space.shape).permute(0, 3, 1, 2)), self.log_std_parameter, {}
|
|
501
|
+
# 2) what with that weird Shapes? search for taken_actions, who called it with this input. How should CNN be applied to such things..just in states?
|
|
502
|
+
|
|
503
|
+
# TODO(ll) output scale removed .. check that tanh where is
|
|
504
|
+
# return output * self.instantiator_output_scale, self.log_std_parameter, {}
|
|
505
|
+
return output, self.log_std_parameter, output_dict
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
class DeterministicLayer(torch.nn.Module, DeterministicMixin):
|
|
509
|
+
def __init__(self,
|
|
510
|
+
input_size,
|
|
511
|
+
output_size,
|
|
512
|
+
device,
|
|
513
|
+
output_shape: Shape = Shape.ONE,
|
|
514
|
+
output_activation: nn.Module = nn.Tanh(),
|
|
515
|
+
clip_actions: bool = False,
|
|
516
|
+
):
|
|
517
|
+
"""Deterministic model
|
|
518
|
+
|
|
519
|
+
TODO(ll) update doc string
|
|
520
|
+
:param observation_space: Observation/state space or shape (default: None).
|
|
521
|
+
If it is not None, the num_observations property will contain the size of that space
|
|
522
|
+
:type observation_space: int, tuple or list of integers, gym.Space, gymnasium.Space or None, optional
|
|
523
|
+
:param action_space: Action space or shape (default: None).
|
|
524
|
+
If it is not None, the num_actions property will contain the size of that space
|
|
525
|
+
:type action_space: int, tuple or list of integers, gym.Space, gymnasium.Space or None, optional
|
|
526
|
+
:param device: Device on which a tensor/array is or will be allocated (default: ``None``).
|
|
527
|
+
If None, the device will be either ``"cuda"`` if available or ``"cpu"``
|
|
528
|
+
:type device: str or torch.device, optional
|
|
529
|
+
:param clip_actions: Flag to indicate whether the actions should be clipped to the action space (default: False)
|
|
530
|
+
:type clip_actions: bool, optional
|
|
531
|
+
:param input_shape: Shape of the input (default: Shape.STATES)
|
|
532
|
+
:type input_shape: Shape, optional
|
|
533
|
+
:param hiddens: Number of hidden units in each hidden layer
|
|
534
|
+
:type hiddens: int or list of ints
|
|
535
|
+
:param hidden_activation: Activation function for each hidden layer (default: "relu").
|
|
536
|
+
:type hidden_activation: list of strings
|
|
537
|
+
:param output_shape: Shape of the output (default: Shape.ACTIONS)
|
|
538
|
+
:type output_shape: Shape, optional
|
|
539
|
+
:param output_activation: Activation function for the output layer (default: "tanh")
|
|
540
|
+
:type output_activation: str or None, optional
|
|
541
|
+
:param output_scale: Scale of the output layer (default: 1.0).
|
|
542
|
+
If None, the output layer will not be scaled
|
|
543
|
+
:type output_scale: float, optional
|
|
544
|
+
|
|
545
|
+
:return: Deterministic model instance
|
|
546
|
+
:rtype: Model
|
|
547
|
+
"""
|
|
548
|
+
|
|
549
|
+
super().__init__()
|
|
550
|
+
self.mixin = DeterministicMixin(clip_actions)
|
|
551
|
+
|
|
552
|
+
#TODO(ll) !!!!!!propagate device
|
|
553
|
+
self.device=device
|
|
554
|
+
|
|
555
|
+
self.output_shape = output_shape
|
|
556
|
+
|
|
557
|
+
self.net = nn.Sequential(
|
|
558
|
+
nn.Linear(input_size, output_size), # self._get_num_units_by_shape(self.output_shape)),
|
|
559
|
+
output_activation
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
def forward(self, input, taken_actions, outputs_dict):
|
|
563
|
+
|
|
564
|
+
output = self.net(input)
|
|
565
|
+
return self.mixin.forward(output, outputs_dict)
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
# class GaussianModel(GaussianMixin, Model):
|
|
570
|
+
# def __init__(self,
|
|
571
|
+
# observation_space: Optional[Union[int, Tuple[int], gym.Space, gymnasium.Space]] = None,
|
|
572
|
+
# action_space: Optional[Union[int, Tuple[int], gym.Space, gymnasium.Space]] = None,
|
|
573
|
+
# # TODO network, if None do pecreptron?
|
|
574
|
+
# network: Optional[nn.Module] = None,
|
|
575
|
+
# device: Optional[Union[str, torch.device]] = None,
|
|
576
|
+
# clip_actions: bool = False,
|
|
577
|
+
# clip_log_std: bool = True,
|
|
578
|
+
# min_log_std: float = -20,
|
|
579
|
+
# max_log_std: float = 2,
|
|
580
|
+
# initial_log_std: float = 0,
|
|
581
|
+
# input_shape: Shape = Shape.STATES,
|
|
582
|
+
# output_shape: Shape = Shape.ACTIONS,
|
|
583
|
+
# reduction="sum",
|
|
584
|
+
# ):
|
|
585
|
+
# """Gaussian model
|
|
586
|
+
|
|
587
|
+
# :param observation_space: Observation/state space or shape (default: None).
|
|
588
|
+
# If it is not None, the num_observations property will contain the size of that space
|
|
589
|
+
# :type observation_space: int, tuple or list of integers, gym.Space, gymnasium.Space or None, optional
|
|
590
|
+
# :param action_space: Action space or shape (default: None).
|
|
591
|
+
# If it is not None, the num_actions property will contain the size of that space
|
|
592
|
+
# :type action_space: int, tuple or list of integers, gym.Space, gymnasium.Space or None, optional
|
|
593
|
+
# :param input_shape todo(ll)
|
|
594
|
+
# :type input_shape
|
|
595
|
+
# :param output_shape todo(ll)
|
|
596
|
+
# :type output_shape
|
|
597
|
+
# :param network todo(ll) description + optional?
|
|
598
|
+
# :type network
|
|
599
|
+
# :param device: Device on which a tensor/array is or will be allocated (default: ``None``).
|
|
600
|
+
# If None, the device will be either ``"cuda"`` if available or ``"cpu"``
|
|
601
|
+
# :type device: str or torch.device, optional
|
|
602
|
+
# :param clip_actions: Flag to indicate whether the actions should be clipped (default: False)
|
|
603
|
+
# :type clip_actions: bool, optional
|
|
604
|
+
# :param clip_log_std: Flag to indicate whether the log standard deviations should be clipped (default: True)
|
|
605
|
+
# :type clip_log_std: bool, optional
|
|
606
|
+
# :param min_log_std: Minimum value of the log standard deviation (default: -20)
|
|
607
|
+
# :type min_log_std: float, optional
|
|
608
|
+
# :param max_log_std: Maximum value of the log standard deviation (default: 2)
|
|
609
|
+
# :type max_log_std: float, optional
|
|
610
|
+
# :param initial_log_std: Initial value for the log standard deviation (default: 0)
|
|
611
|
+
# :type initial_log_std: float, optional
|
|
612
|
+
# :param reduction: Reduction method for returning the log probability density function: (default: ``"sum"``).
|
|
613
|
+
# Supported values are ``"mean"``, ``"sum"``, ``"prod"`` and ``"none"``. If "``none"``, the log probability density
|
|
614
|
+
# function is returned as a tensor of shape ``(num_samples, num_actions)`` instead of ``(num_samples, 1)``
|
|
615
|
+
# :type reduction: str, optional
|
|
616
|
+
# """
|
|
617
|
+
|
|
618
|
+
# Model.__init__(self, observation_space, action_space, device)
|
|
619
|
+
# GaussianMixin.__init__(self, clip_actions, clip_log_std, min_log_std, max_log_std, reduction)
|
|
620
|
+
|
|
621
|
+
# #TODO(ll) other input types ..gym, tuple?
|
|
622
|
+
# #TODO(ll) ignore output scale for now because don't like, but may reintroduce
|
|
623
|
+
# #TODO(ll) where is activation tanh propagated (what used to be forgotten as a bug)
|
|
624
|
+
# # self.instantiator_output_scale = metadata["output_scale"]
|
|
625
|
+
|
|
626
|
+
# self.input_shape = input_shape
|
|
627
|
+
# self.output_shape = output_shape
|
|
628
|
+
|
|
629
|
+
# self.net = network
|
|
630
|
+
|
|
631
|
+
# # TODO(ll) maybe other way .. check net for lstm/rnn/gru?
|
|
632
|
+
# self._rnn = hasattr(self.net, 'sequence_length')
|
|
633
|
+
|
|
634
|
+
# # TODO(ll) one liner:
|
|
635
|
+
# # self.net = nn.Sequential(network, self._get_num_units_by_shape(self.output_shape), torch.nn.Tanh())
|
|
636
|
+
|
|
637
|
+
# # TODO(ll) output_units = self._get_num_units_by_shape(self.output_shape)
|
|
638
|
+
|
|
639
|
+
# # TODO(ll) 512 (last hidden layer) is hardcoded.
|
|
640
|
+
# layers = [nn.Linear(512, self._get_num_units_by_shape(self.output_shape)), torch.nn.Tanh()]
|
|
641
|
+
|
|
642
|
+
# # TODO(ll) propagate output activation from outside. Maybe actually propagate function, so it is easily customable and can include scaling.
|
|
643
|
+
# # -- it can default to tanh here, and to identity in deterministic
|
|
644
|
+
# #
|
|
645
|
+
# # if metadata[0]["output_activation"] is not None:
|
|
646
|
+
# # layers.append(_get_activation_function(metadata[0]["output_activation"]))
|
|
647
|
+
|
|
648
|
+
# self.mean_net = nn.Sequential(*layers)
|
|
649
|
+
|
|
650
|
+
# self.log_std_parameter = nn.Parameter(
|
|
651
|
+
# initial_log_std * torch.ones(self._get_num_units_by_shape(self.output_shape)))
|
|
652
|
+
|
|
653
|
+
# #TODO(ll) only needed for LSTM, RNN, GRU .. PPO_RNN
|
|
654
|
+
# #TODO(ll) consider adding it to Base model.
|
|
655
|
+
# # Recurrent Neural Network (RNN) specification for RNN, LSTM and GRU layers/cells
|
|
656
|
+
# def get_specification(self):
|
|
657
|
+
# if self._rnn:
|
|
658
|
+
# # batch size (N) is the number of envs
|
|
659
|
+
# return {"rnn": {"sequence_length": self.net.sequence_length,
|
|
660
|
+
# "sizes": [(self.net.num_layers, self.net.num_envs, self.net.hidden_size), # hidden states (D ∗ num_layers, N, Hout)
|
|
661
|
+
# (self.net.num_layers, self.net.num_envs, self.net.hidden_size)]}} # cell states (D ∗ num_layers, N, Hcell)
|
|
662
|
+
# else:
|
|
663
|
+
# return {}
|
|
664
|
+
|
|
665
|
+
# def compute(self, inputs, role=""):
|
|
666
|
+
|
|
667
|
+
# # TODO(ll) once shared model is design, you may rethink this to do by call some function pointer or whatever.
|
|
668
|
+
# # or consider inheritance GaussianModelRNN
|
|
669
|
+
# # TODO(ll) if one of the models is not rnn ... and PPO_RNN is called what happens?
|
|
670
|
+
# if self._rnn:
|
|
671
|
+
# output, output_dict = self.net(self._get_all_inputs(inputs), inputs.get('terminated', None), inputs['rnn'])
|
|
672
|
+
# else:
|
|
673
|
+
# output = self.net(self._get_all_inputs(inputs))
|
|
674
|
+
# output_dict = {}
|
|
675
|
+
|
|
676
|
+
# # TODO(ll) passing by independetly as together sequential has just one input in forward
|
|
677
|
+
# # potentially can be done that output dict would be propagated through mean net (mean net overload forward)
|
|
678
|
+
# output = self.mean_net(output)
|
|
679
|
+
|
|
680
|
+
# # TODO(ll)
|
|
681
|
+
# # CNN
|
|
682
|
+
# # 1) changing shape if it comes in linear fashion of input, check how I was doing this.
|
|
683
|
+
# # def compute(self, inputs, role):
|
|
684
|
+
# # # permute (samples, width * height * channels) -> (samples, channels, width, height)
|
|
685
|
+
# # return self.net(inputs["states"].view(-1, *self.observation_space.shape).permute(0, 3, 1, 2)), self.log_std_parameter, {}
|
|
686
|
+
# # 2) what with that weird Shapes? search for taken_actions, who called it with this input. How should CNN be applied to such things..just in states?
|
|
687
|
+
|
|
688
|
+
# # TODO(ll) output scale removed .. check that tanh where is
|
|
689
|
+
# # return output * self.instantiator_output_scale, self.log_std_parameter, {}
|
|
690
|
+
# return output, self.log_std_parameter, output_dict
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
# class DeterministicModel(DeterministicMixin, Model):
|
|
694
|
+
# def __init__(self,
|
|
695
|
+
# observation_space: Optional[Union[int, Tuple[int], gym.Space, gymnasium.Space]] = None,
|
|
696
|
+
# action_space: Optional[Union[int, Tuple[int], gym.Space, gymnasium.Space]] = None,
|
|
697
|
+
# network: Optional[nn.Module] = None,
|
|
698
|
+
# device: Optional[Union[str, torch.device]] = None,
|
|
699
|
+
# clip_actions: bool = False,
|
|
700
|
+
# input_shape: Shape = Shape.STATES,
|
|
701
|
+
# output_shape: Shape = Shape.ONE,
|
|
702
|
+
# ):
|
|
703
|
+
# """Deterministic model
|
|
704
|
+
|
|
705
|
+
# TODO(ll) update doc string
|
|
706
|
+
# :param observation_space: Observation/state space or shape (default: None).
|
|
707
|
+
# If it is not None, the num_observations property will contain the size of that space
|
|
708
|
+
# :type observation_space: int, tuple or list of integers, gym.Space, gymnasium.Space or None, optional
|
|
709
|
+
# :param action_space: Action space or shape (default: None).
|
|
710
|
+
# If it is not None, the num_actions property will contain the size of that space
|
|
711
|
+
# :type action_space: int, tuple or list of integers, gym.Space, gymnasium.Space or None, optional
|
|
712
|
+
# :param device: Device on which a tensor/array is or will be allocated (default: ``None``).
|
|
713
|
+
# If None, the device will be either ``"cuda"`` if available or ``"cpu"``
|
|
714
|
+
# :type device: str or torch.device, optional
|
|
715
|
+
# :param clip_actions: Flag to indicate whether the actions should be clipped to the action space (default: False)
|
|
716
|
+
# :type clip_actions: bool, optional
|
|
717
|
+
# :param input_shape: Shape of the input (default: Shape.STATES)
|
|
718
|
+
# :type input_shape: Shape, optional
|
|
719
|
+
# :param hiddens: Number of hidden units in each hidden layer
|
|
720
|
+
# :type hiddens: int or list of ints
|
|
721
|
+
# :param hidden_activation: Activation function for each hidden layer (default: "relu").
|
|
722
|
+
# :type hidden_activation: list of strings
|
|
723
|
+
# :param output_shape: Shape of the output (default: Shape.ACTIONS)
|
|
724
|
+
# :type output_shape: Shape, optional
|
|
725
|
+
# :param output_activation: Activation function for the output layer (default: "tanh")
|
|
726
|
+
# :type output_activation: str or None, optional
|
|
727
|
+
# :param output_scale: Scale of the output layer (default: 1.0).
|
|
728
|
+
# If None, the output layer will not be scaled
|
|
729
|
+
# :type output_scale: float, optional
|
|
730
|
+
|
|
731
|
+
# :return: Deterministic model instance
|
|
732
|
+
# :rtype: Model
|
|
733
|
+
# """
|
|
734
|
+
|
|
735
|
+
# Model.__init__(self, observation_space, action_space, device)
|
|
736
|
+
# DeterministicMixin.__init__(self, clip_actions)
|
|
737
|
+
|
|
738
|
+
# self.input_shape = input_shape
|
|
739
|
+
# self.output_shape = output_shape
|
|
740
|
+
|
|
741
|
+
# self.net = network
|
|
742
|
+
# self._rnn = hasattr(self.net, 'sequence_length')
|
|
743
|
+
|
|
744
|
+
# # TODO(ll) change identity by custom fction.
|
|
745
|
+
|
|
746
|
+
# # TODO(ll) 512 is hardcoded.
|
|
747
|
+
# self.deterministic_layer = nn.Sequential(
|
|
748
|
+
# nn.Linear(512, self._get_num_units_by_shape(self.output_shape)), torch.nn.Identity())
|
|
749
|
+
|
|
750
|
+
# def get_specification(self):
|
|
751
|
+
# if self._rnn:
|
|
752
|
+
# # batch size (N) is the number of envs
|
|
753
|
+
# return {"rnn": {"sequence_length": self.net.sequence_length,
|
|
754
|
+
# "sizes": [(self.net.num_layers, self.net.num_envs, self.net.hidden_size), # hidden states (D ∗ num_layers, N, Hout)
|
|
755
|
+
# (self.net.num_layers, self.net.num_envs, self.net.hidden_size)]}} # cell states (D ∗ num_layers, N, Hcell)
|
|
756
|
+
# else:
|
|
757
|
+
# return {}
|
|
758
|
+
|
|
759
|
+
# def compute(self, inputs, role=""):
|
|
760
|
+
# # TODO(ll) this block can be maybe moved into base.py if it is the same for all (where get_all_inputs live)
|
|
761
|
+
# if self._rnn:
|
|
762
|
+
# output, output_dict = self.net(self._get_all_inputs(inputs), inputs.get('terminated', None), inputs['rnn'])
|
|
763
|
+
# else:
|
|
764
|
+
# output = self.net(self._get_all_inputs(inputs))
|
|
765
|
+
# output_dict = {}
|
|
766
|
+
|
|
767
|
+
# output = self.deterministic_layer(output)
|
|
768
|
+
|
|
769
|
+
# # TODO(ll) output scale removed
|
|
770
|
+
# # return output * self.instantiator_output_scale, {}
|
|
771
|
+
# return output, output_dict
|