def split_preprocess_Data(degree1, degree2, strength1, strength2, percentage =1):     
    #   1. load the data
    
    x_original_train, train_target, x_original_test, val_target = assign2_utils.load_dataset()
    #train_pairs, val_pairs = transform_dataset(x_original_train, x_original_test, 30, 0.15)
    # 2. split the datset.
    x_original_train = x_original_train.astype('float32')
    x_original_test = x_original_test.astype('float32')
    
    normaliseValue = 255
    x_original_train /= normaliseValue # normalized the entries between 0 and 1
    x_original_test /= normaliseValue
    
    x_original_train1, x_original_train2, train_target1, train_target2  = split_Data(x_original_train,train_target, percentage)
    #x_original_test1, x_original_test2 , val_target1, val_target2  = split_Data(x_original_test,val_target, percentage)

    # 3. transform the dataset.
    warped_pairs1 = np.array([assign2_utils.random_deform(x, degree1, strength1) for x in x_original_train1])
    warped_pairs2 = np.array([assign2_utils.random_deform(x, degree2, strength2) for x in x_original_train2])
    # train_pairs2 = np.array([assign2_utils.random_deform(x, degree2, strength2) for x in x_original_train2]
    

    digit_indicesTrain1 = [np.where(train_target[train_target1] == i)[0] for i in range(NumberOfClass)]
    train_pairs1, train_y1 = create_pairs(warped_pairs1, digit_indicesTrain1, percentage)
    digit_indicesTrain2 = [np.where(train_target[train_target2] == i)[0] for i in range(NumberOfClass)]
    train_pairs2, train_y2 = create_pairs(warped_pairs2, digit_indicesTrain2,  percentage)
    

    #   4. reshape the pairs for 2D  convolutional layer
    
    train_twin1_input1, train_twin2_input1 = reshape_input(image_width, image_height, num_channels, train_pairs1)
    train_twin1_input2, train_twin2_input2 = reshape_input(image_width, image_height, num_channels, train_pairs2)

    return train_twin1_input1, train_twin2_input1, train_twin1_input2, train_twin2_input2, train_y1, train_y2
示例#2
0
def configure_experiments(degree, strength):
    '''
    Define the planned experiments here
    1. load the data
    2. transformed data
    3. Create the positive and negative pairs
    4. run experiment
    5. output report   
    
       @param
      : 
       @return
      :
    '''

    #    1. load the data
    x_original_train, y_train, x_original_test, y_test = assign2_utils.load_dataset(
    )

    #2. transformed data
    if (degree != 0):
        train_pairs, train_y, val_pairs, val_y = transform_dataset(
            x_original_train, x_original_test, degree, strength)

    else:
        train_pairs, train_y, val_pairs, val_y = x_original_train, y_train, x_original_test, y_test

#    3. Create the positive and negative pairs
#    (the total number of pairs, one pair(2 numbers) in the same or not same classification, 28*28 )
    digit_indicesTrain = [np.where(train_y == i)[0] for i in range(10)]
    train_pairs, train_y = create_pairs(train_pairs, digit_indicesTrain)
    #
    digit_indicesTest = [np.where(val_y == i)[0] for i in range(10)]
    val_pairs, val_y = create_pairs(val_pairs, digit_indicesTest)
示例#3
0
def initialize_dataset(dataset):
    '''
    Generate datasets and save them into file. 
    If there is not physical file, the dataset always be generated
        Arg:
            dataset: the dataset in SETTINGS which is SETTINGS['dataset']
    
    '''
    if not os.path.isfile('./mnist_dataset.npz') or dataset['create_original_dataset']:
        x_train, y_train, x_test, y_test = assign2_utils.load_dataset()
        np.savez('mnist_dataset.npz', x_train=x_train, y_train=y_train,
                                  x_test=x_test, y_test=y_test)
    
    if not os.path.isfile('./mnist_warped_dataset.npz') or dataset['create_warped_dataset']:
        generate_warped_dataset(dataset)
