Spaces:
Sleeping
Sleeping
| import torch | |
| import torch.nn as nn | |
| class StateCentricLSTM_Delta(nn.Module): | |
| def __init__( | |
| self, input_dim, hidden_dim=256, num_layers=2, embed_dim=32, use_projection=True | |
| ): | |
| super().__init__() | |
| self.use_projection = use_projection | |
| if self.use_projection: | |
| # Projection: High-Dim Sparse -> Low-Dim Dense | |
| self.encoder = nn.Linear(input_dim, embed_dim) | |
| lstm_input_size = embed_dim * 2 | |
| else: | |
| # No Projection: Use raw input dimensions | |
| lstm_input_size = input_dim * 2 | |
| # LSTM | |
| self.lstm = nn.LSTM( | |
| input_size=lstm_input_size, | |
| hidden_size=hidden_dim, | |
| num_layers=num_layers, | |
| batch_first=True, | |
| ) | |
| # Head: Projects back to Input Dim (Delta) | |
| # No LayerNorm, No ReLU at the end | |
| # We need to predict negative values (subtractions) | |
| self.head = nn.Linear(hidden_dim, input_dim) | |
| def forward(self, state_seq, goal_seq, lengths=None, hidden=None): | |
| """ | |
| Returns: | |
| pred_delta: [B, T, Input_D] (The predicted CHANGE) | |
| hidden: LSTM hidden state | |
| """ | |
| # 1. Encode (or pass through) | |
| if self.use_projection: | |
| state_emb = torch.relu(self.encoder(state_seq)) | |
| goal_emb = torch.relu(self.encoder(goal_seq)) | |
| else: | |
| state_emb = state_seq | |
| goal_emb = goal_seq | |
| _, T, _ = state_emb.shape | |
| # 2. Expand Goal | |
| goal_expanded = goal_emb.unsqueeze(1).expand(-1, T, -1) | |
| # 3. Concat | |
| lstm_input = torch.cat([state_emb, goal_expanded], dim=2) | |
| # 4. Pack | |
| if lengths is not None: | |
| lstm_input = torch.nn.utils.rnn.pack_padded_sequence( | |
| lstm_input, lengths.cpu(), batch_first=True, enforce_sorted=False | |
| ) | |
| # 5. LSTM | |
| out, hidden = self.lstm(lstm_input, hidden) | |
| # 6. Unpack | |
| if lengths is not None: | |
| out, _ = torch.nn.utils.rnn.pad_packed_sequence(out, batch_first=True) | |
| # 7. Predict Delta | |
| pred_delta = self.head(out) | |
| return pred_delta, hidden | |
| class StateCentricLSTM(nn.Module): | |
| def __init__( | |
| self, input_dim, hidden_dim=256, num_layers=2, embed_dim=32, use_projection=True | |
| ): | |
| super().__init__() | |
| self.use_projection = use_projection | |
| if self.use_projection: | |
| # 1. Add a Projection Layer (Dimensionality Reduction) | |
| self.encoder = nn.Linear(input_dim, embed_dim) | |
| lstm_input_size = embed_dim * 2 | |
| else: | |
| lstm_input_size = input_dim * 2 | |
| # LSTM | |
| self.lstm = nn.LSTM( | |
| input_size=lstm_input_size, | |
| hidden_size=hidden_dim, | |
| num_layers=num_layers, | |
| batch_first=True, | |
| ) | |
| # Head projects back to FULL input_dim | |
| self.head = nn.Sequential( | |
| nn.Linear(hidden_dim, hidden_dim), | |
| nn.LayerNorm(hidden_dim), | |
| nn.ReLU(), | |
| nn.Linear(hidden_dim, input_dim), | |
| ) | |
| def forward(self, state_seq, goal_seq, lengths=None, hidden=None): | |
| """ | |
| state_seq: [B, T, Input_D] | |
| goal_seq: [B, D] (will be expanded to [B, T, D]) | |
| """ | |
| # 1. Project High-Dim Sparse -> Low-Dim Dense (Optional) | |
| if self.use_projection: | |
| state_emb = torch.relu(self.encoder(state_seq)) # [B, T, embed_dim] | |
| goal_emb = torch.relu(self.encoder(goal_seq)) # [B, embed_dim] | |
| else: | |
| state_emb = state_seq | |
| goal_emb = goal_seq | |
| _, T, _ = state_emb.shape | |
| # Expand goal to match sequence length | |
| goal_expanded = goal_emb.unsqueeze(1).expand(-1, T, -1) | |
| # Concatenate: [B, T, 2D] | |
| lstm_input = torch.cat([state_emb, goal_expanded], dim=2) | |
| # Pack sequences if lengths are provided | |
| if lengths is not None: | |
| lstm_input = torch.nn.utils.rnn.pack_padded_sequence( | |
| lstm_input, lengths.cpu(), batch_first=True, enforce_sorted=False | |
| ) | |
| # LSTM Forward | |
| out, hidden = self.lstm(lstm_input, hidden) | |
| if lengths is not None: | |
| out, _ = torch.nn.utils.rnn.pad_packed_sequence(out, batch_first=True) | |
| # Project to next state | |
| pred_next_state = self.head(out) | |
| return pred_next_state, hidden | |