text: import pickle
  import tensorflow as tf
  from util.train_model_util_TensorFlow import train_test_model_demo
  
  AID_DATA_DIR = '../data/Criteo/forOtherModels/'  # 辅助用途的文件路径
  
  """
  TensorFlow 2.0 implementation of Product-based Neural Network[1]
  
  Reference:
  [1] Product-based Neural Networks for User ResponsePrediction,
      Yanru Qu, Han Cai, Kan Ren, Weinan Zhang, Yong Yu, Ying Wen, Jun Wang
  [2] Tensorflow implementation of PNN
      https://github.com/Atomu2014/product-nets
  """
  
  class PNN_layer(tf.keras.Model):
  
      def __init__(self, num_feat, num_field, dropout_deep, deep_layer_sizes, product_layer_dim=10,
                   reg_l1=0.01, reg_l2=1e-5, embedding_size=10, product_type='outer'):
          super().__init__()   # Python2 下使用 super(PNN_layer, self).__init__()
          self.reg_l1 = reg_l1
          self.reg_l2 = reg_l2
          self.num_feat = num_feat                                   # Denoted as
          self.num_field = num_field                                 # Denoted as N
          self.product_layer_dim = product_layer_dim                 # Denoted as D1
          self.dropout_deep = dropout_deep
  
          # Embedding
          feat_embeddings = tf.keras.layers.Embedding(num_feat, embedding_size, embeddings_initializer='uniform')
          self.feat_embeddings = feat_embeddings
  
          initializer = tf.initializers.GlorotUniform()
  
          # linear part
          self.linear_weights = tf.Variable(initializer(shape=(product_layer_dim, num_field, embedding_size)))
  
          # quadratic part
          self.product_type = product_type
          if product_type == 'inner':
              self.theta = tf.Variable(initializer(shape=(product_layer_dim, num_field)))  # D1 * N
          else:
              self.quadratic_weights = tf.Variable(initializer(shape=(product_layer_dim, embedding_size,
                                                                      embedding_size)))   # D1 * M * M
  
          # fc layer
          self.deep_layer_sizes = deep_layer_sizes
  
          # 神经网络方面的参数
          for i in range(len(deep_layer_sizes)):
              setattr(self, 'dense_' + str(i), tf.keras.layers.Dense(deep_layer_sizes[i]))
              setattr(self, 'batchNorm_' + str(i), tf.keras.layers.BatchNormalization())
              setattr(self, 'activation_' + str(i), tf.keras.layers.Activation('relu'))
              setattr(self, 'dropout_' + str(i), tf.keras.layers.Dropout(dropout_deep[i]))
  
          # last layer
          self.fc = tf.keras.layers.Dense(1, activation=None, use_bias=True)
  
      def call(self, feat_index, feat_value, use_dropout=True):
          # embedding part
          feat_embedding = self.feat_embeddings(feat_index)          # Batch * N * M
  
          # linear part
          lz = tf.einsum('bnm,dnm->bd', feat_embedding, self.linear_weights)  # Batch * D1
  
          # quadratic part
          if self.product_type == 'inner':
              theta = tf.einsum('bnm,dn->bdnm', feat_embedding, self.theta)   # Batch * D1 * N * M
              lp = tf.einsum('bdnm,bdnm->bd', theta, theta)
          else:
              embed_sum = tf.reduce_sum(feat_embedding, axis=1)
              p = tf.einsum('bm,bn->bmn', embed_sum, embed_sum)
              lp = tf.einsum('bmn,dmn->bd', p, self.quadratic_weights)  # Batch * D1
  
          y_deep = tf.concat((lz, lp), axis=1)
          if use_dropout:
              y_deep = tf.keras.layers.Dropout(self.dropout_deep[0])(y_deep)
  
          for i in range(len(self.deep_layer_sizes)):
              y_deep = getattr(self, 'dense_' + str(i))(y_deep)
              y_deep = getattr(self, 'batchNorm_' + str(i))(y_deep)
              y_deep = getattr(self, 'activation_' + str(i))(y_deep)
              if use_dropout:
                  y_deep = getattr(self, 'dropout_' + str(i))(y_deep)
  
          output = self.fc(y_deep)
          return output
  
  
  if __name__ == '__main__':
      feat_dict_ = pickle.load(open(AID_DATA_DIR + 'aid_data/feat_dict_10.pkl2', 'rb'))
  
      pnn = PNN_layer(num_feat=len(feat_dict_) + 1, num_field=39, dropout_deep=[0.5, 0.5, 0.5],
                      deep_layer_sizes=[400, 400], product_layer_dim=10,
                      reg_l1=0.01, reg_l2=1e-5, embedding_size=10, product_type='outer')
  
      train_label_path = AID_DATA_DIR + 'train_label'
      train_idx_path = AID_DATA_DIR + 'train_idx'
      train_value_path = AID_DATA_DIR + 'train_value'
  
      test_label_path = AID_DATA_DIR + 'test_label'
      test_idx_path = AID_DATA_DIR + 'test_idx'
      test_value_path = AID_DATA_DIR + 'test_value'
  
      train_test_model_demo(pnn, train_label_path, train_idx_path, train_value_path, test_label_path, test_idx_path,
                            test_value_path)
  