Here it is.
It is a bit longish, but it is self contained
import torch
import torch.nn as nn
from torch import tensor, cat
from tqdm import tqdm, trange
from random import seed

torch.manual_seed(0)
seed(0)

c = ['(', ')', '+', '-', '*', '/',
 '0', '1', '2', '3', '4', '5',
 '6', '7', '8', '9', ' ']
ioc = {c[i]:i for i in range(len(c))}


toc = {'(':'PAR', ')':'PAR',
   '+':'OP', '-':'OP' ,'*':'OP' ,'/':'OP' ,
   '0':'NUM', '1':'NUM', '2':'NUM', '3':'NUM', '4':'NUM', '5':'NUM', '6':'NUM', '7':'NUM', '8':'NUM', '9':'NUM',
   ' ':'SPC'}

types = list(toc.values())
types.sort()

iop = {types[i]:i for i in range(len(types))}




class Typed_LSTM(nn.Module):

    def __init__(self, input_dim, hidden_dim, num_layer, device):
        nn.Module.__init__(self)

        self.hidden_dim = hidden_dim
        self.device = device

        self.LSTM = {'_':nn.LSTM(input_dim, hidden_dim, num_layer)}
        for t, l in self.LSTM.items():
            self.add_module('LSTM'+t, l)


    def forward(self, xts):
        b = xts.shape[0]

        states = []

        hc = None
        for xt in xts:
            xt = xt.reshape((1, xt.shape[0], xt.shape[1]))
            s, hc = self.LSTM['_'](xt, hc)
        
            states.append(s)

        states = cat(states)
        
        return states



class PSolver(nn.Module):

    def __init__(self, ioc, iop, emb_dim, pos_dim, hidden_dim, num_layer, types, device):
        nn.Module.__init__(self)
        self.device = device
    
        self.ioc = ioc
        self.iop = iop
        #self.P = nn.Embedding(len(self.iop)+20, pos_dim) # add some dummy embeddings to avoid the cudnn bug
        self.P = nn.Embedding(len(self.iop), pos_dim) 
        self.E = nn.Embedding(len(self.ioc), emb_dim) 

        self.LSTM = Typed_LSTM(emb_dim+pos_dim, hidden_dim, num_layer, device)
        #self.LSTM = nn.LSTM(emb_dim+pos_dim, hidden_dim)

        self.H = nn.Linear(hidden_dim, hidden_dim)
        self.O = nn.Linear(hidden_dim, 1, bias=True)

        self.loss = nn.L1Loss(reduction='sum')
    
        self.trainer = torch.optim.Adadelta(self.parameters())

        self.to(device)


    def encode(self, exp, tags):
        emb = self.E(tensor([[self.ioc[c] for c in exp]], device=self.device)).transpose(0,1)
        pemb = self.P(tensor([[self.iop[p] for p in tags]], device=self.device)).transpose(0,1)

        emb = cat([emb, pemb], dim=2)
        state = self.LSTM(emb)[-1][-1]
        value = self.H(state)        
        value = self.O(value)
    
        return value


    def test(self, exp, tags):

        value = self.encode(exp, tags)
    
        return value.item()



device = torch.device('cuda:0')

solver = PSolver(ioc, iop, 10, 10, 50, 1, types, device)

exp = '1+2-3+4-5+6-7'
tags = ['NUM', 'OP', 'NUM', 'OP', 'NUM', 'OP', 'NUM', 'OP', 'NUM', 'OP', 'NUM', 'OP', 'NUM']

v = solver.test(exp, tags)

The problems is around line 69/70 where adding a few dummy embeddings resolves the cuDNN problem.
The problem otherwise appears with both the “house” lstm and torch native lstm.
At times, on top of the cuDNN error, it also throws a bunch of :
/pytorch/aten/src/THC/THCTensorIndex.cu:308: void indexSelectSmallIndex(TensorInfo<T, IndexType>, TensorInfo<T, IndexType>, TensorInfo<long, IndexType>, int, int, IndexType, long) [with T = float, IndexType = unsigned int, DstDim = 2, SrcDim = 2, IdxDim = -2]: block: [0,0,0], thread: [0,0,0] Assertion srcIndex < srcSelectDimSize failed.
But it is not alway easy to reproduce this one.
If it helps I’ll be glad to know.
Best