@@ -47,6 +47,8 @@ class DreamerActor(nn.Module):
4747 Defaults to 5.0.
4848 std_min_val (:obj:`float`, optional): Minimum value of the standard deviation.
4949 Defaults to 1e-4.
50+ device (torch.device, optional): Device to create the module on.
51+ Defaults to None (uses default device).
5052 """
5153
5254 def __init__ (
@@ -57,13 +59,15 @@ def __init__(
5759 activation_class = nn .ELU ,
5860 std_bias = 5.0 ,
5961 std_min_val = 1e-4 ,
62+ device = None ,
6063 ):
6164 super ().__init__ ()
6265 self .backbone = MLP (
6366 out_features = 2 * out_features ,
6467 depth = depth ,
6568 num_cells = num_cells ,
6669 activation_class = activation_class ,
70+ device = device ,
6771 )
6872 self .backbone .append (
6973 NormalParamExtractor (
@@ -88,9 +92,13 @@ class ObsEncoder(nn.Module):
8892 channels (int, optional): Number of hidden units in the first layer.
8993 Defaults to 32.
9094 num_layers (int, optional): Depth of the network. Defaults to 4.
95+ in_channels (int, optional): Number of input channels. If None, uses LazyConv2d.
96+ Defaults to None for backward compatibility.
97+ device (torch.device, optional): Device to create the module on.
98+ Defaults to None (uses default device).
9199 """
92100
93- def __init__ (self , channels = 32 , num_layers = 4 , depth = None ):
101+ def __init__ (self , channels = 32 , num_layers = 4 , in_channels = None , depth = None , device = None ):
94102 if depth is not None :
95103 warnings .warn (
96104 f"The depth argument in { type (self )} will soon be deprecated and "
@@ -102,14 +110,19 @@ def __init__(self, channels=32, num_layers=4, depth=None):
102110 if num_layers < 1 :
103111 raise RuntimeError ("num_layers cannot be smaller than 1." )
104112 super ().__init__ ()
113+ # Use explicit Conv2d if in_channels provided, else LazyConv2d for backward compat
114+ if in_channels is not None :
115+ first_conv = nn .Conv2d (in_channels , channels , 4 , stride = 2 , device = device )
116+ else :
117+ first_conv = nn .LazyConv2d (channels , 4 , stride = 2 , device = device )
105118 layers = [
106- nn . LazyConv2d ( channels , 4 , stride = 2 ) ,
119+ first_conv ,
107120 nn .ReLU (),
108121 ]
109122 k = 1
110123 for _ in range (1 , num_layers ):
111124 layers += [
112- nn .Conv2d (channels * k , channels * (k * 2 ), 4 , stride = 2 ),
125+ nn .Conv2d (channels * k , channels * (k * 2 ), 4 , stride = 2 , device = device ),
113126 nn .ReLU (),
114127 ]
115128 k = k * 2
@@ -140,9 +153,13 @@ class ObsDecoder(nn.Module):
140153 num_layers (int, optional): Depth of the network. Defaults to 4.
141154 kernel_sizes (int or list of int, optional): the kernel_size of each layer.
142155 Defaults to ``[5, 5, 6, 6]`` if num_layers if 4, else ``[5] * num_layers``.
156+ latent_dim (int, optional): Input dimension (state_dim + rnn_hidden_dim).
157+ If None, uses LazyLinear. Defaults to None for backward compatibility.
158+ device (torch.device, optional): Device to create the module on.
159+ Defaults to None (uses default device).
143160 """
144161
145- def __init__ (self , channels = 32 , num_layers = 4 , kernel_sizes = None , depth = None ):
162+ def __init__ (self , channels = 32 , num_layers = 4 , kernel_sizes = None , latent_dim = None , depth = None , device = None ):
146163 if depth is not None :
147164 warnings .warn (
148165 f"The depth argument in { type (self )} will soon be deprecated and "
@@ -155,8 +172,14 @@ def __init__(self, channels=32, num_layers=4, kernel_sizes=None, depth=None):
155172 raise RuntimeError ("num_layers cannot be smaller than 1." )
156173
157174 super ().__init__ ()
175+ # Use explicit Linear if latent_dim provided, else LazyLinear for backward compat
176+ linear_out = channels * 8 * 2 * 2
177+ if latent_dim is not None :
178+ first_linear = nn .Linear (latent_dim , linear_out , device = device )
179+ else :
180+ first_linear = nn .LazyLinear (linear_out , device = device )
158181 self .state_to_latent = nn .Sequential (
159- nn . LazyLinear ( channels * 8 * 2 * 2 ) ,
182+ first_linear ,
160183 nn .ReLU (),
161184 )
162185 if kernel_sizes is None and num_layers == 4 :
@@ -167,23 +190,24 @@ def __init__(self, channels=32, num_layers=4, kernel_sizes=None, depth=None):
167190 kernel_sizes = [kernel_sizes ] * num_layers
168191 layers = [
169192 nn .ReLU (),
170- nn .ConvTranspose2d (channels , 3 , kernel_sizes [- 1 ], stride = 2 ),
193+ nn .ConvTranspose2d (channels , 3 , kernel_sizes [- 1 ], stride = 2 , device = device ),
171194 ]
172195 kernel_sizes = kernel_sizes [:- 1 ]
173196 k = 1
174197 for j in range (1 , num_layers ):
175198 if j != num_layers - 1 :
176199 layers = [
177200 nn .ConvTranspose2d (
178- channels * k * 2 , channels * k , kernel_sizes [- 1 ], stride = 2
201+ channels * k * 2 , channels * k , kernel_sizes [- 1 ], stride = 2 , device = device
179202 ),
180203 ] + layers
181204 kernel_sizes = kernel_sizes [:- 1 ]
182205 k = k * 2
183206 layers = [nn .ReLU ()] + layers
184207 else :
208+ # Use explicit ConvTranspose2d - input is always channels * 8 from state_to_latent
185209 layers = [
186- nn .LazyConvTranspose2d ( channels * k , kernel_sizes [- 1 ], stride = 2 )
210+ nn .ConvTranspose2d ( linear_out , channels * k , kernel_sizes [- 1 ], stride = 2 , device = device )
187211 ] + layers
188212
189213 self .decoder = nn .Sequential (* layers )
@@ -290,6 +314,10 @@ class RSSMPrior(nn.Module):
290314 Defaults to 30.
291315 scale_lb (:obj:`float`, optional): Lower bound of the scale of the state distribution.
292316 Defaults to 0.1.
317+ action_dim (int, optional): Dimension of the action. If provided along with state_dim,
318+ uses explicit Linear instead of LazyLinear. Defaults to None for backward compatibility.
319+ device (torch.device, optional): Device to create the module on.
320+ Defaults to None (uses default device).
293321
294322
295323 """
@@ -301,16 +329,23 @@ def __init__(
301329 rnn_hidden_dim = 200 ,
302330 state_dim = 30 ,
303331 scale_lb = 0.1 ,
332+ action_dim = None ,
333+ device = None ,
304334 ):
305335 super ().__init__ ()
306336
307- # Prior
308- self .rnn = GRUCell (hidden_dim , rnn_hidden_dim )
309- self .action_state_projector = nn .Sequential (nn .LazyLinear (hidden_dim ), nn .ELU ())
337+ # Prior - use explicit Linear if action_dim provided, else LazyLinear
338+ self .rnn = GRUCell (hidden_dim , rnn_hidden_dim , device = device )
339+ if action_dim is not None :
340+ projector_in = state_dim + action_dim
341+ first_linear = nn .Linear (projector_in , hidden_dim , device = device )
342+ else :
343+ first_linear = nn .LazyLinear (hidden_dim , device = device )
344+ self .action_state_projector = nn .Sequential (first_linear , nn .ELU ())
310345 self .rnn_to_prior_projector = nn .Sequential (
311- nn .Linear (hidden_dim , hidden_dim ),
346+ nn .Linear (hidden_dim , hidden_dim , device = device ),
312347 nn .ELU (),
313- nn .Linear (hidden_dim , 2 * state_dim ),
348+ nn .Linear (hidden_dim , 2 * state_dim , device = device ),
314349 NormalParamExtractor (
315350 scale_lb = scale_lb ,
316351 scale_mapping = "softplus" ,
@@ -330,7 +365,14 @@ def forward(self, state, belief, action):
330365 belief = belief .unsqueeze (0 )
331366 action_state = action_state .unsqueeze (0 )
332367 unsqueeze = True
333- belief = self .rnn (action_state , belief )
368+
369+ # GRUCell can have issues with bfloat16 autocast on some GPU/cuBLAS combinations.
370+ # Run the RNN in full precision to avoid CUBLAS_STATUS_INVALID_VALUE errors.
371+ dtype = action_state .dtype
372+ device_type = action_state .device .type
373+ with torch .amp .autocast (device_type = device_type , enabled = False ):
374+ belief = self .rnn (action_state .float (), belief .float () if belief is not None else None )
375+ belief = belief .to (dtype )
334376 if unsqueeze :
335377 belief = belief .squeeze (0 )
336378
@@ -354,15 +396,27 @@ class RSSMPosterior(nn.Module):
354396 Defaults to 30.
355397 scale_lb (:obj:`float`, optional): Lower bound of the scale of the state distribution.
356398 Defaults to 0.1.
399+ rnn_hidden_dim (int, optional): Dimension of the belief/rnn hidden state.
400+ If provided along with obs_embed_dim, uses explicit Linear. Defaults to None.
401+ obs_embed_dim (int, optional): Dimension of the observation embedding.
402+ If provided along with rnn_hidden_dim, uses explicit Linear. Defaults to None.
403+ device (torch.device, optional): Device to create the module on.
404+ Defaults to None (uses default device).
357405
358406 """
359407
360- def __init__ (self , hidden_dim = 200 , state_dim = 30 , scale_lb = 0.1 ):
408+ def __init__ (self , hidden_dim = 200 , state_dim = 30 , scale_lb = 0.1 , rnn_hidden_dim = None , obs_embed_dim = None , device = None ):
361409 super ().__init__ ()
410+ # Use explicit Linear if both dims provided, else LazyLinear for backward compat
411+ if rnn_hidden_dim is not None and obs_embed_dim is not None :
412+ projector_in = rnn_hidden_dim + obs_embed_dim
413+ first_linear = nn .Linear (projector_in , hidden_dim , device = device )
414+ else :
415+ first_linear = nn .LazyLinear (hidden_dim , device = device )
362416 self .obs_rnn_to_post_projector = nn .Sequential (
363- nn . LazyLinear ( hidden_dim ) ,
417+ first_linear ,
364418 nn .ELU (),
365- nn .Linear (hidden_dim , 2 * state_dim ),
419+ nn .Linear (hidden_dim , 2 * state_dim , device = device ),
366420 NormalParamExtractor (
367421 scale_lb = scale_lb ,
368422 scale_mapping = "softplus" ,
@@ -374,6 +428,5 @@ def forward(self, belief, obs_embedding):
374428 posterior_mean , posterior_std = self .obs_rnn_to_post_projector (
375429 torch .cat ([belief , obs_embedding ], dim = - 1 )
376430 )
377- # post_std = post_std + 0.1
378431 state = posterior_mean + torch .randn_like (posterior_std ) * posterior_std
379432 return posterior_mean , posterior_std , state
0 commit comments