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,1003 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
import torch.nn as nn
|
|
3
|
+
|
|
4
|
+
# todo consider get rid of this and just pass torch.nn stuff
|
|
5
|
+
def _get_activation_function(activation: str) -> nn.Module:
|
|
6
|
+
"""Get the activation function
|
|
7
|
+
|
|
8
|
+
Supported activation functions:
|
|
9
|
+
|
|
10
|
+
- "elu"
|
|
11
|
+
- "leaky_relu"
|
|
12
|
+
- "relu"
|
|
13
|
+
- "selu"
|
|
14
|
+
- "sigmoid"
|
|
15
|
+
- "softmax"
|
|
16
|
+
- "softplus"
|
|
17
|
+
- "softsign"
|
|
18
|
+
- "tanh"
|
|
19
|
+
|
|
20
|
+
:param activation: activation function name.
|
|
21
|
+
If activation is an empty string, a placeholder will be returned (``torch.nn.Identity()``)
|
|
22
|
+
:type activation: str
|
|
23
|
+
|
|
24
|
+
:raises: ValueError if activation is not a valid activation function
|
|
25
|
+
|
|
26
|
+
:return: activation function
|
|
27
|
+
:rtype: nn.Module
|
|
28
|
+
"""
|
|
29
|
+
if not activation:
|
|
30
|
+
return torch.nn.Identity()
|
|
31
|
+
elif activation == "relu":
|
|
32
|
+
return torch.nn.ReLU()
|
|
33
|
+
elif activation == "tanh":
|
|
34
|
+
return torch.nn.Tanh()
|
|
35
|
+
elif activation == "sigmoid":
|
|
36
|
+
return torch.nn.Sigmoid()
|
|
37
|
+
elif activation == "leaky_relu":
|
|
38
|
+
return torch.nn.LeakyReLU()
|
|
39
|
+
elif activation == "elu":
|
|
40
|
+
return torch.nn.ELU()
|
|
41
|
+
elif activation == "softplus":
|
|
42
|
+
return torch.nn.Softplus()
|
|
43
|
+
elif activation == "softsign":
|
|
44
|
+
return torch.nn.Softsign()
|
|
45
|
+
elif activation == "selu":
|
|
46
|
+
return torch.nn.SELU()
|
|
47
|
+
elif activation == "softmax":
|
|
48
|
+
return torch.nn.Softmax()
|
|
49
|
+
else:
|
|
50
|
+
raise ValueError(f"Unknown activation function: {activation}")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# TODO(ll) double function, already defined in model_instantiators.py
|
|
55
|
+
def contains_rnn_module(module: nn.Module, module_types):
|
|
56
|
+
for submodule in module.modules():
|
|
57
|
+
if isinstance(submodule, module_types):
|
|
58
|
+
return True
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# TODO check for input sizes, also check if you can't just pass inputs. instead of separate thingies separated in RLModel
|
|
63
|
+
def get_output_size(module, input_shape):
|
|
64
|
+
module.train(False)
|
|
65
|
+
if isinstance(input_shape, int):
|
|
66
|
+
input_shape = (input_shape,)
|
|
67
|
+
dummy_input = torch.zeros(1, *input_shape)
|
|
68
|
+
if contains_rnn_module(module, (nn.LSTM, nn.RNN, nn.GRU)):
|
|
69
|
+
# TODO(ll) module.num_layer * bidirectional?
|
|
70
|
+
dummy_hidden = torch.zeros(module.num_layers, 1, module.hidden_size)
|
|
71
|
+
return module(dummy_input, None, (dummy_hidden, dummy_hidden))[0].view(-1).shape[0]
|
|
72
|
+
else:
|
|
73
|
+
return module(dummy_input).view(-1).shape[0]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class MLP(nn.Module):
|
|
77
|
+
def __init__(self, params):
|
|
78
|
+
super().__init__()
|
|
79
|
+
|
|
80
|
+
input_size = params['input_size']
|
|
81
|
+
hidden_units = params['hidden_units']
|
|
82
|
+
activations = params['activations']
|
|
83
|
+
|
|
84
|
+
# input layer
|
|
85
|
+
layers = [
|
|
86
|
+
nn.Linear(input_size, hidden_units[0]),
|
|
87
|
+
_get_activation_function(activations[0]),
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
# hidden layers
|
|
91
|
+
for i in range(len(hidden_units) - 1):
|
|
92
|
+
layers.append(nn.Linear(hidden_units[i], hidden_units[i + 1]))
|
|
93
|
+
layers.append(_get_activation_function(activations[i + 1]))
|
|
94
|
+
|
|
95
|
+
self.mlp = nn.Sequential(*layers)
|
|
96
|
+
|
|
97
|
+
def forward(self, input):
|
|
98
|
+
return self.mlp(input)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def example_MLP():
|
|
102
|
+
params = {'input_size': 517, 'hidden_units': [2048, 1024, 1024, 512], 'activations': ['elu', 'elu', 'elu', 'elu']}
|
|
103
|
+
return MLP(params)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def get_cnn_layer(params):
|
|
107
|
+
"""
|
|
108
|
+
Create a CNN layer based on the provided parameters and activation function.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
params (dict): Dictionary containing the parameters for the layer.
|
|
112
|
+
Expected keys are:
|
|
113
|
+
- 'type' (str): Type of the layer ('conv' for convolutional, 'pool' for pooling,
|
|
114
|
+
'dense' for fully connected).
|
|
115
|
+
- 'in_channels' (int): Number of input channels (required for 'conv' type).
|
|
116
|
+
- 'out_channels' (int): Number of output channels (required for 'conv' type).
|
|
117
|
+
- 'kernel_size' (int or tuple): Size of the kernel (required for 'conv' or 'pool' type).
|
|
118
|
+
- 'stride' (int or tuple): Stride of the convolution or pooling operation
|
|
119
|
+
(required for 'conv' or 'pool' type).
|
|
120
|
+
- 'in_features' (int): Number of input features (required for 'dense' type).
|
|
121
|
+
- 'out_features' (int): Number of output features (required for 'dense' type).
|
|
122
|
+
- 'activation' (str): Activation function to use after the layer (only for 'conv' and 'dense' types).
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
list: List containing the created layer(s). For 'conv' type, it includes the convolutional
|
|
126
|
+
layer followed by the activation function. For 'pool' type, it includes only the pooling layer.
|
|
127
|
+
For 'dense' type, it includes the fully connected layer followed by the activation function.
|
|
128
|
+
|
|
129
|
+
Raises:
|
|
130
|
+
ValueError: If the 'type' specified in params is not supported.
|
|
131
|
+
"""
|
|
132
|
+
if params['type'] == 'conv':
|
|
133
|
+
return [
|
|
134
|
+
nn.Conv2d(
|
|
135
|
+
in_channels=params['in_channels'],
|
|
136
|
+
out_channels=params['out_channels'],
|
|
137
|
+
kernel_size=params['kernel_size'],
|
|
138
|
+
stride=params['stride'],
|
|
139
|
+
),
|
|
140
|
+
_get_activation_function(params['activation']),
|
|
141
|
+
]
|
|
142
|
+
elif params['type'] == 'pool':
|
|
143
|
+
return [
|
|
144
|
+
nn.MaxPool2d(
|
|
145
|
+
kernel_size=params['kernel_size'],
|
|
146
|
+
stride=params['stride'],
|
|
147
|
+
)
|
|
148
|
+
]
|
|
149
|
+
elif params['type'] == 'dense':
|
|
150
|
+
return [
|
|
151
|
+
nn.Flatten(), # if there is 2D layer before need to be flatten to 1D.
|
|
152
|
+
nn.Linear(
|
|
153
|
+
in_features=params['in_features'],
|
|
154
|
+
out_features=params['out_features'],
|
|
155
|
+
),
|
|
156
|
+
_get_activation_function(params['activation']),
|
|
157
|
+
]
|
|
158
|
+
else:
|
|
159
|
+
raise ValueError(f"Unsupported layer type: {params['type']}")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class CNN(nn.Module):
|
|
163
|
+
def __init__(self, params):
|
|
164
|
+
super().__init__()
|
|
165
|
+
|
|
166
|
+
layers = sum([get_cnn_layer(layer_params) for layer_params in params['layers']], [])
|
|
167
|
+
self.cnn = nn.Sequential(*layers, nn.Flatten())
|
|
168
|
+
|
|
169
|
+
def forward(self, input):
|
|
170
|
+
return self.cnn(input)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def example_CNN():
|
|
174
|
+
params = {
|
|
175
|
+
'input_shape': [1, 13, 13],
|
|
176
|
+
'layers': [
|
|
177
|
+
{'type': 'conv', 'kernel_size': 3, 'stride': 2, 'in_channels': 1, 'out_channels': 32, 'activation': 'relu'},
|
|
178
|
+
{
|
|
179
|
+
'type': 'conv',
|
|
180
|
+
'kernel_size': 3,
|
|
181
|
+
'stride': 1,
|
|
182
|
+
'in_channels': 32,
|
|
183
|
+
'out_channels': 64,
|
|
184
|
+
'activation': 'relu',
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return CNN(params)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class TripleCnnAndMlp(nn.Module):
|
|
193
|
+
"""
|
|
194
|
+
Split the observation space into parts and pass some parts through different CNNs.
|
|
195
|
+
|
|
196
|
+
----------------------------------------------------------------------
|
|
197
|
+
| Network architecture (cnn shape 1x13x13) |
|
|
198
|
+
|--------------------------------------------------------------------|
|
|
199
|
+
| |
|
|
200
|
+
| 10 1x13x13 1x13x13 1x13x13 |
|
|
201
|
+
| | | | | |
|
|
202
|
+
| | CNN0 CNN1 CNN2 |
|
|
203
|
+
| | | | | |
|
|
204
|
+
| | Flatten Flatten Flatten |
|
|
205
|
+
| | | | | |
|
|
206
|
+
| |____|_________|_________| |
|
|
207
|
+
| | |
|
|
208
|
+
| Join to shape 10 + OutUnits0 + OutUnits1 + OutUnits2 |
|
|
209
|
+
| | |
|
|
210
|
+
| MLP: UNITS[0] |
|
|
211
|
+
| | |
|
|
212
|
+
| ... |
|
|
213
|
+
| | |
|
|
214
|
+
| MLP: UNITS[-1] |
|
|
215
|
+
| | |
|
|
216
|
+
| Output |
|
|
217
|
+
| |
|
|
218
|
+
----------------------------------------------------------------------
|
|
219
|
+
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
def __init__(self, cnn_params, mlp_params):
|
|
223
|
+
super().__init__()
|
|
224
|
+
self.input_shape = cnn_params['input_shape']
|
|
225
|
+
|
|
226
|
+
self.prefix_length = 10
|
|
227
|
+
self.cnn_number = 3
|
|
228
|
+
|
|
229
|
+
self.cnns = nn.ModuleList([CNN(cnn_params) for _ in range(self.cnn_number)])
|
|
230
|
+
|
|
231
|
+
mlp_params['input_size'] = self.prefix_length + self.cnn_number * get_output_size(
|
|
232
|
+
self.cnns[0], self.input_shape
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
self.mlp = MLP(mlp_params)
|
|
236
|
+
|
|
237
|
+
def forward(self, input):
|
|
238
|
+
# Split the input
|
|
239
|
+
prefix = input[:, : self.prefix_length]
|
|
240
|
+
|
|
241
|
+
c, h, w = self.input_shape
|
|
242
|
+
cnn_input = input[:, self.prefix_length :].view(-1, self.cnn_number * c, h, w)
|
|
243
|
+
|
|
244
|
+
# Forward pass through CNNs
|
|
245
|
+
cnn_outputs = []
|
|
246
|
+
for i in range(self.cnn_number):
|
|
247
|
+
cnn_output = self.cnns[i](cnn_input[:, i : i + 1, :, :]).view(input.size(0), -1)
|
|
248
|
+
cnn_outputs.append(cnn_output)
|
|
249
|
+
|
|
250
|
+
# Concatenate the outputs
|
|
251
|
+
combined = torch.cat([prefix] + cnn_outputs, dim=1)
|
|
252
|
+
|
|
253
|
+
# Forward pass through MLP
|
|
254
|
+
output = self.mlp(combined)
|
|
255
|
+
return output
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def triple_cnn_and_mlp_example():
|
|
259
|
+
cnn_params = {
|
|
260
|
+
'input_shape': [1, 13, 13],
|
|
261
|
+
'layers': [
|
|
262
|
+
{'type': 'conv', 'kernel_size': 3, 'stride': 2, 'in_channels': 1, 'out_channels': 32, 'activation': 'relu'},
|
|
263
|
+
{
|
|
264
|
+
'type': 'conv',
|
|
265
|
+
'kernel_size': 3,
|
|
266
|
+
'stride': 1,
|
|
267
|
+
'in_channels': 32,
|
|
268
|
+
'out_channels': 64,
|
|
269
|
+
'activation': 'relu',
|
|
270
|
+
},
|
|
271
|
+
],
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
mlp_params = {'hidden_units': [1024, 1024, 512], 'activations': ['elu', 'elu', 'elu']}
|
|
275
|
+
|
|
276
|
+
return TripleCnnAndMlp(cnn_params, mlp_params)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
class RnnBase(nn.Module):
|
|
280
|
+
def __init__(self, params):
|
|
281
|
+
super().__init__()
|
|
282
|
+
|
|
283
|
+
# parameters necessery for RNN, GRU and LSTM networks
|
|
284
|
+
self.num_envs = params['num_envs']
|
|
285
|
+
self.num_layers = params['num_layers']
|
|
286
|
+
self.hidden_size = params['hidden_size']
|
|
287
|
+
self.sequence_length = params['sequence_length']
|
|
288
|
+
if 'input_size' in params:
|
|
289
|
+
self.input_size = params['input_size']
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class LSTM(RnnBase):
|
|
293
|
+
|
|
294
|
+
def __init__(self, params):
|
|
295
|
+
super().__init__(params)
|
|
296
|
+
|
|
297
|
+
self.lstm = nn.LSTM(
|
|
298
|
+
input_size=self.input_size,
|
|
299
|
+
hidden_size=self.hidden_size,
|
|
300
|
+
num_layers=self.num_layers,
|
|
301
|
+
batch_first=True,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
def forward(self, states, terminated, rnn_inputs):
|
|
305
|
+
|
|
306
|
+
# Process rnn inputs
|
|
307
|
+
hidden_states, cell_states = rnn_inputs[0], rnn_inputs[1]
|
|
308
|
+
|
|
309
|
+
# Dimensions Explained
|
|
310
|
+
# ---------------------
|
|
311
|
+
# 'N' - Batch size
|
|
312
|
+
# 'L' - Sequence length
|
|
313
|
+
# 'Hin' - Input size (number of features per input at each time step)
|
|
314
|
+
# 'Hout' - Hidden size (number of features in the hidden state of the LSTM)
|
|
315
|
+
# 'HCell' - Cell state size (same as hidden size in LSTM context)
|
|
316
|
+
# 'D' - Number of directions (1 for unidirectional, 2 for bidirectional)
|
|
317
|
+
# 'num_layers' - Number of stacked LSTM layers
|
|
318
|
+
|
|
319
|
+
# training
|
|
320
|
+
if self.training:
|
|
321
|
+
# reshape (N * L, Hin) -> (N, L, Hin)
|
|
322
|
+
rnn_input = states.view(-1, self.sequence_length, states.shape[-1])
|
|
323
|
+
|
|
324
|
+
# reshape (D * num_layers, N * L, Hout) -> (D * num_layers, N, L, Hout)
|
|
325
|
+
hidden_states = hidden_states.view(self.num_layers, -1, self.sequence_length, hidden_states.shape[-1])
|
|
326
|
+
|
|
327
|
+
# reshape (D * num_layers, N * L, Hcell) -> (D * num_layers, N, L, Hcell)
|
|
328
|
+
cell_states = cell_states.view(self.num_layers, -1, self.sequence_length, cell_states.shape[-1])
|
|
329
|
+
|
|
330
|
+
# get the hidden/cell states corresponding to the first time step of the sequence for each batch.
|
|
331
|
+
hidden_states = hidden_states[:, :, 0, :].contiguous() # (D * num_layers, N, Hout)
|
|
332
|
+
cell_states = cell_states[:, :, 0, :].contiguous() # (D * num_layers, N, Hcell)
|
|
333
|
+
|
|
334
|
+
# reset the RNN state in the middle of a sequence
|
|
335
|
+
if terminated is not None and torch.any(terminated):
|
|
336
|
+
rnn_outputs = []
|
|
337
|
+
terminated = terminated.view(-1, self.sequence_length)
|
|
338
|
+
indexes = (
|
|
339
|
+
[0]
|
|
340
|
+
+ (terminated[:, :-1].any(dim=0).nonzero(as_tuple=True)[0] + 1).tolist()
|
|
341
|
+
+ [self.sequence_length]
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
for i in range(len(indexes) - 1):
|
|
345
|
+
i0, i1 = indexes[i], indexes[i + 1]
|
|
346
|
+
# Compute the RNN output for the segment of the sequence
|
|
347
|
+
rnn_output, (hidden_states, cell_states) = self.lstm(
|
|
348
|
+
rnn_input[:, i0:i1, :], (hidden_states, cell_states)
|
|
349
|
+
)
|
|
350
|
+
# Reset hidden and cell states where sequences are terminated
|
|
351
|
+
hidden_states[:, (terminated[:, i1 - 1]), :] = 0
|
|
352
|
+
cell_states[:, (terminated[:, i1 - 1]), :] = 0
|
|
353
|
+
rnn_outputs.append(rnn_output)
|
|
354
|
+
|
|
355
|
+
rnn_states = (hidden_states, cell_states)
|
|
356
|
+
rnn_output = torch.cat(rnn_outputs, dim=1)
|
|
357
|
+
# if no termination reset is needed, simply compute the RNN output
|
|
358
|
+
else:
|
|
359
|
+
rnn_output, rnn_states = self.lstm(rnn_input, (hidden_states, cell_states))
|
|
360
|
+
# rollout
|
|
361
|
+
else:
|
|
362
|
+
# reshape (N, Hin) -> (N, 1, Hin)
|
|
363
|
+
# This is done to add a sequence length dimension of 1 for processing one time step at a time
|
|
364
|
+
rnn_input = states.view(-1, 1, states.shape[-1])
|
|
365
|
+
rnn_output, rnn_states = self.lstm(rnn_input, (hidden_states, cell_states))
|
|
366
|
+
|
|
367
|
+
# reshape (N, L, D * Hout) -> (N * L, D * Hout)
|
|
368
|
+
rnn_output = torch.flatten(rnn_output, start_dim=0, end_dim=1)
|
|
369
|
+
|
|
370
|
+
return rnn_output, {'rnn': [rnn_states[0], rnn_states[1]]}
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
class RnnModule(RnnBase):
|
|
374
|
+
|
|
375
|
+
def __init__(self, params):
|
|
376
|
+
super().__init__(params)
|
|
377
|
+
|
|
378
|
+
def forward(self, states, terminated, rnn_inputs):
|
|
379
|
+
|
|
380
|
+
# Process rnn inputs
|
|
381
|
+
hidden_states = rnn_inputs[0]
|
|
382
|
+
|
|
383
|
+
# Dimensions Explained
|
|
384
|
+
# ---------------------
|
|
385
|
+
# 'N' - Batch size
|
|
386
|
+
# 'L' - Sequence length
|
|
387
|
+
# 'Hin' - Input size (number of features per input at each time step)
|
|
388
|
+
# 'Hout' - Hidden size (number of features in the hidden state of the RNN)
|
|
389
|
+
# 'D' - Number of directions (1 for unidirectional, 2 for bidirectional)
|
|
390
|
+
# 'num_layers' - Number of stacked RNN layers
|
|
391
|
+
|
|
392
|
+
# training
|
|
393
|
+
if self.training:
|
|
394
|
+
# reshape (N * L, Hin) -> (N, L, Hin)
|
|
395
|
+
rnn_input = states.view(-1, self.sequence_length, states.shape[-1])
|
|
396
|
+
|
|
397
|
+
# reshape (D * num_layers, N * L, Hout) -> (D * num_layers, N, L, Hout)
|
|
398
|
+
hidden_states = hidden_states.view(self.num_layers, -1, self.sequence_length, hidden_states.shape[-1])
|
|
399
|
+
|
|
400
|
+
# get the hidden states corresponding to the first time step of the sequence for each batch.
|
|
401
|
+
hidden_states = hidden_states[:, :, 0, :].contiguous() # (D * num_layers, N, Hout)
|
|
402
|
+
|
|
403
|
+
# reset the RNN state in the middle of a sequence
|
|
404
|
+
if terminated is not None and torch.any(terminated):
|
|
405
|
+
rnn_outputs = []
|
|
406
|
+
terminated = terminated.view(-1, self.sequence_length)
|
|
407
|
+
indexes = (
|
|
408
|
+
[0]
|
|
409
|
+
+ (terminated[:, :-1].any(dim=0).nonzero(as_tuple=True)[0] + 1).tolist()
|
|
410
|
+
+ [self.sequence_length]
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
for i in range(len(indexes) - 1):
|
|
414
|
+
i0, i1 = indexes[i], indexes[i + 1]
|
|
415
|
+
# Compute the RNN output for the segment of the sequence
|
|
416
|
+
rnn_output, hidden_states = self.rnn(rnn_input[:, i0:i1, :], hidden_states)
|
|
417
|
+
# Reset hidden states where sequences are terminated
|
|
418
|
+
hidden_states[:, (terminated[:, i1 - 1]), :] = 0
|
|
419
|
+
rnn_outputs.append(rnn_output)
|
|
420
|
+
|
|
421
|
+
rnn_output = torch.cat(rnn_outputs, dim=1)
|
|
422
|
+
# if no termination reset is needed, simply compute the RNN output
|
|
423
|
+
else:
|
|
424
|
+
rnn_output, hidden_states = self.rnn(rnn_input, hidden_states)
|
|
425
|
+
# rollout
|
|
426
|
+
else:
|
|
427
|
+
# reshape (N, Hin) -> (N, 1, Hin)
|
|
428
|
+
# This is done to add a sequence length dimension of 1 for processing one time step at a time
|
|
429
|
+
rnn_input = states.view(-1, 1, states.shape[-1])
|
|
430
|
+
rnn_output, hidden_states = self.rnn(rnn_input, hidden_states)
|
|
431
|
+
|
|
432
|
+
# reshape (N, L, D * Hout) -> (N * L, D * Hout)
|
|
433
|
+
rnn_output = torch.flatten(rnn_output, start_dim=0, end_dim=1)
|
|
434
|
+
|
|
435
|
+
return rnn_output, {'rnn': [hidden_states]}
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
class RNN(RnnModule):
|
|
439
|
+
def __init__(self, params):
|
|
440
|
+
super().__init__(params)
|
|
441
|
+
|
|
442
|
+
self.rnn = nn.RNN(
|
|
443
|
+
input_size=self.input_size,
|
|
444
|
+
hidden_size=self.hidden_size,
|
|
445
|
+
num_layers=self.num_layers,
|
|
446
|
+
batch_first=True,
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
class GRU(RnnModule):
|
|
451
|
+
def __init__(self, params):
|
|
452
|
+
super().__init__(params)
|
|
453
|
+
|
|
454
|
+
self.rnn = nn.GRU(
|
|
455
|
+
input_size=self.input_size,
|
|
456
|
+
hidden_size=self.hidden_size,
|
|
457
|
+
num_layers=self.num_layers,
|
|
458
|
+
batch_first=True,
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
def example_RNN():
|
|
463
|
+
params = {
|
|
464
|
+
'num_envs': 2048,
|
|
465
|
+
'input_size': 517,
|
|
466
|
+
'num_layers': 1,
|
|
467
|
+
'hidden_size': 512 + 256,
|
|
468
|
+
'sequence_length': 128,
|
|
469
|
+
}
|
|
470
|
+
return RNN(params)
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def example_GRU():
|
|
474
|
+
params = {
|
|
475
|
+
'num_envs': 2048,
|
|
476
|
+
'input_size': 517,
|
|
477
|
+
'num_layers': 1,
|
|
478
|
+
'hidden_size': 512 + 256,
|
|
479
|
+
'sequence_length': 128,
|
|
480
|
+
}
|
|
481
|
+
return GRU(params)
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def example_LSTM():
|
|
485
|
+
params = {
|
|
486
|
+
'num_envs': 2048,
|
|
487
|
+
'input_size': 517,
|
|
488
|
+
'num_layers': 1,
|
|
489
|
+
'hidden_size': 512 + 256,
|
|
490
|
+
'sequence_length': 32,
|
|
491
|
+
}
|
|
492
|
+
return LSTM(params)
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
class RnnMlp(RnnBase):
|
|
496
|
+
|
|
497
|
+
def __init__(self, rnn_class, rnn_params, mlp_params):
|
|
498
|
+
super().__init__(rnn_params)
|
|
499
|
+
|
|
500
|
+
self.rnn = rnn_class(rnn_params)
|
|
501
|
+
|
|
502
|
+
mlp_params['input_size'] = self.hidden_size
|
|
503
|
+
|
|
504
|
+
self.mlp = MLP(mlp_params)
|
|
505
|
+
|
|
506
|
+
def forward(self, states, terminated, rnn_inputs):
|
|
507
|
+
rnn_output, output_dict = self.rnn(states, terminated, rnn_inputs)
|
|
508
|
+
return self.mlp(rnn_output), output_dict
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def example_LstmMlp():
|
|
512
|
+
rnn_params = {
|
|
513
|
+
'num_envs': 2048,
|
|
514
|
+
'input_size': 517,
|
|
515
|
+
'num_layers': 1,
|
|
516
|
+
'hidden_size': 512 + 256,
|
|
517
|
+
'sequence_length': 128,
|
|
518
|
+
}
|
|
519
|
+
mlp_params = {
|
|
520
|
+
'hidden_units': [2048, 1024, 1024, 512],
|
|
521
|
+
'activations': ['elu', 'elu', 'elu', 'elu'],
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
return RnnMlp(LSTM, rnn_params, mlp_params)
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
def example_GruMlp():
|
|
528
|
+
rnn_params = {
|
|
529
|
+
'num_envs': 2048,
|
|
530
|
+
'input_size': 517,
|
|
531
|
+
'num_layers': 1,
|
|
532
|
+
'hidden_size': 512 + 256,
|
|
533
|
+
'sequence_length': 128,
|
|
534
|
+
}
|
|
535
|
+
mlp_params = {
|
|
536
|
+
'hidden_units': [2048, 1024, 1024, 512],
|
|
537
|
+
'activations': ['elu', 'elu', 'elu', 'elu'],
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return RnnMlp(GRU, rnn_params, mlp_params)
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
def example_RnnMlp():
|
|
544
|
+
rnn_params = {
|
|
545
|
+
'num_envs': 2048,
|
|
546
|
+
'input_size': 517,
|
|
547
|
+
'num_layers': 1,
|
|
548
|
+
'hidden_size': 512 + 256,
|
|
549
|
+
'sequence_length': 128,
|
|
550
|
+
}
|
|
551
|
+
mlp_params = {
|
|
552
|
+
'hidden_units': [2048, 1024, 1024, 512],
|
|
553
|
+
'activations': ['elu', 'elu', 'elu', 'elu'],
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
return RnnMlp(RNN, rnn_params, mlp_params)
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
class RnnMlpWithForwardedInput(RnnBase):
|
|
560
|
+
|
|
561
|
+
def __init__(self, rnn_class, rnn_params, mlp_params):
|
|
562
|
+
super().__init__(rnn_params)
|
|
563
|
+
|
|
564
|
+
self.rnn = rnn_class(rnn_params)
|
|
565
|
+
|
|
566
|
+
mlp_params['input_size'] = self.input_size + self.hidden_size
|
|
567
|
+
|
|
568
|
+
self.mlp = MLP(mlp_params)
|
|
569
|
+
|
|
570
|
+
def forward(self, states, terminated, rnn_inputs):
|
|
571
|
+
rnn_output, output_dict = self.rnn(states, terminated, rnn_inputs)
|
|
572
|
+
mlp_input = torch.cat((states, rnn_output), dim=1)
|
|
573
|
+
|
|
574
|
+
return self.mlp(mlp_input), output_dict
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def example_LstmMlpWithForwardedInput():
|
|
578
|
+
rnn_params = {
|
|
579
|
+
'num_envs': 2048,
|
|
580
|
+
'input_size': 517,
|
|
581
|
+
'num_layers': 1,
|
|
582
|
+
'hidden_size': 512 + 256,
|
|
583
|
+
'sequence_length': 128,
|
|
584
|
+
}
|
|
585
|
+
mlp_params = {
|
|
586
|
+
'hidden_units': [2048, 1024, 1024, 512],
|
|
587
|
+
'activations': ['elu', 'elu', 'elu', 'elu'],
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
return RnnMlpWithForwardedInput(LSTM, rnn_params, mlp_params)
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
def example_GruMlpWithForwardedInput():
|
|
594
|
+
rnn_params = {
|
|
595
|
+
'num_envs': 2048,
|
|
596
|
+
'input_size': 517,
|
|
597
|
+
'num_layers': 1,
|
|
598
|
+
'hidden_size': 512 + 256,
|
|
599
|
+
'sequence_length': 128,
|
|
600
|
+
}
|
|
601
|
+
mlp_params = {
|
|
602
|
+
'hidden_units': [2048, 1024, 1024, 512],
|
|
603
|
+
'activations': ['elu', 'elu', 'elu', 'elu'],
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
return RnnMlpWithForwardedInput(GRU, rnn_params, mlp_params)
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
def example_RnnMlpWithForwardedInput():
|
|
610
|
+
rnn_params = {
|
|
611
|
+
'num_envs': 2048,
|
|
612
|
+
'input_size': 517,
|
|
613
|
+
'num_layers': 1,
|
|
614
|
+
'hidden_size': 512 + 256,
|
|
615
|
+
'sequence_length': 128,
|
|
616
|
+
}
|
|
617
|
+
mlp_params = {
|
|
618
|
+
'hidden_units': [2048, 1024, 1024, 512],
|
|
619
|
+
'activations': ['elu', 'elu', 'elu', 'elu'],
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
return RnnMlpWithForwardedInput(RNN, rnn_params, mlp_params)
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
class CrazyNet(RnnBase):
|
|
626
|
+
def __init__(self, rnn_class, rnn_params, cnn_params, mlp_params):
|
|
627
|
+
super().__init__(rnn_params)
|
|
628
|
+
|
|
629
|
+
self.input_shape = cnn_params['input_shape']
|
|
630
|
+
|
|
631
|
+
self.prefix_length = 10
|
|
632
|
+
self.cnn_number = 3
|
|
633
|
+
|
|
634
|
+
self.cnns = nn.ModuleList([CNN(cnn_params) for _ in range(self.cnn_number)])
|
|
635
|
+
|
|
636
|
+
rnn_params['input_size'] = self.prefix_length + self.cnn_number * get_output_size(
|
|
637
|
+
self.cnns[0], self.input_shape
|
|
638
|
+
)
|
|
639
|
+
|
|
640
|
+
self.rnn = rnn_class(rnn_params)
|
|
641
|
+
|
|
642
|
+
mlp_params['input_size'] = self.rnn.hidden_size + self.rnn.input_size
|
|
643
|
+
|
|
644
|
+
self.mlp = MLP(mlp_params)
|
|
645
|
+
|
|
646
|
+
def forward(self, states, terminated, rnn_inputs):
|
|
647
|
+
# Split the input
|
|
648
|
+
prefix = states[:, : self.prefix_length]
|
|
649
|
+
|
|
650
|
+
c, h, w = self.input_shape
|
|
651
|
+
cnn_input = states[:, self.prefix_length :].view(-1, self.cnn_number * c, h, w)
|
|
652
|
+
|
|
653
|
+
# Forward pass through CNNs
|
|
654
|
+
cnn_outputs = []
|
|
655
|
+
for i in range(self.cnn_number):
|
|
656
|
+
cnn_output = self.cnns[i](cnn_input[:, i : i + 1, :, :]).view(states.size(0), -1)
|
|
657
|
+
cnn_outputs.append(cnn_output)
|
|
658
|
+
|
|
659
|
+
# Concatenate the outputs of prefix and CNNs
|
|
660
|
+
cnn_combined = torch.cat([prefix] + cnn_outputs, dim=1)
|
|
661
|
+
|
|
662
|
+
# Forward pass through RNN
|
|
663
|
+
rnn_output, output_dict = self.rnn(cnn_combined, terminated, rnn_inputs)
|
|
664
|
+
|
|
665
|
+
# Concatenate the outputs of RNN, CNNs and prefix
|
|
666
|
+
combined = torch.cat([cnn_combined, rnn_output], dim=1)
|
|
667
|
+
|
|
668
|
+
# Forward pass through MLP
|
|
669
|
+
output = self.mlp(combined)
|
|
670
|
+
|
|
671
|
+
return output, output_dict
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
def crazy_net_example():
|
|
675
|
+
rnn_params = {
|
|
676
|
+
'num_envs': 2048,
|
|
677
|
+
'num_layers': 1,
|
|
678
|
+
'hidden_size': 512 + 256,
|
|
679
|
+
'sequence_length': 128,
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
cnn_params = {
|
|
683
|
+
'input_shape': [1, 13, 13],
|
|
684
|
+
'layers': [
|
|
685
|
+
{'type': 'conv', 'kernel_size': 3, 'stride': 2, 'in_channels': 1, 'out_channels': 32, 'activation': 'relu'},
|
|
686
|
+
{
|
|
687
|
+
'type': 'conv',
|
|
688
|
+
'kernel_size': 3,
|
|
689
|
+
'stride': 1,
|
|
690
|
+
'in_channels': 32,
|
|
691
|
+
'out_channels': 64,
|
|
692
|
+
'activation': 'relu',
|
|
693
|
+
},
|
|
694
|
+
],
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
mlp_params = {'hidden_units': [1024, 1024, 512], 'activations': ['elu', 'elu', 'elu']}
|
|
698
|
+
|
|
699
|
+
return CrazyNet(LSTM, rnn_params, cnn_params, mlp_params)
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
# def lstm_module(model_params, observation_space, action_space, device, double_pass):
|
|
703
|
+
|
|
704
|
+
# class LSTM(nn.Module):
|
|
705
|
+
|
|
706
|
+
# def __init__(self):
|
|
707
|
+
# super().__init__()
|
|
708
|
+
|
|
709
|
+
# # lstm
|
|
710
|
+
# self.num_envs = 2048
|
|
711
|
+
# self.num_layers = 1
|
|
712
|
+
# self.hidden_size = 256 + 512
|
|
713
|
+
# self.sequence_length = 128
|
|
714
|
+
|
|
715
|
+
# self.lstm = nn.LSTM(
|
|
716
|
+
# input_size=observation_space.shape[0],
|
|
717
|
+
# hidden_size=self.hidden_size,
|
|
718
|
+
# num_layers=self.num_layers,
|
|
719
|
+
# batch_first=True,
|
|
720
|
+
# )
|
|
721
|
+
|
|
722
|
+
# # mlp
|
|
723
|
+
# input_size = self.hidden_size
|
|
724
|
+
|
|
725
|
+
# mlp_params = model_params['mlp']
|
|
726
|
+
# self.net = DEPRECATEDMLP(input_size, mlp_params['units'], device, mlp_params['activation'])
|
|
727
|
+
|
|
728
|
+
# # TODO(ll) can inherit from LSTM ..without mlp
|
|
729
|
+
# def forward(self, inputs):
|
|
730
|
+
|
|
731
|
+
# # Process rnn inputs
|
|
732
|
+
# hidden_states, cell_states = rnn_inputs[0], rnn_inputs[1]
|
|
733
|
+
|
|
734
|
+
# # Dimensions Explained
|
|
735
|
+
# # ---------------------
|
|
736
|
+
# # 'N' - Batch size
|
|
737
|
+
# # 'L' - Sequence length
|
|
738
|
+
# # 'Hin' - Input size (number of features per input at each time step)
|
|
739
|
+
# # 'Hout' - Hidden size (number of features in the hidden state of the LSTM)
|
|
740
|
+
# # 'HCell' - Cell state size (same as hidden size in LSTM context)
|
|
741
|
+
# # 'D' - Number of directions (1 for unidirectional, 2 for bidirectional)
|
|
742
|
+
# # 'num_layers' - Number of stacked LSTM layers
|
|
743
|
+
|
|
744
|
+
# # training
|
|
745
|
+
# if self.training:
|
|
746
|
+
# # reshape (N * L, Hin) -> (N, L, Hin)
|
|
747
|
+
# rnn_input = states.view(-1, self.sequence_length, states.shape[-1])
|
|
748
|
+
|
|
749
|
+
# # reshape (D * num_layers, N * L, Hout) -> (D * num_layers, N, L, Hout)
|
|
750
|
+
# hidden_states = hidden_states.view(self.num_layers, -1, self.sequence_length, hidden_states.shape[-1])
|
|
751
|
+
|
|
752
|
+
# # reshape (D * num_layers, N * L, Hcell) -> (D * num_layers, N, L, Hcell)
|
|
753
|
+
# cell_states = cell_states.view(self.num_layers, -1, self.sequence_length, cell_states.shape[-1])
|
|
754
|
+
|
|
755
|
+
# # get the hidden/cell states corresponding to the first time step of the sequence for each batch.
|
|
756
|
+
# hidden_states = hidden_states[:, :, 0, :].contiguous() # (D * num_layers, N, Hout)
|
|
757
|
+
# cell_states = cell_states[:, :, 0, :].contiguous() # (D * num_layers, N, Hcell)
|
|
758
|
+
|
|
759
|
+
# # reset the RNN state in the middle of a sequence
|
|
760
|
+
# if terminated is not None and torch.any(terminated):
|
|
761
|
+
# rnn_outputs = []
|
|
762
|
+
# terminated = terminated.view(-1, self.sequence_length)
|
|
763
|
+
# indexes = (
|
|
764
|
+
# [0]
|
|
765
|
+
# + (terminated[:, :-1].any(dim=0).nonzero(as_tuple=True)[0] + 1).tolist()
|
|
766
|
+
# + [self.sequence_length]
|
|
767
|
+
# )
|
|
768
|
+
|
|
769
|
+
# for i in range(len(indexes) - 1):
|
|
770
|
+
# i0, i1 = indexes[i], indexes[i + 1]
|
|
771
|
+
# # Compute the RNN output for the segment of the sequence
|
|
772
|
+
# rnn_output, (hidden_states, cell_states) = self.lstm(
|
|
773
|
+
# rnn_input[:, i0:i1, :], (hidden_states, cell_states)
|
|
774
|
+
# )
|
|
775
|
+
# # Reset hidden and cell states where sequences are terminated
|
|
776
|
+
# hidden_states[:, (terminated[:, i1 - 1]), :] = 0
|
|
777
|
+
# cell_states[:, (terminated[:, i1 - 1]), :] = 0
|
|
778
|
+
# rnn_outputs.append(rnn_output)
|
|
779
|
+
|
|
780
|
+
# rnn_states = (hidden_states, cell_states)
|
|
781
|
+
# rnn_output = torch.cat(rnn_outputs, dim=1)
|
|
782
|
+
# # if no termination reset is needed, simply compute the RNN output
|
|
783
|
+
# else:
|
|
784
|
+
# rnn_output, rnn_states = self.lstm(rnn_input, (hidden_states, cell_states))
|
|
785
|
+
# # rollout
|
|
786
|
+
# else:
|
|
787
|
+
# # reshape (N, Hin) -> (N, 1, Hin)
|
|
788
|
+
# # This is done to add a sequence length dimension of 1 for processing one time step at a time
|
|
789
|
+
# rnn_input = states.view(-1, 1, states.shape[-1])
|
|
790
|
+
# rnn_output, rnn_states = self.lstm(rnn_input, (hidden_states, cell_states))
|
|
791
|
+
|
|
792
|
+
# # reshape (N, L, D * Hout) -> (N * L, D * Hout)
|
|
793
|
+
# rnn_output = torch.flatten(rnn_output, start_dim=0, end_dim=1)
|
|
794
|
+
|
|
795
|
+
# return self.net(rnn_output), {'rnn': [rnn_states[0], rnn_states[1]]}
|
|
796
|
+
|
|
797
|
+
# # TODO(ll) if not giving in params then just fast return.
|
|
798
|
+
# lstm = LSTM()
|
|
799
|
+
# return lstm
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
def get_models_shared(model_params, observation_space, action_space, device, double_pass):
|
|
803
|
+
# input_size = observation_space.shape[0]
|
|
804
|
+
|
|
805
|
+
# MLP -- change mlp in grouting PPO
|
|
806
|
+
# mlp_params = model_params['mlp']
|
|
807
|
+
# net = MLP(input_size, mlp_params['units'], device, mlp_params['activation'])
|
|
808
|
+
|
|
809
|
+
# LSTM -- change lstm in grouting PPO
|
|
810
|
+
# net = lstm_module(model_params, observation_space, action_space, device, double_pass)
|
|
811
|
+
|
|
812
|
+
# net = example_MLP()
|
|
813
|
+
# net = crazy_net_example()
|
|
814
|
+
# net = triple_cnn_and_mlp_example()
|
|
815
|
+
net = example_LstmMlp()
|
|
816
|
+
# net = example_LstmMlpWithForwardedInput()
|
|
817
|
+
|
|
818
|
+
# TODO --infere this inside of Layer?
|
|
819
|
+
net_output_size = get_output_size(net, observation_space.shape[0])
|
|
820
|
+
|
|
821
|
+
model = SharedRLModel(
|
|
822
|
+
observation_space=observation_space,
|
|
823
|
+
action_space=action_space,
|
|
824
|
+
input_shape=Shape.STATES,
|
|
825
|
+
device=device,
|
|
826
|
+
network=net,
|
|
827
|
+
output_layer={
|
|
828
|
+
'policy': GaussianLayer(
|
|
829
|
+
input_size=net_output_size,
|
|
830
|
+
output_size=action_space.shape[0],
|
|
831
|
+
device=device,
|
|
832
|
+
output_shape=Shape.ACTIONS,
|
|
833
|
+
output_activation=nn.Tanh(),
|
|
834
|
+
clip_actions=False,
|
|
835
|
+
clip_log_std=True,
|
|
836
|
+
min_log_std=-1.2,
|
|
837
|
+
max_log_std=2,
|
|
838
|
+
initial_log_std=0.2,
|
|
839
|
+
),
|
|
840
|
+
'value': DeterministicLayer(
|
|
841
|
+
input_size=net_output_size,
|
|
842
|
+
output_size=1,
|
|
843
|
+
device=device,
|
|
844
|
+
output_shape=Shape.ONE,
|
|
845
|
+
output_activation=nn.Identity(),
|
|
846
|
+
),
|
|
847
|
+
},
|
|
848
|
+
).to(device)
|
|
849
|
+
|
|
850
|
+
return {'policy': model, 'value': model}
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
def get_models_separate(model_params, observation_space, action_space, device, double_pass):
|
|
854
|
+
|
|
855
|
+
net = example_MLP()
|
|
856
|
+
value_net = example_MLP()
|
|
857
|
+
|
|
858
|
+
# change for lstm/mlp
|
|
859
|
+
# net = lstm_module(model_params, observation_space, action_space, device, double_pass)
|
|
860
|
+
# value_net = lstm_module(model_params, observation_space, action_space, device, double_pass)
|
|
861
|
+
|
|
862
|
+
policy_model = RLModel(
|
|
863
|
+
observation_space=observation_space,
|
|
864
|
+
action_space=action_space,
|
|
865
|
+
input_shape=Shape.STATES,
|
|
866
|
+
device=device,
|
|
867
|
+
network=net,
|
|
868
|
+
output_layer=GaussianLayer(
|
|
869
|
+
input_size=get_output_size(net, observation_space.shape[0]),
|
|
870
|
+
output_size=action_space.shape[0],
|
|
871
|
+
device=device,
|
|
872
|
+
output_shape=Shape.ACTIONS,
|
|
873
|
+
output_activation=nn.Tanh(),
|
|
874
|
+
clip_actions=False,
|
|
875
|
+
clip_log_std=True,
|
|
876
|
+
min_log_std=-20,
|
|
877
|
+
max_log_std=2,
|
|
878
|
+
initial_log_std=0,
|
|
879
|
+
),
|
|
880
|
+
).to(device)
|
|
881
|
+
|
|
882
|
+
value_model = RLModel(
|
|
883
|
+
observation_space=observation_space,
|
|
884
|
+
action_space=action_space,
|
|
885
|
+
input_shape=Shape.STATES,
|
|
886
|
+
device=device,
|
|
887
|
+
network=value_net,
|
|
888
|
+
output_layer=DeterministicLayer(
|
|
889
|
+
input_size=get_output_size(value_net, observation_space.shape[0]),
|
|
890
|
+
output_size=1,
|
|
891
|
+
device=device,
|
|
892
|
+
output_shape=Shape.ONE,
|
|
893
|
+
output_activation=nn.Identity(),
|
|
894
|
+
),
|
|
895
|
+
).to(device)
|
|
896
|
+
|
|
897
|
+
return {'policy': policy_model, 'value': value_model}
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
# def get_models_separate_in(model_params, observation_space, action_space, device, double_pass):
|
|
901
|
+
|
|
902
|
+
# if 'mlp' in model_params:
|
|
903
|
+
|
|
904
|
+
# # if 'lstm' in model_params:
|
|
905
|
+
# # input_size = model_params['lstm']['hidden_size']
|
|
906
|
+
# # else:
|
|
907
|
+
# input_size = observation_space.shape[0] # TODO: is this approach too simplistic
|
|
908
|
+
|
|
909
|
+
# if 'cnn' in model_params:
|
|
910
|
+
# net = MixedCNN(model_params, input_size, device)
|
|
911
|
+
# else:
|
|
912
|
+
# mlp_params = model_params['mlp']
|
|
913
|
+
# net = MLP(input_size, mlp_params['units'], device, mlp_params['activation'])
|
|
914
|
+
# value_net = MLP(input_size, mlp_params['units'], device, mlp_params['activation'])
|
|
915
|
+
# else:
|
|
916
|
+
# raise ValueError('Invalid model type')
|
|
917
|
+
|
|
918
|
+
# # change for lstm/mlp
|
|
919
|
+
# # net = lstm_module(model_params, observation_space, action_space, device, double_pass)
|
|
920
|
+
# # value_net = lstm_module(model_params, observation_space, action_space, device, double_pass)
|
|
921
|
+
|
|
922
|
+
# policy_model = GaussianModel(
|
|
923
|
+
# observation_space=observation_space,
|
|
924
|
+
# action_space=action_space,
|
|
925
|
+
# network=net,
|
|
926
|
+
# device=device,
|
|
927
|
+
# clip_actions=False,
|
|
928
|
+
# clip_log_std=True,
|
|
929
|
+
# min_log_std=-20,
|
|
930
|
+
# max_log_std=2,
|
|
931
|
+
# initial_log_std=0,
|
|
932
|
+
# )
|
|
933
|
+
|
|
934
|
+
# value_model = DeterministicModel(
|
|
935
|
+
# observation_space=observation_space,
|
|
936
|
+
# action_space=action_space,
|
|
937
|
+
# network=value_net,
|
|
938
|
+
# device=device,
|
|
939
|
+
# clip_actions=False,
|
|
940
|
+
# )
|
|
941
|
+
|
|
942
|
+
# return {'policy': policy_model, 'value': value_model}
|
|
943
|
+
|
|
944
|
+
|
|
945
|
+
# def get_models(model_params, observation_space, action_space, device, double_pass):
|
|
946
|
+
|
|
947
|
+
# if 'mlp' in model_params:
|
|
948
|
+
|
|
949
|
+
# if 'lstm' in model_params:
|
|
950
|
+
# input_size = model_params['lstm']['hidden_size']
|
|
951
|
+
# else:
|
|
952
|
+
# input_size = observation_space.shape[0] # TODO: is this approach too simplistic
|
|
953
|
+
|
|
954
|
+
# if 'cnn' in model_params:
|
|
955
|
+
# net = MixedCNN(model_params, input_size, device)
|
|
956
|
+
# else:
|
|
957
|
+
# mlp_params = model_params['mlp']
|
|
958
|
+
# net = MLP(input_size, mlp_params['units'], device, mlp_params['activation'])
|
|
959
|
+
# else:
|
|
960
|
+
# raise ValueError('Invalid model type')
|
|
961
|
+
|
|
962
|
+
# shared_config = {
|
|
963
|
+
# 'clip_actions': False,
|
|
964
|
+
# 'clip_log_std': True,
|
|
965
|
+
# 'min_log_std': -20,
|
|
966
|
+
# 'max_log_std': 2,
|
|
967
|
+
# 'initial_log_std': 0,
|
|
968
|
+
# 'input_shape': Shape.STATES,
|
|
969
|
+
# 'output_scale': 1,
|
|
970
|
+
# 'hiddens': model_params['mlp']['units'],
|
|
971
|
+
# 'hidden_activation': [model_params['mlp']['activation'] for _ in range(len(model_params['mlp']['units']))],
|
|
972
|
+
# 'output_activation': None,
|
|
973
|
+
# }
|
|
974
|
+
|
|
975
|
+
# policy_config = shared_config.copy()
|
|
976
|
+
# value_config = shared_config.copy()
|
|
977
|
+
|
|
978
|
+
# policy_config['output_activation'] = 'tanh'
|
|
979
|
+
# policy_config['output_shape'] = Shape.ACTIONS
|
|
980
|
+
# value_config['output_shape'] = Shape.ONE
|
|
981
|
+
|
|
982
|
+
# if 'lstm' in model_params:
|
|
983
|
+
# model = shared_model_lstm(
|
|
984
|
+
# observation_space=observation_space,
|
|
985
|
+
# action_space=action_space,
|
|
986
|
+
# device=device,
|
|
987
|
+
# roles=['policy', 'value'],
|
|
988
|
+
# parameters=[policy_config, value_config],
|
|
989
|
+
# net=net,
|
|
990
|
+
# double_pass=double_pass,
|
|
991
|
+
# )
|
|
992
|
+
# else:
|
|
993
|
+
# model = shared_model(
|
|
994
|
+
# observation_space=observation_space,
|
|
995
|
+
# action_space=action_space,
|
|
996
|
+
# device=device,
|
|
997
|
+
# roles=['policy', 'value'],
|
|
998
|
+
# parameters=[policy_config, value_config],
|
|
999
|
+
# net=net,
|
|
1000
|
+
# double_pass=double_pass,
|
|
1001
|
+
# )
|
|
1002
|
+
|
|
1003
|
+
# return {'policy': model, 'value': model}
|