def noSplit_preprocess_Data(degree, strength):
    '''
    This function prepares the data set for the training stage (and validation)
    1. Load the data
    2. Transform data (if warping is needed)
    3. Create the positive and negative pairs
    4. Reshape the pairs for 2D convolutional layer
    5. Split into training / validation datasets   
    
       @param
        degree: The max degree of the transformation
        strength: The strength of the transformation
        percentage : Percentage of dataset used for training
       @return
      :
    '''
    #   1. load the data
    x_original_train, train_target, x_original_test, val_target = assign2_utils.load_dataset()
    
    x_original_train = x_original_train.astype('float32')
    x_original_test = x_original_test.astype('float32')
    
    x_original_train /= 255 # normalized the entries between 0 and 1
    x_original_test /= 255
    
    
    #   2. transformed data
    if (degree != 0 or strength !=0 ):
        train_pairs, val_pairs = transform_dataset(x_original_train, x_original_test, degree, strength)
    else:
        train_pairs, val_pairs = x_original_train, x_original_test

    #   3. Create the positive and negative pairs
    #   the total number of pairs, one pair(2 numbers) in the same or not same classification, 28*28 

    digit_indicesTrain = [np.where(train_target == i)[0] for i in range(10)]
    digit_indicesTest = [np.where(val_target == i)[0] for i in range(10)]

    train_pairs, train_y = create_pairs(train_pairs, digit_indicesTrain)
    val_pairs, val_y = create_pairs(val_pairs, digit_indicesTest)
        
        #   4. reshape the pairs for 2D  convolutional layer
    train_twin1_input, train_twin2_input = reshape_input(image_width, image_height, num_channels, train_pairs)
    val_twin1_input, val_twin2_input = reshape_input(image_width, image_height, num_channels, val_pairs)
    
    return train_twin1_input, train_twin2_input, val_twin1_input, val_twin2_input, train_y, val_y
示例#5
0
def initialize_dataset(dataset):
    '''
    Generate datasets and save them into file. 
    If there is not physical file, the dataset always be generated
        Arg:
            dataset: the dataset in SETTINGS which is SETTINGS['dataset']
    
    '''
    if not os.path.isfile(dataset['original_file_name']
                          ) or dataset['create_original_dataset']:
        x_train, y_train, x_test, y_test = assign2_utils.load_dataset()
        np.savez(dataset['original_file_name'],
                 x_train=x_train,
                 y_train=y_train,
                 x_test=x_test,
                 y_test=y_test)

    if not os.path.isfile(
            dataset['hardset_file_name']) or dataset['create_hard_dataset']:
        generate_warped_dataset(dataset['original_file_name'],
                                dataset['hardset_file_name'],
                                dataset['hard_set'],
                                dataset['hard_pair_rotation'],
                                dataset['hard_pair_variation'])

    if not os.path.isfile(
            dataset['easyset_file_name']) or dataset['create_easy_dataset']:
        generate_warped_dataset(dataset['original_file_name'],
                                dataset['easyset_file_name'],
                                dataset['easy_set'],
                                dataset['easy_pair_rotation'],
                                dataset['easy_pair_variation'])

    if not os.path.isfile(
            './test_dataset.npz') or dataset['create_test_dataset']:
        generate_testset(dataset['original_file_name'], dataset['test_set'],
                         dataset['testset_rotation'],
                         dataset['testset_variation'])
示例#6
0
def simplistic_solution():
    '''
    
    Train a Siamese network to predict whether two input images correspond to the 
    same digit.
    
    WARNING: 
        in your submission, you should use auxiliary functions to create the 
        Siamese network, to train it, and to compute its performance.
    
    
    '''
    def create_simplistic_base_network(input_dim):
        '''
        Base network to be shared (eq. to feature extraction).
        '''
        seq = keras.models.Sequential()
        seq.add(keras.layers.Dense(128, input_shape=(input_dim,), activation='relu'))
        seq.add(keras.layers.Dropout(0.1))
        seq.add(keras.layers.Dense(128, activation='relu'))
        seq.add(keras.layers.Dropout(0.1))
        seq.add(keras.layers.Dense(128, activation='relu'))
        return seq
        # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
    
    # load the dataset
    x_train, y_train, x_test, y_test  = assign2_utils.load_dataset()

    # Example of magic numbers (6000, 784)
    # This should be avoided. Here we could/should have retrieve the
    # dimensions of the arrays using the numpy ndarray method shape 
    x_train = x_train.reshape(60000, 784) 
    x_test = x_test.reshape(10000, 784)
    x_train = x_train.astype('float32')
    x_test = x_test.astype('float32')
    x_train /= 255 # normalized the entries between 0 and 1
    x_test /= 255
    input_dim = 784 # 28x28

    #
    epochs = 20

    # create training+test positive and negative pairs
    digit_indices = [np.where(y_train == i)[0] for i in range(10)]
    tr_pairs, tr_y = create_pairs(x_train, digit_indices)
    
    digit_indices = [np.where(y_test == i)[0] for i in range(10)]
    te_pairs, te_y = create_pairs(x_test, digit_indices)
    
    # network definition
    base_network = create_simplistic_base_network(input_dim)
    
    input_a = keras.layers.Input(shape=(input_dim,))
    input_b = keras.layers.Input(shape=(input_dim,))
    
    # because we re-use the same instance `base_network`,
    # the weights of the network
    # will be shared across the two branches
    processed_a = base_network(input_a)
    processed_b = base_network(input_b)
    
    # node to compute the distance between the two vectors
    # processed_a and processed_a
    distance = keras.layers.Lambda(euclidean_distance)([processed_a, processed_b])
    
    # Our model take as input a pair of images input_a and input_b
    # and output the Euclidian distance of the mapped inputs
    model = keras.models.Model([input_a, input_b], distance)

    callback = siamese_callback([te_pairs[:, 0], te_pairs[:, 1]], te_y)
