def pad_sequence(batch, padding_value=0.0):
    """ output_batch = pad_sequence(batch)
    
    input
    -----
      batch: list of tensor, [data_1, data2, ...], and data_1 is (len, dim, ...)
    
    output
    ------
      output_batch: list of tensor, [data_1_padded, data_2_padded, ...]

    Pad a batch of data sequences to be same length (maximum length in batch).
    This function is based on 
    pytorch.org/docs/stable/_modules/torch/nn/utils/rnn.html#pad_sequence
    """
    # get the rest of the dimensions (dim, ...)
    max_size = batch[0].size()
    trailing_dims = max_size[1:]
    # get the maximum length
    max_len = max([s.size(0) for s in batch])
    
    if all(x.shape[0] == max_len for x in batch):
        # if all data sequences in batch have the same length, no need to pad
        return batch
    else:
        # else, we need to pad 
        out_dims = (max_len, ) + trailing_dims
        
        output_batch = []
        for i, tensor in enumerate(batch):
            # check the rest of dimensions
            if tensor.size()[1:] != trailing_dims:
                print("Data in batch has different dimensions:")
                for data in batch:
                    print(str(data.size()))
                raise RuntimeError('Fail to create batch data')
            # save padded results
            out_tensor = tensor.new_full(out_dims, padding_value)
            out_tensor[:tensor.size(0), ...] = tensor
            output_batch.append(out_tensor)
        return output_batch