text: import os
  import time
  import argparse
  import numpy as np
  import math
  import random
  import matplotlib.pyplot as plt
  import cv2
  import glob
  from tqdm import tqdm
  import pickle
  import scipy.ndimage.interpolation as inter
  from scipy.signal import medfilt 
  from scipy.spatial.distance import cdist
  
  from keras.optimizers import *
  from keras.models import Model
  from keras.layers import *
  from keras.layers.core import *
  from tensorflow.keras.callbacks import *
  from keras.layers.convolutional import *
  from keras import backend as K
  import keras
  import tensorflow as tf
  from collections import Counter
  random.seed(1234)
  
  
  #parser = argparse.ArgumentParser()
  #parser.add_argument("--input_file", help = "File pkl contains frames of video")
  #parser.add_argument("--checkpoint", help = "Model weights file")
  #args = parser.parse_args()
  class Config():
      def __init__(self):
          self.frame_l = 32 # the length of frames
          self.joint_n = 14 # the number of joints
          self.joint_d = 2 # the dimension of joints
          self.clc_num = 15 # the number of class
          self.feat_d = 91
          self.filters = 64
  C = Config()
  
  
  # Temple resizing function
  def zoom(p,target_l=64,joints_num=25,joints_dim=3):
      l = p.shape[0]
      p_new = np.empty([target_l,joints_num,joints_dim]) 
      for m in range(joints_num):
          for n in range(joints_dim):
              p[:,m,n] = medfilt(p[:,m,n],3)
              p_new[:,m,n] = inter.zoom(p[:,m,n],target_l/l)[:target_l]         
      return p_new
  
  # Calculate JCD feature
  def norm_scale(x):
      return (x-np.mean(x))/np.mean(x)
    
  def get_CG(p,C):
      M = []
      iu = np.triu_indices(C.joint_n,1,C.joint_n)
      for f in range(C.frame_l): 
          d_m = cdist(p[f],p[f],'euclidean')    
          d_m = d_m[iu] 
          M.append(d_m)
      M = np.stack(M) 
      M = norm_scale(M)
      return M
      
  # Genrate dataset  
  def data_generator(T,C):
      X_0 = []
      X_1 = []
      Y = []
      for i in tqdm(range(len(T))): 
          p = np.copy(T[i])
          p = zoom(p,target_l=C.frame_l,joints_num=C.joint_n,joints_dim=C.joint_d)
  
          M = get_CG(p,C)
          X_0.append(M)
          X_1.append(p)
  
      X_0 = np.stack(X_0)  
      X_1 = np.stack(X_1) 
      return X_0,X_1
      
  def poses_diff(x):
      H, W = x.get_shape()[1],x.get_shape()[2]
      x = tf.subtract(x[:,1:,...],x[:,:-1,...])
      x = tf.image.resize(x,size=[H,W]) 
      return x
  
  def pose_motion(P,frame_l):
      P_diff_slow = Lambda(lambda x: poses_diff(x))(P)
      P_diff_slow = Reshape((frame_l,-1))(P_diff_slow)
      P_fast = Lambda(lambda x: x[:,::2,...])(P)
      P_diff_fast = Lambda(lambda x: poses_diff(x))(P_fast)
      P_diff_fast = Reshape((int(frame_l/2),-1))(P_diff_fast)
      return P_diff_slow,P_diff_fast
      
  def c1D(x,filters,kernel):
      x = Conv1D(filters, kernel_size=kernel,padding='same',use_bias=False)(x)
      x = BatchNormalization()(x)
      x = LeakyReLU(alpha=0.2)(x)
      return x
  
  def block(x,filters):
      x = c1D(x,filters,3)
      x = c1D(x,filters,3)
      return x
      
  def d1D(x,filters):
      x = Dense(filters,use_bias=False)(x)
      x = BatchNormalization()(x)
      x = LeakyReLU(alpha=0.2)(x)
      return x
  
  def build_FM(frame_l=32,joint_n=22,joint_d=2,feat_d=231,filters=16):   
      M = Input(shape=(frame_l,feat_d))
      P = Input(shape=(frame_l,joint_n,joint_d))
      
      diff_slow, diff_fast = pose_motion(P,frame_l)
      
      x = c1D(M,filters*2,1)
      x = SpatialDropout1D(0.1)(x)
      x = c1D(x,filters,3)
      x = SpatialDropout1D(0.1)(x)
      x = c1D(x,filters,1)
      x = MaxPooling1D(2)(x)
      x = SpatialDropout1D(0.1)(x)
  
      x_d_slow = c1D(diff_slow,filters*2,1)
      x_d_slow = SpatialDropout1D(0.1)(x_d_slow)
      x_d_slow = c1D(x_d_slow,filters,3)
      x_d_slow = SpatialDropout1D(0.1)(x_d_slow)
      x_d_slow = c1D(x_d_slow,filters,1)
      x_d_slow = MaxPool1D(2)(x_d_slow)
      x_d_slow = SpatialDropout1D(0.1)(x_d_slow)
          
      x_d_fast = c1D(diff_fast,filters*2,1)
      x_d_fast = SpatialDropout1D(0.1)(x_d_fast)
      x_d_fast = c1D(x_d_fast,filters,3) 
      x_d_fast = SpatialDropout1D(0.1)(x_d_fast)
      x_d_fast = c1D(x_d_fast,filters,1) 
      x_d_fast = SpatialDropout1D(0.1)(x_d_fast)
     
      x = concatenate([x,x_d_slow,x_d_fast])
      x = block(x,filters*2)
      x = MaxPool1D(2)(x)
      x = SpatialDropout1D(0.1)(x)
      
      x = block(x,filters*4)
      x = MaxPool1D(2)(x)
      x = SpatialDropout1D(0.1)(x)
  
      x = block(x,filters*8)
      x = SpatialDropout1D(0.1)(x)
      
      return Model(inputs=[M,P],outputs=x)
  
  
  def build_DD_Net(C):
      M = Input(name='M', shape=(C.frame_l,C.feat_d))  
      P = Input(name='P', shape=(C.frame_l,C.joint_n,C.joint_d)) 
      
      FM = build_FM(C.frame_l,C.joint_n,C.joint_d,C.feat_d,C.filters)
      
      x = FM([M,P])
  
      x = GlobalMaxPool1D()(x)
      
      x = d1D(x,128)
      x = Dropout(0.5)(x)
      x = d1D(x,128)
      x = Dropout(0.5)(x)
      x = Dense(C.clc_num, activation='softmax')(x)
      
      ######################Self-supervised part
      model = Model(inputs=[M,P],outputs=x)
      return model
  
  if __name__ == "__main__":
      DD_Net = build_DD_Net(C)
  
      DD_Net.summary()
      DD_Net.load_weights(args.checkpoint)
  
      Test = pickle.load(open(args.input_file, "rb"))
      Test = np.expand_dims(Test, axis=0)
      print(np.shape(Test))
      start = time.time()
      X_test_0,X_test_1 = data_generator(Test,C)
  
      prediction = DD_Net.predict([X_test_0, X_test_1])
      print("Total time: ", time.time() - start)
      print(np.argsort(prediction), prediction[0][np.argsort(prediction)[0][-1]], prediction[0][np.argsort(prediction)[0][-2]])
  