#    filepath="weights.best.hdf5"
#    earlyStopping = EarlyStopping(monitor='val_loss', min_delta=2, patience=0, verbose=0, mode='auto')
#    checkpointer = ModelCheckpoint(filepath, monitor='val_loss', verbose=1, save_best_only=True, mode='min')

    callback_list = [callback]
    # train
    rms = keras.optimizers.RMSprop()
    model.compile(loss=contrastive_loss, optimizer=rms)
    # important code - donot delete line below for loading model from file
#    model = load_model('best_model.h5', custom_objects={'contrastive_loss': contrastive_loss})
    model.fit([tr_pairs[:, 0], tr_pairs[:, 1]], tr_y,
              batch_size=128,
              epochs=epochs,
              validation_data=([te_pairs[:, 0], te_pairs[:, 1]], te_y), 
              callbacks=callback_list)
    
    # compute final accuracy on training and test sets
    pred_train = model.predict([tr_pairs[:, 0], tr_pairs[:, 1]])
    tr_acc = compute_accuracy(pred_train, tr_y)
    pred_test = model.predict([te_pairs[:, 0], te_pairs[:, 1]])
    te_acc = compute_accuracy(pred_test, te_y)
#    
    print('* Accuracy on training set: %0.2f%%' % (100 * tr_acc))
    print('* Accuracy on test set: %0.2f%%' % (100 * te_acc))
    
    visualise_roc(pred_train, tr_y, pred_test, te_y)
示例#7
0
    
    print('* Accuracy on training set: %0.2f%%' % (100 * tr_acc))
    print('* Accuracy on test set: %0.2f%%' % (100 * te_acc))
    print('* Accuracy on test set (small warp): %0.2f%%' % (100 * te_S_acc))
    print('* Accuracy on test set (large warp): %0.2f%%' % (100 * te_L_acc))


#------------------------------------------------------------------------------        

#----------------------------- SETTINGS ---------------------------------------
COLOR_INTENSITY = 255 # Scalar used to normalize values in the MNIST Dataset
ROTATION = 45 # Maximum Rotational Scalar for Warped Dataset
STRENGTH = 0.3 # Maximum Strength Value for Warped Dataset

#------------------------ Load MNIST Dataset ----------------------------------
x_train, y_train, x_test, y_test  = assign2_utils.load_dataset()
input_dim = x_train.shape[1:3]# 28x28

#---=------------------------- Mixed Dataset ----------------------------------
x_a, y_a = create_warped_dataset(x_train,y_train,0,0,output_size=50000) # Unwarped Data
x_b, y_b = create_warped_dataset(x_train,y_train,(ROTATION/2),(STRENGTH/2),output_size=25000) # Light Warped Data
x_c, y_c = create_warped_dataset(x_train,y_train,ROTATION,STRENGTH,output_size=25000) # Heavy Warped Data

# Concatinate Mixed Set together
x_train_mix = np.concatenate((x_a,x_b,x_c))
y_train_mix = np.concatenate((y_a,y_b,y_c))

x_train_mix = x_train_mix.reshape(x_train_mix.shape[0],input_dim[0],input_dim[1],1)
x_train_mix = x_train_mix.astype('float32')

