import tensorflow as tf

__weights_dict = dict()

is_train = True
import numpy as np



def load_weights(weight_file):

    if weight_file == None:
        return

    try:
        weights_dict = np.load(weight_file).item()
    except:
        weights_dict = np.load(weight_file, encoding='bytes').item()

    return weights_dict

#modes training, lstm, testing
def KitModel(weight_file = None, X=None, mode="testing"):
    global __weights_dict
    __weights_dict = load_weights(weight_file)

    conv1_7x7_s2_pad = tf.pad(X, paddings=[[0, 0], [3, 4], [3, 4], [0, 0]])
    conv1_7x7_s2    = convolution(conv1_7x7_s2_pad, group=1, strides=[2, 2], padding='VALID', name='conv1/7x7_s2')
    conv1_relu_7x7  = tf.nn.relu(conv1_7x7_s2, name = 'conv1/relu_7x7')
    pool1_3x3_s2_pad = tf.pad(conv1_relu_7x7, paddings = [[0, 0], [0, 1], [0, 1], [0, 0]], constant_values=float('-Inf'))
    pool1_3x3_s2    = tf.nn.max_pool(pool1_3x3_s2_pad, [1, 3, 3, 1], [1, 2, 2, 1], padding='VALID', name='pool1/3x3_s2')
    pool1_norm1     = tf.nn.lrn(pool1_3x3_s2, depth_radius=2, bias=1, alpha=1.99999994948e-05, beta=0.75, name='pool1/norm1')
    conv2_3x3_reduce = convolution(pool1_norm1, group=1, strides=[1, 1], padding='VALID', name='conv2/3x3_reduce')
    conv2_relu_3x3_reduce = tf.nn.relu(conv2_3x3_reduce, name = 'conv2/relu_3x3_reduce')
    conv2_3x3_pad   = tf.pad(conv2_relu_3x3_reduce, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]])
    conv2_3x3       = convolution(conv2_3x3_pad, group=1, strides=[1, 1], padding='VALID', name='conv2/3x3')
    conv2_relu_3x3  = tf.nn.relu(conv2_3x3, name = 'conv2/relu_3x3')
    conv2_norm2     = tf.nn.lrn(conv2_relu_3x3, depth_radius=2, bias=1, alpha=1.99999994948e-05, beta=0.75, name='conv2/norm2')
    pool2_3x3_s2_pad = tf.pad(conv2_norm2, paddings = [[0, 0], [0, 1], [0, 1], [0, 0]], constant_values=float('-Inf'))
    pool2_3x3_s2    = tf.nn.max_pool(pool2_3x3_s2_pad, [1, 3, 3, 1], [1, 2, 2, 1], padding='VALID', name='pool2/3x3_s2')
    inception_3a_pool_pad = tf.pad(pool2_3x3_s2, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]], constant_values=float('-Inf'))
    inception_3a_pool = tf.nn.max_pool(inception_3a_pool_pad, [1, 3, 3, 1], [1, 1, 1, 1], padding='VALID', name='inception_3a/pool')
    inception_3a_1x1 = convolution(pool2_3x3_s2, group=1, strides=[1, 1], padding='VALID', name='inception_3a/1x1')
    inception_3a_5x5_reduce = convolution(pool2_3x3_s2, group=1, strides=[1, 1], padding='VALID', name='inception_3a/5x5_reduce')
    inception_3a_3x3_reduce = convolution(pool2_3x3_s2, group=1, strides=[1, 1], padding='VALID', name='inception_3a/3x3_reduce')
    inception_3a_pool_proj = convolution(inception_3a_pool, group=1, strides=[1, 1], padding='VALID', name='inception_3a/pool_proj')
    inception_3a_relu_1x1 = tf.nn.relu(inception_3a_1x1, name = 'inception_3a/relu_1x1')
    inception_3a_relu_5x5_reduce = tf.nn.relu(inception_3a_5x5_reduce, name = 'inception_3a/relu_5x5_reduce')
    inception_3a_relu_3x3_reduce = tf.nn.relu(inception_3a_3x3_reduce, name = 'inception_3a/relu_3x3_reduce')
    inception_3a_relu_pool_proj = tf.nn.relu(inception_3a_pool_proj, name = 'inception_3a/relu_pool_proj')
    inception_3a_5x5_pad = tf.pad(inception_3a_relu_5x5_reduce, paddings = [[0, 0], [2, 2], [2, 2], [0, 0]])
    inception_3a_5x5 = convolution(inception_3a_5x5_pad, group=1, strides=[1, 1], padding='VALID', name='inception_3a/5x5')
    inception_3a_3x3_pad = tf.pad(inception_3a_relu_3x3_reduce, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]])
    inception_3a_3x3 = convolution(inception_3a_3x3_pad, group=1, strides=[1, 1], padding='VALID', name='inception_3a/3x3')
    inception_3a_relu_5x5 = tf.nn.relu(inception_3a_5x5, name = 'inception_3a/relu_5x5')
    inception_3a_relu_3x3 = tf.nn.relu(inception_3a_3x3, name = 'inception_3a/relu_3x3')
    inception_3a_output = tf.concat([inception_3a_relu_1x1, inception_3a_relu_3x3, inception_3a_relu_5x5, inception_3a_relu_pool_proj], 3, name = 'inception_3a/output')
    inception_3b_3x3_reduce = convolution(inception_3a_output, group=1, strides=[1, 1], padding='VALID', name='inception_3b/3x3_reduce')
    inception_3b_pool_pad = tf.pad(inception_3a_output, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]], constant_values=float('-Inf'))
    inception_3b_pool = tf.nn.max_pool(inception_3b_pool_pad, [1, 3, 3, 1], [1, 1, 1, 1], padding='VALID', name='inception_3b/pool')
    inception_3b_1x1 = convolution(inception_3a_output, group=1, strides=[1, 1], padding='VALID', name='inception_3b/1x1')
    inception_3b_5x5_reduce = convolution(inception_3a_output, group=1, strides=[1, 1], padding='VALID', name='inception_3b/5x5_reduce')
    inception_3b_relu_3x3_reduce = tf.nn.relu(inception_3b_3x3_reduce, name = 'inception_3b/relu_3x3_reduce')
    inception_3b_pool_proj = convolution(inception_3b_pool, group=1, strides=[1, 1], padding='VALID', name='inception_3b/pool_proj')
    inception_3b_relu_1x1 = tf.nn.relu(inception_3b_1x1, name = 'inception_3b/relu_1x1')
    inception_3b_relu_5x5_reduce = tf.nn.relu(inception_3b_5x5_reduce, name = 'inception_3b/relu_5x5_reduce')
    inception_3b_3x3_pad = tf.pad(inception_3b_relu_3x3_reduce, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]])
    inception_3b_3x3 = convolution(inception_3b_3x3_pad, group=1, strides=[1, 1], padding='VALID', name='inception_3b/3x3')
    inception_3b_relu_pool_proj = tf.nn.relu(inception_3b_pool_proj, name = 'inception_3b/relu_pool_proj')
    inception_3b_5x5_pad = tf.pad(inception_3b_relu_5x5_reduce, paddings = [[0, 0], [2, 2], [2, 2], [0, 0]])
    inception_3b_5x5 = convolution(inception_3b_5x5_pad, group=1, strides=[1, 1], padding='VALID', name='inception_3b/5x5')
    inception_3b_relu_3x3 = tf.nn.relu(inception_3b_3x3, name = 'inception_3b/relu_3x3')
    inception_3b_relu_5x5 = tf.nn.relu(inception_3b_5x5, name = 'inception_3b/relu_5x5')
    inception_3b_output = tf.concat([inception_3b_relu_1x1, inception_3b_relu_3x3, inception_3b_relu_5x5, inception_3b_relu_pool_proj], 3, name = 'inception_3b/output')
    pool3_3x3_s2_pad = tf.pad(inception_3b_output, paddings = [[0, 0], [0, 1], [0, 1], [0, 0]], constant_values=float('-Inf'))
    pool3_3x3_s2    = tf.nn.max_pool(pool3_3x3_s2_pad, [1, 3, 3, 1], [1, 2, 2, 1], padding='VALID', name='pool3/3x3_s2')
    inception_4a_1x1 = convolution(pool3_3x3_s2, group=1, strides=[1, 1], padding='VALID', name='inception_4a/1x1')
    inception_4a_3x3_reduce = convolution(pool3_3x3_s2, group=1, strides=[1, 1], padding='VALID', name='inception_4a/3x3_reduce')
    inception_4a_5x5_reduce = convolution(pool3_3x3_s2, group=1, strides=[1, 1], padding='VALID', name='inception_4a/5x5_reduce')
    inception_4a_pool_pad = tf.pad(pool3_3x3_s2, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]], constant_values=float('-Inf'))
    inception_4a_pool = tf.nn.max_pool(inception_4a_pool_pad, [1, 3, 3, 1], [1, 1, 1, 1], padding='VALID', name='inception_4a/pool')
    inception_4a_relu_1x1 = tf.nn.relu(inception_4a_1x1, name = 'inception_4a/relu_1x1')
    inception_4a_relu_3x3_reduce = tf.nn.relu(inception_4a_3x3_reduce, name = 'inception_4a/relu_3x3_reduce')
    inception_4a_relu_5x5_reduce = tf.nn.relu(inception_4a_5x5_reduce, name = 'inception_4a/relu_5x5_reduce')
    inception_4a_pool_proj = convolution(inception_4a_pool, group=1, strides=[1, 1], padding='VALID', name='inception_4a/pool_proj')
    inception_4a_3x3_pad = tf.pad(inception_4a_relu_3x3_reduce, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]])
    inception_4a_3x3 = convolution(inception_4a_3x3_pad, group=1, strides=[1, 1], padding='VALID', name='inception_4a/3x3')
    inception_4a_5x5_pad = tf.pad(inception_4a_relu_5x5_reduce, paddings = [[0, 0], [2, 2], [2, 2], [0, 0]])
    inception_4a_5x5 = convolution(inception_4a_5x5_pad, group=1, strides=[1, 1], padding='VALID', name='inception_4a/5x5')
    inception_4a_relu_pool_proj = tf.nn.relu(inception_4a_pool_proj, name = 'inception_4a/relu_pool_proj')
    inception_4a_relu_3x3 = tf.nn.relu(inception_4a_3x3, name = 'inception_4a/relu_3x3')
    inception_4a_relu_5x5 = tf.nn.relu(inception_4a_5x5, name = 'inception_4a/relu_5x5')
    inception_4a_output = tf.concat([inception_4a_relu_1x1, inception_4a_relu_3x3, inception_4a_relu_5x5, inception_4a_relu_pool_proj], 3, name = 'inception_4a/output')
    inception_4b_pool_pad = tf.pad(inception_4a_output, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]], constant_values=float('-Inf'))
    inception_4b_pool = tf.nn.max_pool(inception_4b_pool_pad, [1, 3, 3, 1], [1, 1, 1, 1], padding='VALID', name='inception_4b/pool')
    loss1_ave_pool_pad = tf.pad(inception_4a_output, paddings = [[0, 0], [0, 1], [0, 1], [0, 0]])
    loss1_ave_pool  = tf.nn.avg_pool(loss1_ave_pool_pad, [1, 5, 5, 1], [1, 3, 3, 1], padding='VALID', name='loss1/ave_pool')
    inception_4b_5x5_reduce = convolution(inception_4a_output, group=1, strides=[1, 1], padding='VALID', name='inception_4b/5x5_reduce')
    inception_4b_1x1 = convolution(inception_4a_output, group=1, strides=[1, 1], padding='VALID', name='inception_4b/1x1')
    inception_4b_3x3_reduce = convolution(inception_4a_output, group=1, strides=[1, 1], padding='VALID', name='inception_4b/3x3_reduce')
    inception_4b_pool_proj = convolution(inception_4b_pool, group=1, strides=[1, 1], padding='VALID', name='inception_4b/pool_proj')
    loss1_conv      = convolution(loss1_ave_pool, group=1, strides=[1, 1], padding='VALID', name='loss1/conv')
    inception_4b_relu_5x5_reduce = tf.nn.relu(inception_4b_5x5_reduce, name = 'inception_4b/relu_5x5_reduce')
    inception_4b_relu_1x1 = tf.nn.relu(inception_4b_1x1, name = 'inception_4b/relu_1x1')
    inception_4b_relu_3x3_reduce = tf.nn.relu(inception_4b_3x3_reduce, name = 'inception_4b/relu_3x3_reduce')
    inception_4b_relu_pool_proj = tf.nn.relu(inception_4b_pool_proj, name = 'inception_4b/relu_pool_proj')
    loss1_relu_conv = tf.nn.relu(loss1_conv, name = 'loss1/relu_conv')
    inception_4b_5x5_pad = tf.pad(inception_4b_relu_5x5_reduce, paddings = [[0, 0], [2, 2], [2, 2], [0, 0]])
    inception_4b_5x5 = convolution(inception_4b_5x5_pad, group=1, strides=[1, 1], padding='VALID', name='inception_4b/5x5')
    inception_4b_3x3_pad = tf.pad(inception_4b_relu_3x3_reduce, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]])
    inception_4b_3x3 = convolution(inception_4b_3x3_pad, group=1, strides=[1, 1], padding='VALID', name='inception_4b/3x3')
    loss1_fc_0      = tf.contrib.layers.flatten(loss1_relu_conv)
    inception_4b_relu_5x5 = tf.nn.relu(inception_4b_5x5, name = 'inception_4b/relu_5x5')
    inception_4b_relu_3x3 = tf.nn.relu(inception_4b_3x3, name = 'inception_4b/relu_3x3')
    loss1_fc_1      = tf.layers.dense(loss1_fc_0, 1024, kernel_initializer = tf.constant_initializer(__weights_dict['loss1/fc_1']['weights']),
                                      bias_initializer = tf.constant_initializer(__weights_dict['loss1/fc_1']['bias']), use_bias=True, name='loss1/fc_1')
    #loss1_fc_1_dropout = tf.nn.dropout(loss1_fc_1, dropout, name='loss1_fc_1_dropout')
    inception_4b_output = tf.concat([inception_4b_relu_1x1, inception_4b_relu_3x3, inception_4b_relu_5x5, inception_4b_relu_pool_proj], 3, name = 'inception_4b/output')
    loss1_relu_fc   = tf.nn.relu(loss1_fc_1, name = 'loss1/relu_fc')
    inception_4c_5x5_reduce = convolution(inception_4b_output, group=1, strides=[1, 1], padding='VALID', name='inception_4c/5x5_reduce')
    inception_4c_pool_pad = tf.pad(inception_4b_output, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]], constant_values=float('-Inf'))
    inception_4c_pool = tf.nn.max_pool(inception_4c_pool_pad, [1, 3, 3, 1], [1, 1, 1, 1], padding='VALID', name='inception_4c/pool')
    inception_4c_1x1 = convolution(inception_4b_output, group=1, strides=[1, 1], padding='VALID', name='inception_4c/1x1')
    inception_4c_3x3_reduce = convolution(inception_4b_output, group=1, strides=[1, 1], padding='VALID', name='inception_4c/3x3_reduce')
    inception_4c_relu_5x5_reduce = tf.nn.relu(inception_4c_5x5_reduce, name = 'inception_4c/relu_5x5_reduce')
    inception_4c_pool_proj = convolution(inception_4c_pool, group=1, strides=[1, 1], padding='VALID', name='inception_4c/pool_proj')
    inception_4c_relu_1x1 = tf.nn.relu(inception_4c_1x1, name = 'inception_4c/relu_1x1')
    inception_4c_relu_3x3_reduce = tf.nn.relu(inception_4c_3x3_reduce, name = 'inception_4c/relu_3x3_reduce')
    loss1_SLclassifier_0 = tf.contrib.layers.flatten(loss1_relu_fc)
    inception_4c_5x5_pad = tf.pad(inception_4c_relu_5x5_reduce, paddings = [[0, 0], [2, 2], [2, 2], [0, 0]])
    inception_4c_5x5 = convolution(inception_4c_5x5_pad, group=1, strides=[1, 1], padding='VALID', name='inception_4c/5x5')
    inception_4c_relu_pool_proj = tf.nn.relu(inception_4c_pool_proj, name = 'inception_4c/relu_pool_proj')
    inception_4c_3x3_pad = tf.pad(inception_4c_relu_3x3_reduce, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]])
    inception_4c_3x3 = convolution(inception_4c_3x3_pad, group=1, strides=[1, 1], padding='VALID', name='inception_4c/3x3')
    loss1_SLclassifier_1 = tf.layers.dense(loss1_SLclassifier_0, 24, kernel_initializer=tf.contrib.layers.xavier_initializer(),
                                           bias_initializer=tf.zeros_initializer(), name = 'inception_4c/FC')
    inception_4c_relu_5x5 = tf.nn.relu(inception_4c_5x5, name = 'inception_4c/relu_5x5')
    inception_4c_relu_3x3 = tf.nn.relu(inception_4c_3x3, name = 'inception_4c/relu_3x3')
    inception_4c_output = tf.concat([inception_4c_relu_1x1, inception_4c_relu_3x3, inception_4c_relu_5x5, inception_4c_relu_pool_proj], 3, name = 'inception_4c/output')
    inception_4d_pool_pad = tf.pad(inception_4c_output, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]], constant_values=float('-Inf'))
    inception_4d_pool = tf.nn.max_pool(inception_4d_pool_pad, [1, 3, 3, 1], [1, 1, 1, 1], padding='VALID', name='inception_4d/pool')
    inception_4d_3x3_reduce = convolution(inception_4c_output, group=1, strides=[1, 1], padding='VALID', name='inception_4d/3x3_reduce')
    inception_4d_1x1 = convolution(inception_4c_output, group=1, strides=[1, 1], padding='VALID', name='inception_4d/1x1')
    inception_4d_5x5_reduce = convolution(inception_4c_output, group=1, strides=[1, 1], padding='VALID', name='inception_4d/5x5_reduce')
    inception_4d_pool_proj = convolution(inception_4d_pool, group=1, strides=[1, 1], padding='VALID', name='inception_4d/pool_proj')
    inception_4d_relu_3x3_reduce = tf.nn.relu(inception_4d_3x3_reduce, name = 'inception_4d/relu_3x3_reduce')
    inception_4d_relu_1x1 = tf.nn.relu(inception_4d_1x1, name = 'inception_4d/relu_1x1')
    inception_4d_relu_5x5_reduce = tf.nn.relu(inception_4d_5x5_reduce, name = 'inception_4d/relu_5x5_reduce')
    inception_4d_relu_pool_proj = tf.nn.relu(inception_4d_pool_proj, name = 'inception_4d/relu_pool_proj')
    inception_4d_3x3_pad = tf.pad(inception_4d_relu_3x3_reduce, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]])
    inception_4d_3x3 = convolution(inception_4d_3x3_pad, group=1, strides=[1, 1], padding='VALID', name='inception_4d/3x3')
    inception_4d_5x5_pad = tf.pad(inception_4d_relu_5x5_reduce, paddings = [[0, 0], [2, 2], [2, 2], [0, 0]])
    inception_4d_5x5 = convolution(inception_4d_5x5_pad, group=1, strides=[1, 1], padding='VALID', name='inception_4d/5x5')
    inception_4d_relu_3x3 = tf.nn.relu(inception_4d_3x3, name = 'inception_4d/relu_3x3')
    inception_4d_relu_5x5 = tf.nn.relu(inception_4d_5x5, name = 'inception_4d/relu_5x5')
    inception_4d_output = tf.concat([inception_4d_relu_1x1, inception_4d_relu_3x3, inception_4d_relu_5x5, inception_4d_relu_pool_proj], 3, name = 'inception_4d/output')
    inception_4e_1x1 = convolution(inception_4d_output, group=1, strides=[1, 1], padding='VALID', name='inception_4e/1x1')
    inception_4e_5x5_reduce = convolution(inception_4d_output, group=1, strides=[1, 1], padding='VALID', name='inception_4e/5x5_reduce')
    loss2_ave_pool_pad = tf.pad(inception_4d_output, paddings = [[0, 0], [0, 1], [0, 1], [0, 0]])
    loss2_ave_pool  = tf.nn.avg_pool(loss2_ave_pool_pad, [1, 5, 5, 1], [1, 3, 3, 1], padding='VALID', name='loss2/ave_pool')
    inception_4e_3x3_reduce = convolution(inception_4d_output, group=1, strides=[1, 1], padding='VALID', name='inception_4e/3x3_reduce')
    inception_4e_pool_pad = tf.pad(inception_4d_output, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]], constant_values=float('-Inf'))
    inception_4e_pool = tf.nn.max_pool(inception_4e_pool_pad, [1, 3, 3, 1], [1, 1, 1, 1], padding='VALID', name='inception_4e/pool')
    inception_4e_relu_1x1 = tf.nn.relu(inception_4e_1x1, name = 'inception_4e/relu_1x1')
    inception_4e_relu_5x5_reduce = tf.nn.relu(inception_4e_5x5_reduce, name = 'inception_4e/relu_5x5_reduce')
    loss2_conv      = convolution(loss2_ave_pool, group=1, strides=[1, 1], padding='VALID', name='loss2/conv')
    inception_4e_relu_3x3_reduce = tf.nn.relu(inception_4e_3x3_reduce, name = 'inception_4e/relu_3x3_reduce')
    inception_4e_pool_proj = convolution(inception_4e_pool, group=1, strides=[1, 1], padding='VALID', name='inception_4e/pool_proj')
    inception_4e_5x5_pad = tf.pad(inception_4e_relu_5x5_reduce, paddings = [[0, 0], [2, 2], [2, 2], [0, 0]])
    inception_4e_5x5 = convolution(inception_4e_5x5_pad, group=1, strides=[1, 1], padding='VALID', name='inception_4e/5x5')
    loss2_relu_conv = tf.nn.relu(loss2_conv, name = 'loss2/relu_conv')
    inception_4e_3x3_pad = tf.pad(inception_4e_relu_3x3_reduce, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]])
    inception_4e_3x3 = convolution(inception_4e_3x3_pad, group=1, strides=[1, 1], padding='VALID', name='inception_4e/3x3')
    inception_4e_relu_pool_proj = tf.nn.relu(inception_4e_pool_proj, name = 'inception_4e/relu_pool_proj')
    inception_4e_relu_5x5 = tf.nn.relu(inception_4e_5x5, name = 'inception_4e/relu_5x5')
    loss2_fc_0      = tf.contrib.layers.flatten(loss2_relu_conv)
    inception_4e_relu_3x3 = tf.nn.relu(inception_4e_3x3, name = 'inception_4e/relu_3x3')
    loss2_fc_1      = tf.layers.dense(loss2_fc_0, 1024, kernel_initializer = tf.constant_initializer(__weights_dict['loss2/fc_1']['weights']),
                                      bias_initializer = tf.constant_initializer(__weights_dict['loss2/fc_1']['bias']), use_bias=True, name='loss2/fc_1')
    #loss2_fc_1_dropout = tf.nn.dropout(loss2_fc_1, dropout, name='loss2_fc_1_dropout')
    inception_4e_output = tf.concat([inception_4e_relu_1x1, inception_4e_relu_3x3, inception_4e_relu_5x5, inception_4e_relu_pool_proj], 3, name = 'inception_4e/output')
    loss2_relu_fc   = tf.nn.relu(loss2_fc_1, name = 'loss2/relu_fc')
    pool4_3x3_s2_pad = tf.pad(inception_4e_output, paddings = [[0, 0], [0, 1], [0, 1], [0, 0]], constant_values=float('-Inf'))
    pool4_3x3_s2    = tf.nn.max_pool(pool4_3x3_s2_pad, [1, 3, 3, 1], [1, 2, 2, 1], padding='VALID', name='pool4/3x3_s2')
    inception_5a_1x1 = convolution(pool4_3x3_s2, group=1, strides=[1, 1], padding='VALID', name='inception_5a/1x1')
    inception_5a_5x5_reduce = convolution(pool4_3x3_s2, group=1, strides=[1, 1], padding='VALID', name='inception_5a/5x5_reduce')
    inception_5a_pool_pad = tf.pad(pool4_3x3_s2, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]], constant_values=float('-Inf'))
    inception_5a_pool = tf.nn.max_pool(inception_5a_pool_pad, [1, 3, 3, 1], [1, 1, 1, 1], padding='VALID', name='inception_5a/pool')
    inception_5a_3x3_reduce = convolution(pool4_3x3_s2, group=1, strides=[1, 1], padding='VALID', name='inception_5a/3x3_reduce')
    loss2_SLclassifier_0 = tf.contrib.layers.flatten(loss2_relu_fc)
    inception_5a_relu_1x1 = tf.nn.relu(inception_5a_1x1, name = 'inception_5a/relu_1x1')
    inception_5a_relu_5x5_reduce = tf.nn.relu(inception_5a_5x5_reduce, name = 'inception_5a/relu_5x5_reduce')
    inception_5a_pool_proj = convolution(inception_5a_pool, group=1, strides=[1, 1], padding='VALID', name='inception_5a/pool_proj')
    inception_5a_relu_3x3_reduce = tf.nn.relu(inception_5a_3x3_reduce, name = 'inception_5a/relu_3x3_reduce')
    loss2_SLclassifier_1 = tf.layers.dense(loss2_SLclassifier_0, 24, kernel_initializer=tf.contrib.layers.xavier_initializer(),
                                           bias_initializer=tf.zeros_initializer(), name='incpetion_5a/FC')
    inception_5a_5x5_pad = tf.pad(inception_5a_relu_5x5_reduce, paddings = [[0, 0], [2, 2], [2, 2], [0, 0]])
    inception_5a_5x5 = convolution(inception_5a_5x5_pad, group=1, strides=[1, 1], padding='VALID', name='inception_5a/5x5')
    inception_5a_relu_pool_proj = tf.nn.relu(inception_5a_pool_proj, name = 'inception_5a/relu_pool_proj')
    inception_5a_3x3_pad = tf.pad(inception_5a_relu_3x3_reduce, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]])
    inception_5a_3x3 = convolution(inception_5a_3x3_pad, group=1, strides=[1, 1], padding='VALID', name='inception_5a/3x3')
    inception_5a_relu_5x5 = tf.nn.relu(inception_5a_5x5, name = 'inception_5a/relu_5x5')
    inception_5a_relu_3x3 = tf.nn.relu(inception_5a_3x3, name = 'inception_5a/relu_3x3')
    inception_5a_output = tf.concat([inception_5a_relu_1x1, inception_5a_relu_3x3, inception_5a_relu_5x5, inception_5a_relu_pool_proj], 3, name = 'inception_5a/output')
    inception_5b_3x3_reduce = convolution(inception_5a_output, group=1, strides=[1, 1], padding='VALID', name='inception_5b/3x3_reduce')
    inception_5b_pool_pad = tf.pad(inception_5a_output, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]], constant_values=float('-Inf'))
    inception_5b_pool = tf.nn.max_pool(inception_5b_pool_pad, [1, 3, 3, 1], [1, 1, 1, 1], padding='VALID', name='inception_5b/pool')
    inception_5b_5x5_reduce = convolution(inception_5a_output, group=1, strides=[1, 1], padding='VALID', name='inception_5b/5x5_reduce')
    inception_5b_1x1 = convolution(inception_5a_output, group=1, strides=[1, 1], padding='VALID', name='inception_5b/1x1')
    inception_5b_relu_3x3_reduce = tf.nn.relu(inception_5b_3x3_reduce, name = 'inception_5b/relu_3x3_reduce')
    inception_5b_pool_proj = convolution(inception_5b_pool, group=1, strides=[1, 1], padding='VALID', name='inception_5b/pool_proj')
    inception_5b_relu_5x5_reduce = tf.nn.relu(inception_5b_5x5_reduce, name = 'inception_5b/relu_5x5_reduce')
    inception_5b_relu_1x1 = tf.nn.relu(inception_5b_1x1, name = 'inception_5b/relu_1x1')
    inception_5b_3x3_pad = tf.pad(inception_5b_relu_3x3_reduce, paddings = [[0, 0], [1, 1], [1, 1], [0, 0]])
    inception_5b_3x3 = convolution(inception_5b_3x3_pad, group=1, strides=[1, 1], padding='VALID', name='inception_5b/3x3')
    inception_5b_relu_pool_proj = tf.nn.relu(inception_5b_pool_proj, name = 'inception_5b/relu_pool_proj')
    inception_5b_5x5_pad = tf.pad(inception_5b_relu_5x5_reduce, paddings = [[0, 0], [2, 2], [2, 2], [0, 0]])
    inception_5b_5x5 = convolution(inception_5b_5x5_pad, group=1, strides=[1, 1], padding='VALID', name='inception_5b/5x5')
    inception_5b_relu_3x3 = tf.nn.relu(inception_5b_3x3, name = 'inception_5b/relu_3x3')
    inception_5b_relu_5x5 = tf.nn.relu(inception_5b_5x5, name = 'inception_5b/relu_5x5')
    inception_5b_output = tf.concat([inception_5b_relu_1x1, inception_5b_relu_3x3, inception_5b_relu_5x5, inception_5b_relu_pool_proj], 3, name = 'inception_5b/output')
    pool5_7x7_s1    = tf.nn.avg_pool(inception_5b_output, [1, 7, 7, 1], [1, 1, 1, 1], padding='VALID', name='pool5/7x7_s1')
    loss3_SLclassifier_0 = tf.contrib.layers.flatten(pool5_7x7_s1)
    loss3_SLclassifier_1 = tf.layers.dense(loss3_SLclassifier_0, 24, kernel_initializer=tf.contrib.layers.xavier_initializer(),
                                           bias_initializer=tf.zeros_initializer(), name = 'inception_5b/FC')
    prob_3            = tf.nn.softmax(loss3_SLclassifier_1, name = 'prob3')
    prob_2            = tf.nn.softmax(loss2_SLclassifier_1, name = 'prob2')
    prob_1            = tf.nn.softmax(loss1_SLclassifier_1, name = 'prob1')

    if mode is "training":
        return loss3_SLclassifier_1, loss2_SLclassifier_1, loss1_SLclassifier_1
    elif mode is "lstm":
        return loss3_SLclassifier_0
    else: # testing mode
        return prob_1, prob_2, prob_3


def convolution(input, name, group, **kwargs):
    w = tf.Variable(__weights_dict[name]['weights'], trainable=is_train, name=name + "_weight")
    if group == 1:
        layer = tf.nn.convolution(input, w, name=name, **kwargs)
    else:
        weight_groups = tf.split(w, num_or_size_splits=group, axis=-1)
        xs = tf.split(input, num_or_size_splits=group, axis=-1)
        convolved = [tf.nn.convolution(x, weight, name=name, **kwargs) for
                    (x, weight) in zip(xs, weight_groups)]
        layer = tf.concat(convolved, axis=-1)

    if 'bias' in __weights_dict[name]:
        b = tf.Variable(__weights_dict[name]['bias'], trainable=is_train, name=name + "_bias")
        layer = layer + b
    return layer
