pytorch / pytorch/rl

[Feature Request] CUDNN version of RSSM

Open
#366 1 comment 0 reactions 1 assignee View on GitHub

@vmoens is already working on this.

Since Aug 17, 2022.

enhancement
Dominant language
Python
Stars
3.6k
Forks
484
Avg merge
1d 1h
Merged PRs (30d)
207

Description

Motivation

In model based models such as dreamer and planet the main computation bottleneck is the unroll of the RSSM prior. RSSM prior is based on a GRUCell. However, since at each step we need to compute some additional operations, we cannot use nn.GRU to have an optimized version. Having this could considerably boost the performance of model based model that use RSSM.

Solution

Currently, we have a single operation of RSSMPrior defined as:


class RSSMPrior(nn.Module):
    def __init__(self, hidden_dim=200, rnn_hidden_dim=200, state_dim=20):
        super().__init__()
        ### Prior
        self.rnn = nn.GRUCell(hidden_dim, rnn_hidden_dim)
        self.action_state_projector = nn.Sequential(nn.LazyLinear(hidden_dim), nn.ELU())
        self.rnn_to_prior_projector = NormalParamWrapper(
            nn.Sequential(
                nn.Linear(hidden_dim, hidden_dim),
                nn.ELU(),
                nn.Linear(hidden_dim, 2 * state_dim),
            ),
            scale_lb=0.1,
        )

        self.state_dim = state_dim
        self.rnn_hidden_dim = rnn_hidden_dim

    def forward(self, state, rnn_hidden, action):
        *batch_size, _ = action.shape
        if state is None:
            state = torch.zeros(*batch_size, self.state_dim, device=action.device)
        if rnn_hidden is None:
            rnn_hidden = torch.zeros(
                *batch_size, self.rnn_hidden_dim, device=action.device
            )

        action_state = self.action_state_projector(torch.cat([state, action], dim=-1))
        rnn_hidden = self.rnn(action_state, rnn_hidden)
        belief = rnn_hidden
        prior_mean, prior_std = self.rnn_to_prior_projector(belief)
        prior_state = prior_mean + torch.randn_like(prior_std) * prior_std
        return prior_mean, prior_std, prior_state, belief

And what we unroll it in two ways:

  1. Given a actions of shape [BxTxD], (init_prior_state, init_belief of shape [BxD1] and [BxD2] resp.) we compute the T corresponding states

    def unroll_rssm(init_prior_state, init_belief , actions):
        rssm_prior = RSSMPrior(hidden_dim=200, rnn_hidden_dim=200, state_dim=20)
        prior_means = []
        prior_stds = []
        prior_states = []
        beliefs = []
        prior_state, belief = init_prior_state, init_belief`
        for i in range(actions.shape[1]):
            prior_mean, prior_std, prior_state, belief = rssm_prior(
                prior_state, belief, action[:, i]
            )
            prior_means.append(prior_mean)
            prior_stds.append(prior_std)
            prior_states.append(prior_state)
            beliefs.append(belief)
        prior_means = torch.stack(prior_means, dim=1)
        prior_stds = torch.stack(prior_stds, dim=1)
        prior_states = torch.stack(prior_states, dim=1)
        beliefs = torch.stack(beliefs, dim=1)
        return prior_means, prior_stds, prior_states, beliefs
  1. Given an actor model, we unroll the states for H steps computing the actions on the fly.
    def unroll_rssm(init_prior_state, init_belief , actor, horizon=H):
        rssm_prior = RSSMPrior(hidden_dim=200, rnn_hidden_dim=200, state_dim=20)
        prior_means = []
        prior_stds = []
        prior_states = []
        beliefs = []
        prior_state, belief = init_prior_state, init_belief
        for i in range(horizon):
            action = actor(prior_state, belief)
            prior_mean, prior_std, prior_state, belief = rssm_prior(
                prior_state, belief, action
            )
            prior_means.append(prior_mean)
            prior_stds.append(prior_std)
            prior_states.append(prior_state)
            beliefs.append(belief)
        prior_means = torch.stack(prior_means, dim=1)
        prior_stds = torch.stack(prior_stds, dim=1)
        prior_states = torch.stack(prior_states, dim=1)
        beliefs = torch.stack(beliefs, dim=1)
        return prior_means, prior_stds, prior_states, beliefs

The idea would be to have an optimized CUDNN version of both operation which would speed-up this operation.

Checklist

  • I have checked that there is no similar issue in the repo (required)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.