#--------------------------- Small Warp Dataset -------------------------------
示例#8
0
def simplistic_solution():
    '''
    
    Train a Siamese network to predict whether two input images correspond to the 
    same digit.
    
    WARNING: 
        in your submission, you should use auxiliary functions to create the 
        Siamese network, to train it, and to compute its performance.
    
    
    '''
    def create_simplistic_base_network(input_dim):
        '''
        Base network to be shared (eq. to feature extraction).
        '''
        seq = keras.models.Sequential()
        seq.add(
            keras.layers.Dense(128,
                               input_shape=(input_dim, ),
                               activation='relu'))
        seq.add(keras.layers.Dropout(0.1))
        seq.add(keras.layers.Dense(128, activation='relu'))
        seq.add(keras.layers.Dropout(0.1))
        seq.add(keras.layers.Dense(128, activation='relu'))
        return seq
        # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

    # load the dataset
    x_train, y_train, x_test, y_test = assign2_utils.load_dataset()

    # Example of magic numbers (6000, 784)
    # This should be avoided. Here we could/should have retrieve the
    # dimensions of the arrays using the numpy ndarray method shape
    x_train = x_train.reshape(60000, 784)
    x_test = x_test.reshape(10000, 784)
    x_train = x_train.astype('float32')
    x_test = x_test.astype('float32')
    x_train /= 255  # normalized the entries between 0 and 1
    x_test /= 255
    input_dim = 784  # 28x28

    #

    # create training+test positive and negative pairs
    digit_indices = [np.where(y_train == i)[0] for i in range(10)]
    train_pairs, train_y = create_pairs(x_train, digit_indices)

    digit_indices = [np.where(y_test == i)[0] for i in range(10)]
    val_pairs, val_y = create_pairs(x_test, digit_indices)

    # network definition
    base_network = create_simplistic_base_network(input_dim)

    input_a = keras.layers.Input(shape=(input_dim, ))
    input_b = keras.layers.Input(shape=(input_dim, ))

    # because we re-use the same instance `base_network`,
    # the weights of the network
    # will be shared across the two branches
    processed_a = base_network(input_a)
    processed_b = base_network(input_b)

    # node to compute the distance between the two vectors
    # processed_a and processed_a
    distance = keras.layers.Lambda(euclidean_distance)(
        [processed_a, processed_b])

    # Our model take as input a pair of images input_a and input_b
    # and output the Euclidian distance of the mapped inputs
    model = keras.models.Model([input_a, input_b], distance)

    # train
    rms = keras.optimizers.RMSprop()
    model.compile(loss=contrastive_loss, optimizer=rms)
    model.fit([train_pairs[:, 0], train_pairs[:, 1]],
              train_y,
              validation_data=([val_pairs[:, 0], val_pairs[:, 1]], val_y))

    # compute final accuracy on training and test sets
    pred = model.predict([train_pairs[:, 0], train_pairs[:, 1]])
    tr_acc = compute_accuracy(pred, train_y)
    pred = model.predict([val_pairs[:, 0], val_pairs[:, 1]])
    te_acc = compute_accuracy(pred, val_y)

    print('* Accuracy on training set: %0.2f%%' % (100 * tr_acc))
    print('* Accuracy on test set: %0.2f%%' % (100 * te_acc))
    #dropout2
    seq.add(keras.layers.Dropout(dropout2_probability))
    return seq
#------------------------------------------------------------------------------
if __name__=='__main__':

    
    '''
    architecture_flag:1 for the initial architecture. 2 is for the second architecutre
    degree1:
    degree2: 0 
    strength1: 
    strength2: 
    percentage:
    '''
    x_original_train, train_target, x_original_test, val_target = assign2_utils.load_dataset()
    #train_pairs, val_pairs = transform_dataset(x_original_train, x_original_test, 30, 0.15)
    # 2. split the datset.
    x_original_train = x_original_train.astype('float32')
    x_original_test = x_original_test.astype('float32')
    
    normaliseValue = 255
    x_original_train /= normaliseValue # normalized the entries between 0 and 1
    x_original_test /= normaliseValue
    
    x_original_train1, x_original_train2, train_target1, train_target2  = split_Data(x_original_train,train_target, 0.4)
    #x_original_test1, x_original_test2 , val_target1, val_target2  = split_Data(x_original_test,val_target, percentage)

    # 3. transform the dataset.
    warped_pairs1 = np.array([assign2_utils.random_deform(x, 15, 0.1) for x in x_original_train1])
    warped_pairs2 = np.array([assign2_utils.random_deform(x, 45, 0.3) for x in x_original_train2])
