How to train Siamese network in Keras? - machine-learning

I have a pandas dataframe containing filenames of positive and negative examples as below
img1 img2 y
001.jpg 002.jpg 1
003.jpg 004.jpg 0
003.jpg 002.jpg 1
I want to train my Siamese network using Keras ImageDataGenerator and flow_from_dataframe. How do I set up my training so that the code inputs 2 images with 1 label simultaneously.
Below is the code for my model
def siamese_model(input_shape) :
left = Input(input_shape)
right = Input(input_shape)
model = Sequential()
model.add(Conv2D(32, (3,3), activation='relu', input_shape=input_shape))
model.add(BatchNormalization())
model.add(Conv2D(64, (3,3), activation='relu'))
model.add(BatchNormalization())
model.add(Conv2D(128, (3,3), activation='relu'))
model.add(BatchNormalization())
model.add(Conv2D(256, (3,3), activation='relu')
model.add(BatchNormalization())
model.add(Conv2D(256, (3,3), activation='relu')
model.add(MaxPooling2D())
model.add(BatchNormalization())
model.add(Flatten())
model.add(Dense(512, activation='sigmoid'))
left_encoded = model(left)
right_encoded = model(right)
L1_layer = Lambda(lambda tensors:K.abs(tensors[0] - tensors[1]))
L1_distance = L1_layer([left_encoded, right_encoded])
prediction = Dense(1,activation='sigmoid')(L1_distance)
siamese_net = Model(inputs=[left,right],outputs=prediction)
return siamese_net
model = siamese_model((224,224,3))
model.compile(loss="binary_crossentropy",optimizer="adam", metrics=['accuracy'])
datagen_left = ImageDataGenerator(rotation_range=10,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
vertical_flip = True)
datagen_right = ImageDataGenerator(rotation_range=10,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
vertical_flip = True)

Join the generators in a custom generator.
Make one of them output the desired labels, discard the label of the other.
class DoubleGenerator(Sequence):
def __init__(self, gen1, gen2):
self.gen1 = gen1
self.gen2 = gen2
def __len__(self):
return len(self.gen1)
def __getitem__(self, i):
x1,y = self.gen1[i]
x2,y2 = self.gen2[i]
return (x1,x2), y
Use it:
double_gen = DoubleGenerator(datagen_left.flow_from_directory(...),
datagen_right.flow_from_directory(...))

Related

Why is my loss so high and accuracy stays at 0.1?

I am new to deep learning and neural network so I need help understanding why this is happening and how i can fix it.
I have a training size of 7500 images
This is my model
img_size = 50
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu',
input_shape=(img_size, img_size, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Flatten())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.summary()
model.compile(loss='binary_crossentropy',
optimizer=optimizers.RMSprop(learning_rate=2*1e-4),
metrics=['acc'])
# Date processing
# All images will be rescaled by 1./255
train_datagen = ImageDataGenerator(
rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,)
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
# This is the target directory
train_dir,
target_size=(img_size, img_size),
batch_size=20,
class_mode='binary')
validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(img_size, img_size),
batch_size=20,
class_mode='binary')
# Train the Model
history = model.fit(
train_generator,
steps_per_epoch=375, #train_sample_size/data_batch_size
epochs=100,
validation_data=validation_generator,
validation_steps=50)
I have tried changing the parameters, such as adding dropout, changing batch size etc.. but still get a really high loss. The loss would be in the negative 20million and just keep increases.

Input 0 of layer conv1d_2 is incompatible with the layer: : expected min_ndim=3, found ndim=2. Full shape received: (None, 128). To develop LSTM-CNN

