text: from torch.autograd import Variable
  import numpy as np
  
  # sample data
  def load_data():
      # passengers number of international airline , 1949-01 ~ 1960-12 per month
      seq_number = np.array(
          [112., 118., 132., 129., 121., 135., 148., 148., 136., 119., 104.,
           118., 115., 126., 141., 135., 125., 149., 170., 170., 158., 133.,
           114., 140., 145., 150., 178., 163., 172., 178., 199., 199., 184.,
           162., 146., 166., 171., 180., 193., 181., 183., 218., 230., 242.,
           209., 191., 172., 194., 196., 196., 236., 235., 229., 243., 264.,
           272., 237., 211., 180., 201., 204., 188., 235., 227., 234., 264.,
           302., 293., 259., 229., 203., 229., 242., 233., 267., 269., 270.,
           315., 364., 347., 312., 274., 237., 278., 284., 277., 317., 313.,
           318., 374., 413., 405., 355., 306., 271., 306., 315., 301., 356.,
           348., 355., 422., 465., 467., 404., 347., 305., 336., 340., 318.,
           362., 348., 363., 435., 491., 505., 404., 359., 310., 337., 360.,
           342., 406., 396., 420., 472., 548., 559., 463., 407., 362., 405.,
           417., 391., 419., 461., 472., 535., 622., 606., 508., 461., 390.,
           432.], dtype=np.float32)
      # assert seq_number.shape == (144, )
      # plt.plot(seq_number)
      # plt.ion()
      # plt.pause(1)
      seq_number = seq_number[:, np.newaxis]
  
      # print(repr(seq))
      # 1949~1960, 12 years, 12*12==144 month
      seq_year = np.arange(12)
      seq_month = np.arange(12)
      seq_year_month = np.transpose(
          [np.repeat(seq_year, len(seq_month)),
           np.tile(seq_month, len(seq_year))],
      )  # Cartesian Product
  
      seq = np.concatenate((seq_number, seq_year_month), axis=1)
  
      # normalization
      seq = (seq - seq.mean(axis=0)) / seq.std(axis=0)
      return seq
  
  
  import torch
  import torch.nn as nn
  import torchvision.transforms as transforms
  import torchvision.datasets as dsets
  from torch import Tensor
  import torch.nn.functional as F
  
  
  import pdb
  import math
  
  cuda  = True if torch.cuda.is_available() else False
  
  class LSTMCell(nn.Module):
      
      """
      An implementation of Hochreiter & Schmidhuber:
      'Long-Short Term Memory' cell.
      http://www.bioinf.jku.at/publications/older/2604.pdf
  
      """
  
      def __init__(self, input_size, hidden_size, bias=True):
          super(LSTMCell, self).__init__()
          self.input_size = input_size
          self.hidden_size = hidden_size
          self.bias = bias
          self.x2h = nn.Linear(input_size, 4 * hidden_size, bias=bias)
          self.h2h = nn.Linear(hidden_size, 4 * hidden_size, bias=bias)
          self.c2c = Tensor(hidden_size * 3)
          self.reset_parameters()
  
  
  
      def reset_parameters(self):
          std = 1.0 / math.sqrt(self.hidden_size)
          for w in self.parameters():
              w.data.uniform_(-std, std)
      
      def forward(self, x, hidden):
          #pdb.set_trace()
          hx, cx = hidden
          
          x = x.view(-1, x.size(1))
          
          gates = self.x2h(x) + self.h2h(hx)
      
          gates = gates.squeeze()
          
          c2c = self.c2c.unsqueeze(0)
          ci, cf, co = c2c.chunk(3,1)
          ingate, forgetgate, cellgate, outgate = gates.chunk(4, 1)
          
          ingate = torch.sigmoid(ingate+ ci * cx)
          forgetgate = torch.sigmoid(forgetgate + cf * cx)
          cellgate = forgetgate*cx + ingate* torch.tanh(cellgate)
          outgate = torch.sigmoid(outgate+ co*cellgate)
          
  
          hm = outgate * F.tanh(cellgate)
          return (hm, cellgate)
  
  ##
  class LSTMModel(nn.Module):
      def __init__(self, input_dim, hidden_dim, layer_dim, output_dim, bias=True):
          super(LSTMModel, self).__init__()
          # Hidden dimensions
          self.hidden_dim = hidden_dim
           
          # Number of hidden layers
          self.layer_dim = layer_dim
                 
          self.lstm = LSTMCell(input_dim, hidden_dim, layer_dim)  
          
          self.fc = nn.Linear(hidden_dim, output_dim)
       
      
      
      def forward(self, x):
          
          # Initialize hidden state with zeros
          #######################
          #  USE GPU FOR MODEL  #
          #######################
          #print(x.shape,"x.shape")100, 28, 28
          if torch.cuda.is_available():
              h0 = Tensor(torch.zeros(self.layer_dim, x.size(0), self.hidden_dim).cuda())
          else:
              h0 = Tensor(torch.zeros(self.layer_dim, x.size(0), self.hidden_dim))
  
          # Initialize cell state
          if torch.cuda.is_available():
              c0 = Tensor(torch.zeros(self.layer_dim, x.size(0), self.hidden_dim).cuda())
          else:
              c0 = Tensor(torch.zeros(self.layer_dim, x.size(0), hidden_dim))
  
                      
         
          outs = []
          
          cn = c0[0,:,:]
          hn = h0[0,:,:]
          
          for seq in range(x.size(1)):
              hn, cn = self.lstm(x[:,seq,:], (hn,cn)) 
              outs.append(hn)
              
      
  
          out = outs[-1].squeeze()
          
          out = self.fc(out) 
          # out.size() --> 100, 10
          return out
  
  
  input_dim = 28
  hidden_dim = 128
  layer_dim = 1  # ONLY CHANGE IS HERE FROM ONE LAYER TO TWO LAYER
  output_dim = 10
   
  model = LSTMModel(input_dim, hidden_dim, layer_dim, output_dim)
  
  if __name__ == "__main__":
      import torch
      from torchvision.models import AlexNet
      from torchsummary import summary
      input_size = (3,256, 256)
      summary(model, input_size, batch_size=1, device='cpu')
      
  
      '''
      from tensorboardX import SummaryWriter
      
      
      x=torch.rand(8,3,256,512)
      model=AlexNet()
      
      with SummaryWriter(comment='AlexNet') as w:
          w.add_graph(model, x) 
      '''
      
      # Visualize the graph: ensorboard --logdir Nov06_23-48-39_MacBook-Pro.localAlexNet