<jupyter_start><jupyter_text>Siamese Network with CNNIn this little experiment, we are going to create an "Y model" based on MNIST model. The "Y model" has two inputs and one outputs. The Y-Network uses the same input twice, both on the left and right CNN branches. The network combines the results using concatenate layer. The merge operation concatenate is similar to stacking two tensors of the same shape along the concatenation axis to form one tensor.  import libraries<jupyter_code>import numpy as np
from keras.layers import Dense, Dropout, Input
from keras.layers import Conv2D, MaxPooling2D, Flatten
from keras.models import Model
from keras.layers.merge import concatenate
from keras.datasets import mnist
import matplotlib.pyplot as plt<jupyter_output><empty_output><jupyter_text>load data<jupyter_code>(x_train,y_train), (x_test,y_test) = mnist.load_data()<jupyter_output><empty_output><jupyter_text>compute the number of labels<jupyter_code>num_labels = len(np.unique(y_train))<jupyter_output><empty_output><jupyter_text>mnist example<jupyter_code>indexes = np.random.randint(0,x_train.shape[0], size=25)
images = x_train[indexes]
labels = y_train[indexes]

plt.figure(figsize=(5,5))
for i in range(len(indexes)):
    plt.subplot(5,5,i+1)
    image = images[i]
    plt.imshow(image,cmap='gray')
    plt.axis('off')

plt.show()
plt.close('all')<jupyter_output><empty_output><jupyter_text>reshape and normalize the data<jupyter_code>image_size = x_train.shape[1]
x_train = np.reshape(x_train,[-1,image_size,image_size,1])
x_test = np.reshape(x_test,[-1,image_size,image_size,1])
x_train = x_train.astype('float32')/255
x_test = x_test.astype('float32')/255<jupyter_output><empty_output><jupyter_text>network parameters<jupyter_code>input_shape = (image_size,image_size,1)
batch_size = 32
kernel_size = 3
dropout = 0.4
n_filters = 32<jupyter_output><empty_output><jupyter_text>left branch of Y network<jupyter_code>left_inputs = Input(shape=input_shape)
x = left_inputs
filters = n_filters<jupyter_output><empty_output><jupyter_text>3 layers of Conv2D-Dropout-MaxPooling2D number of filters doubles after each layer (32-64-128)<jupyter_code>for i in range(3):
    x = Conv2D(filters=filters,
               kernel_size=kernel_size,
               padding='same',
               activation='relu')(x)
    x = Dropout(dropout)(x)
    x = MaxPooling2D()(x)
    filters *= 2<jupyter_output><empty_output><jupyter_text>right branch of Y network<jupyter_code>right_inputs = Input(shape=input_shape)
y = right_inputs
filters = n_filters<jupyter_output><empty_output><jupyter_text>3 layers of Conv2D-Dropout-MaxPooling2D number of filters doubles after each layer (32-64-128)<jupyter_code>for i in range(3):
    y = Conv2D(filters=filters,
               kernel_size=kernel_size,
               padding='same',
               activation='relu',
               dilation_rate=2)(y)
    y = Dropout(dropout)(y)
    y = MaxPooling2D()(y)
    filters *= 2<jupyter_output><empty_output><jupyter_text>merge left and right branches outputs<jupyter_code>y = concatenate([x,y])<jupyter_output><empty_output><jupyter_text>feature maps to vector before connecting to dense layer<jupyter_code>y = Flatten()(y)
y = Dropout(dropout)(y)
outputs = Dense(num_labels,activation='softmax')(y)<jupyter_output><empty_output><jupyter_text>build the model in functional API<jupyter_code>model = Model([left_inputs,right_inputs],outputs)<jupyter_output><empty_output><jupyter_text>verify the model<jupyter_code>model.summary()<jupyter_output>Model: "model_2"
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_3 (InputLayer)            (None, 28, 28, 1)    0                                            
__________________________________________________________________________________________________
input_4 (InputLayer)            (None, 28, 28, 1)    0                                            
__________________________________________________________________________________________________
conv2d_7 (Conv2D)               (None, 28, 28, 32)   320         input_3[0][0]                    
__________________________________________________________________________________________________
conv2d_10 (Conv2D)              (None, 28, 28, 32)   320         input_4[0][0]              [...]<jupyter_text>compile and train  the model<jupyter_code>model.compile(loss='sparse_categorical_crossentropy',
              optimizer='adamax',
              metrics=['accuracy'])

model.fit([x_train,x_train],
          y_train, validation_data=([x_test,x_test],y_test),
          epochs=20,
          batch_size=batch_size)<jupyter_output>Train on 60000 samples, validate on 10000 samples
Epoch 1/20
60000/60000 [==============================] - 123s 2ms/step - loss: 0.1910 - accuracy: 0.9406 - val_loss: 0.1945 - val_accuracy: 0.9836
Epoch 2/20
60000/60000 [==============================] - 131s 2ms/step - loss: 0.0719 - accuracy: 0.9784 - val_loss: 0.1506 - val_accuracy: 0.9888
Epoch 3/20
60000/60000 [==============================] - 138s 2ms/step - loss: 0.0524 - accuracy: 0.9836 - val_loss: 0.1057 - val_accuracy: 0.9907
Epoch 4/20
60000/60000 [==============================] - 127s 2ms/step - loss: 0.0427 - accuracy: 0.9865 - val_loss: 0.0813 - val_accuracy: 0.9923
Epoch 5/20
60000/60000 [==============================] - 129s 2ms/step - loss: 0.0380 - accuracy: 0.9881 - val_loss: 0.0728 - val_accuracy: 0.9918
Epoch 6/20
60000/60000 [==============================] - 128s 2ms/step - loss: 0.0351 - accuracy: 0.9893 - val_loss: 0.0828 - val_accuracy: 0.9932
Epoch 7/20
60000/60000 [==============================] - 131s[...]<jupyter_text>model accuracy on test dataset<jupyter_code>score = model.evaluate([x_test,x_test],y_test,batch_size=batch_size)
print("\nTEST ACCURACY: %.1f%%" % (100*score[1]))<jupyter_output>10000/10000 [==============================] - 5s 527us/step

TEST ACCURACY: 99.5%
{'fraction_non_alphanumeric': 0.15755208333333334, 'fraction_numerical': 0.06201171875, 'mean_word_length': 4.658379373848987, 'pattern_counts': {'":': 0, '<': 62, '<?xml version=': 0, '>': 62, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '16', 'dir': 'jupyter-structured-clean-dedup', 'id': '306100', 'license': 'MIT', 'n_tokens_mistral': 2247, 'n_tokens_neox': 1961, 'n_words': 405, 'path': 'Artificial_Neural_Network/Siamese_Network/Siamese_CNN.ipynb', 'repo_name': 'AndryRafam/DEEP-LEARNING-Python3', 'size': '6144'}