I am trying to incorporate a CNN layer into the LSTM network as shown.
model = Sequential()
model.add(LSTM(64, return_sequences = True, input_shape=(X_train.shape[1], X_train.shape[2]),activation='relu'))
model.add(Dropout(0.1)) model.add(LSTM(128, activation= 'relu'))
model.add(Conv1D(32, kernel_size=3, activation='relu'))
model.add(Flatten()) model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
But it is giving the following error about the input shape. Please help to resolve the issue.
Try this:
model = Sequential()
model.add(LSTM(64, return_sequences = True, input_shape = (X_train.shape[1], X_train.shape[2]), activation='relu'))
model.add(Dropout(0.1))
model.add(LSTM(128, activation = 'relu', return_sequences = True))
model.add(Conv1D(32, kernel_size= 1, input_shape = (None, 128, 1), activation = 'relu'))
model.add(Flatten())
model.add(Dense(1))

Convolutional Autoencoders

I am writing a code for running autoencoder on CIFAR10 dataset and see the reconstructed images.
The requirement is to create
Encoder with First Layer
Input shape: (32,32,3)
Conv2D Layer with 64 Filters of (3,3)
BatchNormalization layer
ReLu activation
2D MaxpoolingLayer with (2,2) filter
Encoder with Second Layer
Conv2D layer with 16 filters (3,3)
BatchNormalization layer
ReLu activation
2D MaxpoolingLayer with (2,2) filter
Final Encoded as MaxPool with (2,2) with all previous layers
Decoder with First Layer
Input shape: encoder output
Conv2D Layer with 16 Filters of (3,3)
BatchNormalization layer
ReLu activation
UpSampling2D with (2,2) filter
Decoder with Second Layer
Conv2D Layer with 32 Filters of (3,3)
BatchNormalization layer
ReLu activation
UpSampling2D with (2,2) filter
Final Decoded as Sigmoid with all previous layers
I understand that
When we are creating Convolutional Autoencoder (or any AE), we need to pass the output of the previous layer to the next layer.
So, when I create the first Conv2D layer with ReLu and then perform BatchNormalization .. in which I pass the Conv2D layer .. right?
But when I do MaxPooling2D .. what should I pass .. BatchNormalization output or Conv2D layer output?
Also, is there any order in which I should be performing these operations?
Conv2D --> BatchNormalization --> MaxPooling2D
OR
Conv2D --> MaxPooling2D --> BatchNormalization
I am attaching my code below ... I have attempted it to two different ways and hence getting different outputs (in terms of model summary and also model training graph)
Can someone please help me by explaining which is the correct method (Method-1 or Method-2)? Also, how do I understand which graph shows better model performance?
Method - 1
input_image = Input(shape=(32, 32, 3))
### Encoder
conv1_1 = Conv2D(64, (3, 3), activation='relu', padding='same')(input_image)
bnorm1_1 = BatchNormalization()(conv1_1)
mpool1_1 = MaxPooling2D((2, 2), padding='same')(conv1_1)
conv1_2 = Conv2D(16, (3, 3), activation='relu', padding='same')(mpool1_1)
borm1_2 = BatchNormalization()(conv1_2)
encoder = MaxPooling2D((2, 2), padding='same')(conv1_2)
### Decoder
conv2_1 = Conv2D(16, (3, 3), activation='relu', padding='same')(encoder)
bnorm2_1 = BatchNormalization()(conv2_1)
up1_1 = UpSampling2D((2, 2))(conv2_1)
conv2_2 = Conv2D(32, (3, 3), activation='relu', padding='same')(up1_1)
bnorm2_2 = BatchNormalization()(conv2_2)
up2_1 = UpSampling2D((2, 2))(conv2_2)
decoder = Conv2D(3, (3, 3), activation='sigmoid', padding='same')(up2_1)
model = Model(input_image, decoder)
model.compile(optimizer='adam', loss='binary_crossentropy')
model.summary()
history = model.fit(trainX, trainX,
epochs=50,
batch_size=1000,
shuffle=True,
verbose=2,
validation_data=(testX, testX)
)
As an output of the model summary, I get this
Total params: 18,851
Trainable params: 18,851
Non-trainable params: 0
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper right')
plt.show()
Method - 2
input_image = Input(shape=(32, 32, 3))
### Encoder
x = Conv2D(64, (3, 3), activation='relu', padding='same')(input_image)
x = BatchNormalization()(x)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Conv2D(16, (3, 3), activation='relu', padding='same')(x)
x = BatchNormalization()(x)
encoder = MaxPooling2D((2, 2), padding='same')(x)
### Decoder
x = Conv2D(16, (3, 3), activation='relu', padding='same')(encoder)
x = BatchNormalization()(x)
x = UpSampling2D((2, 2))(x)
x = Conv2D(32, (3, 3), activation='relu', padding='same')(x)
x = BatchNormalization()(x)
x = UpSampling2D((2, 2))(x)
decoder = Conv2D(3, (3, 3), activation='sigmoid', padding='same')(x)
model = Model(input_image, decoder)
model.compile(optimizer='adam', loss='binary_crossentropy')
model.summary()
history = model.fit(trainX, trainX,
epochs=50,
batch_size=1000,
shuffle=True,
verbose=2,
validation_data=(testX, testX)
)
As an output of the model summary, I get this
Total params: 19,363
Trainable params: 19,107
Non-trainable params: 256
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper right')
plt.show()
In method 1, BatchNormalization layers does not exist in the compiled model, as the output of these layers are not used anywhere. You can check this by running model1.summary()
Method 2 is perfectly alright.
Order of the operations :
Conv2D --> BatchNormalization --> MaxPooling2D is usually the common approach.
Though either order would work since, since BatchNorm is just mean and variance normalization.
Edit:
For Conv2D --> BatchNormalization --> MaxPooling2D :
conv1_1 = Conv2D(64, (3, 3), activation='relu', padding='same')(input_image)
bnorm1_1 = BatchNormalization()(conv1_1)
mpool1_1 = MaxPooling2D((2, 2), padding='same')(bnorm1_1)
and then use mpool1_1 as input for next layer.
For Conv2D --> MaxPooling2D --> BatchNormalization:
conv1_1 = Conv2D(64, (3, 3), activation='relu', padding='same')(input_image)
mpool1_1 = MaxPooling2D((2, 2), padding='same')(conv1_1)
bnorm1_1 = BatchNormalization()(mpool1_1)
and then use bnorm1_1 as input for next layer.
To effectively use BatchNormalization layer, you should always use it before activation.
Instead of:
conv1_1 = Conv2D(64, (3, 3), activation='relu', padding='same')(input_image)
bnorm1_1 = BatchNormalization()(conv1_1)
mpool1_1 = MaxPooling2D((2, 2), padding='same')(bnorm1_1)
Use it like this:
conv1_1 = Conv2D(64, (3, 3), padding='same')(input_image)
bnorm1_1 = BatchNormalization()(conv1_1)
act_1 = Activation('relu')(bnorm1_1)
mpool1_1 = MaxPooling2D((2, 2), padding='same')(act_1)
For more details, check here:
Where do I call the BatchNormalization function in Keras?