示例#10
0
def stage_learning():
    """
    stage learning
    training the first 20% easy warped images first,
    then training the 80% hard warped images
    test all images 
    predict the accuracy
    """
    #expand x_train,y_train into a new x_train and y_train array with 100,000
    x_train, y_train, x_test, y_test = assign2_utils.load_dataset()

    a = x_train[0:40000, :, :]
    x_train = np.concatenate((a, x_train), axis=0)

    b = y_train[0:40000]
    y_train = np.concatenate((b, y_train), axis=0)

    img_row = x_train.shape[1]
    img_col = x_train.shape[2]

    # normalized the input image
    x_train = x_train.astype('float32')
    x_test = x_test.astype('float32')

    x_train /= 255
    x_test /= 255

    #reshape data
    x_train = x_train.reshape(x_train.shape[0], img_row, img_col, 1)
    x_test = x_test.reshape(x_test.shape[0], img_row, img_col, 1)

    input_dim = (img_row, img_col, 1)

    epochs = 10
    x_train_easy = x_train
    x_train_hard = x_train
    x_test_easy = x_test
    x_test_hard = x_test

    #warped images with with easy strength and easy degree
    for i in range(100000):
        x_train_easy[i] = assign2_utils.random_deform(x_train[i], 15, 0.1)
    for i in range(100000):
        x_train_hard[i] = assign2_utils.random_deform(x_train[i], 45, 0.3)

    #warped images with with hard strength and hard degree
    for i in range(10000):
        x_test_easy[i] = assign2_utils.random_deform(x_test[i], 15, 0.1)
    for i in range(10000):
        x_test_hard[i] = assign2_utils.random_deform(x_test[i], 45, 0.3)

    # create training+test positive and negative pairs
    digit_indices = [np.where(y_train == i)[0] for i in range(10)]
    tr_pairs_easy, tr_y_easy = create_pairs(x_train_easy, digit_indices)

    digit_indices = [np.where(y_train == i)[0] for i in range(10)]
    tr_pairs_hard, tr_y_hard = create_pairs(x_train_hard, digit_indices)

    digit_indices = [np.where(y_test == i)[0] for i in range(10)]
    te_pairs, te_y = create_pairs(x_test, digit_indices)

    # network definition
    base_network = create_simplistic_base_network(input_dim)

    input_a = keras.layers.Input(shape=input_dim)
    input_b = keras.layers.Input(shape=input_dim)

    # because we re-use the same instance `base_network`,
    # the weights of the network will be shared across the two branches
    processed_a = base_network(input_a)
    processed_b = base_network(input_b)

    # node to compute the distance between the two vectors
    # processed_a and processed_a
    distance = keras.layers.Lambda(euclidean_distance)(
        [processed_a, processed_b])

    # Our model take as input a pair of images input_a and input_b
    # and output the Euclidian distance of the mapped inputs

    #model to fit the first 20% easy warped images
    model = keras.models.Model([input_a, input_b], distance)
    rms = keras.optimizers.RMSprop()
    model.compile(loss=contrastive_loss, optimizer=rms)
    model.fit([tr_pairs_easy[0:36096, 0], tr_pairs_easy[0:36096, 1]],
              tr_y_easy[0:36096],
              batch_size=128,
              epochs=epochs,
              validation_data=([te_pairs[0:3564, 0],
                                te_pairs[0:3564, 1]], te_y[0:3564]))
    #model.save_weights("easy_warped.h5")

    #model to fit the last 80% hard warped images
    model2 = keras.models.Model([input_a, input_b], distance)
    rms = keras.optimizers.RMSprop()
    model2.compile(loss=contrastive_loss, optimizer=rms)

    #model2.load_weights("easy_warped.h5")

    model2.fit([tr_pairs_hard[36096:, 0], tr_pairs_hard[36096:, 1]],
               tr_y_hard[36096:],
               batch_size=128,
               epochs=epochs,
               validation_data=([te_pairs[3564:, 0],
                                 te_pairs[3564:, 1]], te_y[3564:]))

    #merge two tr_pairs dataset together
    tr_pairs = np.concatenate((tr_pairs_hard[36096:], tr_pairs_easy[0:36096]),
                              axis=0)
    tr_y = np.concatenate((tr_y_hard[36096:], tr_y_easy[0:36096]))

    pred = model.predict([tr_pairs[:, 0], tr_pairs[:, 1]])
    tr_acc = compute_accuracy(pred, tr_y)

    pred = model.predict([te_pairs[:, 0], te_pairs[:, 1]])
    te_acc = compute_accuracy(pred, te_y)

    print('when epochs is {}'.format(epochs))
    print('* Accuracy on training set: %0.2f%%' % (100 * tr_acc))
    print('* Accuracy on test set: %0.2f%% \n\n' % (100 * te_acc))
