engineportf's picture
Upload folder using huggingface_hub
558db1e verified
Raw
History Blame Contribute Delete
3.35 kB
import torch
import torch.nn as nn
import torch.nn.functional as F
class RSSMState:
def __init__(self, stochastic: torch.Tensor, deterministic: torch.Tensor):
self.stoch = stochastic
self.deter = deterministic
def get_features(self):
"""Returns the concatenated stochastic and deterministic state."""
return torch.cat([self.stoch, self.deter], dim=-1)
class RSSM(nn.Module):
def __init__(self, action_dim: int, embed_dim: int = 256, stoch_dim: int = 32, deter_dim: int = 256, hidden_dim: int = 256):
super().__init__()
self.stoch_dim = stoch_dim
self.deter_dim = deter_dim
self.action_dim = action_dim
# RNN now takes action_dim + stoch_dim instead of embed_dim
self.rnn = nn.GRUCell(action_dim + stoch_dim, deter_dim)
# Prior predicts next stochastic state from deterministic state
self.prior_net = nn.Sequential(
nn.Linear(deter_dim, hidden_dim),
nn.ELU(),
nn.Linear(hidden_dim, 2 * stoch_dim)
)
# Posterior predicts stochastic state from deterministic state + current observation embedding
self.post_net = nn.Sequential(
nn.Linear(deter_dim + embed_dim, hidden_dim),
nn.ELU(),
nn.Linear(hidden_dim, 2 * stoch_dim)
)
def initial_state(self, batch_size: int, device: torch.device) -> RSSMState:
return RSSMState(
stochastic=torch.zeros(batch_size, self.stoch_dim, device=device),
deterministic=torch.zeros(batch_size, self.deter_dim, device=device)
)
def observe_step(self, prev_state: RSSMState, action: torch.Tensor, embed: torch.Tensor) -> tuple:
"""
Single step of posterior given a real observation embedding.
Uses the prior action taken to advance the deterministic dynamics.
"""
rnn_input = torch.cat([prev_state.stoch, action], dim=-1)
deter = self.rnn(rnn_input, prev_state.deter)
post_stats = self.post_net(torch.cat([deter, embed], dim=-1))
post_mean, post_std = torch.chunk(post_stats, 2, dim=-1)
post_std = F.softplus(post_std) + 0.1
prior_stats = self.prior_net(deter)
prior_mean, prior_std = torch.chunk(prior_stats, 2, dim=-1)
prior_std = F.softplus(prior_std) + 0.1
stoch = post_mean + post_std * torch.randn_like(post_std)
new_state = RSSMState(stochastic=stoch, deterministic=deter)
return new_state, (post_mean, post_std), (prior_mean, prior_std)
def imagine_step(self, prev_state: RSSMState, action: torch.Tensor) -> RSSMState:
"""
Single step of prior imagination without real observations.
Requires the action intended to be taken.
"""
rnn_input = torch.cat([prev_state.stoch, action], dim=-1)
deter = self.rnn(rnn_input, prev_state.deter)
prior_stats = self.prior_net(deter)
prior_mean, prior_std = torch.chunk(prior_stats, 2, dim=-1)
prior_std = F.softplus(prior_std) + 0.1
stoch = prior_mean + prior_std * torch.randn_like(prior_std)
new_state = RSSMState(stochastic=stoch, deterministic=deter)
return new_state