Train deep classification model with different color features

I have a simple sequential deep model as below, which performs a binary classification. I pass the 3 color channels of my dataset images to the model for training. How can I add grayscale as the 4th channel to my model? What changes do I need to make?
from keras.models import Sequential, load_model, Model
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D
from keras.layers.normalization import BatchNormalization
from PIL import Image
from random import shuffle, choice
import numpy as np
import os
from keras.callbacks import ModelCheckpoint
from keras.preprocessing.image import ImageDataGenerator
from sklearn.model_selection import train_test_split
from keras import optimizers
IMAGE_SIZE = 300
epochs_num = 100
batch_size = 64
IMAGE_DIRECTORY = './data'
def label_img(name):
if name == 'fire': return np.array([1, 0])
elif name == 'none' : return np.array([0, 1])
def load_data():
print("Loading images...")
train_data = []
directories = next(os.walk(IMAGE_DIRECTORY))[1]
for dirname in directories:
print("Loading {0}".format(dirname))
file_names = next(os.walk(os.path.join(IMAGE_DIRECTORY, dirname)))[2]
for i in range(len(file_names)):
image_name = choice(file_names)
image_path = os.path.join(IMAGE_DIRECTORY, dirname, image_name)
label = label_img(dirname)
if "DS_Store" not in image_path:
img = Image.open(image_path)
img = img.resize((IMAGE_SIZE, IMAGE_SIZE), Image.ANTIALIAS)
train_data.append([np.array(img), label])
shuffle(train_data)
return train_data
def create_model():
model = Sequential()
model.add(Conv2D(32, kernel_size = (5, 5), activation='relu', input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3)))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(BatchNormalization())
model.add(Conv2D(64, kernel_size=(3,3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(BatchNormalization())
model.add(Conv2D(128, kernel_size=(3,3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(BatchNormalization())
model.add(Conv2D(64, kernel_size=(3,3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(BatchNormalization())
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(128, activation='relu'))
model.add(Dense(2, activation = 'softmax'))
return model
training_data = load_data()
training_images = np.array([i[0] for i in training_data])
training_labels = np.array([i[1] for i in training_data])
print(str(len(training_images)))
# Split the data
training_images, validation_images, training_labels, validation_labels = train_test_split(training_images, training_labels, test_size=0.2, shuffle= True)
print(str(len(training_images)))
print('creating model')
#========================
model = create_model()
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
filepath="./checkpoints/model_{epoch:03d}_{accuracy:.4f}_{val_accuracy:.4f}_{val_loss:.7f}.h5"
checkpoint = ModelCheckpoint(filepath, monitor=["accuracy"], verbose=1, mode='max', save_weights_only=False)
callbacks_list = [checkpoint]
datagen = ImageDataGenerator(zoom_range=0.2, horizontal_flip=True)
datagen.fit(training_images)
train_gen=datagen.flow(training_images, training_labels, batch_size=batch_size)
#validation
val_datagen = ImageDataGenerator(horizontal_flip=True)
val_datagen.fit(training_images)
val_gen=datagen.flow(validation_images, validation_labels, batch_size=batch_size)
model.fit(train_gen, validation_data=val_gen, epochs=epochs_num, verbose=1, callbacks=callbacks_list)
i dont't think that you need to add gray scale and i 'm not sure if you can "add" it as an extra channel. Gray scale image is an image that RGB values are the same on the same pixel. You can train your classifier to classify gray scale images or coloured ones or both (not recommended). But if your raw data is coloured images keep them as they are and use data augmentation if you need more.

CNN not efficient on my dataset in Keras

I'm working on a classification of one dimensional data. I presented the data in the form of 549 arrays, each contains 600 samples. I've made a multi-layer perceptron, which showed an efficiency of about 80%. Now I'm trying to do CNN but for some reason it's accuracy doesn't exceed 31%. What can be wrong?
My model:
model = Sequential()
model.add(Conv1D(filters=20, kernel_size=4,activation='relu',padding='same',input_shape=(600,1)))
model.add(MaxPooling1D(pool_size = 2))
model.add(Dropout(0.3))
model.add(Flatten())
model.add(Dense(50, activation='relu', input_dim = 600))
model.add(Dense(1, activation='softmax'))
model.compile(loss="binary_crossentropy", optimizer="nadam", metrics=['accuracy'])
model.fit(np.array(X), np.array(Y), epochs = 100, batch_size=8, verbose=1, validation_data=(np.array(X1),np.array(Y1)))
scores = model.evaluate(np.array(X1), np.array(Y1), verbose=0)
Input data:
X1 = X[:90]
X = X[91:]
Y1 = Y[:90]
Y = Y[91:]
X = np.expand_dims(X, axis=2)
X1 =np.expand_dims(X1, axis=2)
print(np.array(X).shape)
Get the dimension (458, 600, 1) can there be something wrong with the dimensions?
change
model.add(Dense(1, activation='softmax'))
to
model.add(Dense(1, activation='sigmoid'))

Resources