示例#11
0
def simplistic_solution(epochs, degree, strength):
    '''
    Train a Siamese network to predict whether two input images correspond to the 
    same digit.

    WARNING: 
        in your submission, you should use auxiliary functions to create the 
        Siamese network, to train it, and to compute its performance.

    '''
    # load dataset and expand 60,000 to 100,000

    x_train, y_train, x_test, y_test = assign2_utils.load_dataset()
    a = x_train[0:40000, :, :]

    x_train = np.concatenate((a, x_train), axis=0)

    b = y_train[0:40000]

    y_train = np.concatenate((b, y_train), axis=0)
    img_row = x_train.shape[1]

    img_col = x_train.shape[2]

    # normalized the input image

    x_train = x_train.astype('float32')
    x_test = x_test.astype('float32')

    x_train /= 255
    x_test /= 255

    def warped_images(x_train, x_test, degree, strength):
        """
        warped dataset with degree and strength.
        
        @param: expanded x_train,x_test.
                degree: warped degree
                strength: warped strength
        @return: warped x_train, x_test
        """
        print("This time is warped data with {} degree and {} strength".format(
            degree, strength))

        for i in range(len(x_train)):

            x_train[i] = assign2_utils.random_deform(x_train[i], degree,
                                                     strength)

        for i in range(len(x_test)):

            x_test[i] = assign2_utils.random_deform(x_test[i], degree,
                                                    strength)

        return x_train, x_test

#------------------------------------------------------------------------------

    combo_warped = False

    if combo_warped:

        x_train_easy, x_test_easy = warped_images(x_train[0:20000],
                                                  x_test[0:2000], 15, 0.1)
        x_train_hard, x_test_hard = warped_images(x_train[20000:],
                                                  x_test[2000:], 45, 0.3)

        x_train = np.concatenate((x_train_easy, x_train_hard), axis=0)
        x_test = np.concatenate((x_test_easy, x_test_hard), axis=0)

    else:
        x_train, x_test = warped_images(x_train, x_test, degree, strength)

    #reshape data
    if K.image_data_format() == 'channels_first':
        x_train = x_train.reshape(x_train.shape[0], 1, img_row, img_col)
        x_test = x_test.reshape(x_test.shape[0], 1, img_row, img_col)
        input_dim = (1, img_row, img_col)

    else:

        x_train = x_train.reshape(x_train.shape[0], img_row, img_col, 1)
        x_test = x_test.reshape(x_test.shape[0], img_row, img_col, 1)
        input_dim = (img_row, img_col, 1)

    epochs = epochs

    # create training+test positive and negative pairs
    digit_indices = [np.where(y_train == i)[0] for i in range(10)]
    tr_pairs, tr_y = create_pairs(x_train, digit_indices)

    digit_indices = [np.where(y_test == i)[0] for i in range(10)]
    te_pairs, te_y = create_pairs(x_test, digit_indices)
    #    print(len(te_y))
    #    print(len(te_pairs))

    # network definition
    base_network = create_simplistic_base_network(input_dim)

    input_a = keras.layers.Input(shape=input_dim)
    input_b = keras.layers.Input(shape=input_dim)

    # because we re-use the same instance `base_network`,
    # the weights of the network will be shared across the two branches

    processed_a = base_network(input_a)
    processed_b = base_network(input_b)

    # node to compute the distance between the two vectors
    # processed_a and processed_a
    distance = keras.layers.Lambda(euclidean_distance)(
        [processed_a, processed_b])

    # Our model take as input a pair of images input_a and input_b
    # and output the Euclidian distance of the mapped inputs

    model = keras.models.Model([input_a, input_b], distance)
    rms = keras.optimizers.RMSprop()
    model.compile(loss=contrastive_loss, optimizer=rms)

    model.fit([tr_pairs[:, 0], tr_pairs[:, 1]],
              tr_y,
              batch_size=128,
              epochs=epochs,
              validation_data=([te_pairs[:, 0], te_pairs[:, 1]], te_y))

    # compute final accuracy on training and test sets

    pred = model.predict([tr_pairs[:, 0], tr_pairs[:, 1]])
    tr_acc = compute_accuracy(pred, tr_y)

    pred = model.predict([te_pairs[:, 0], te_pairs[:, 1]])
    te_acc = compute_accuracy(pred, te_y)

    print('when epochs is {}'.format(epochs))
    print('* Accuracy on training set: %0.2f%%' % (100 * tr_acc))
    print('* Accuracy on test set: %0.2f%%' % (100 * te_acc))

    return tr_acc, te_acc