How to have parallel convolutional layers in keras? - neural-network

I am a little new to neural networks and keras. I have some images with size 6*7 and the size of the filter is 15. I want to have several filters and train a convolutional layer separately on each and then combine them. I have looked at one example here:
model = Sequential()
model.add(Convolution2D(nb_filters, kernel_size[0], kernel_size[1],
border_mode='valid',
input_shape=input_shape))
model.add(Activation('relu'))
model.add(Convolution2D(nb_filters, kernel_size[0], kernel_size[1]))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=pool_size))
model.add(Dropout(0.25))
model.add(Flatten(input_shape=input_shape))
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(nb_classes))
model.add(Activation('tanh'))
This model works with one filter. Can anybody give me some hints on how to modify the model to work with parallel convolutional layers.
Thanks

Here is an example of designing a network of parallel convolution and sub sampling layers in keras version 2. I hope this resolves your problem.
rows, cols = 100, 15
def create_convnet(img_path='network_image.png'):
input_shape = Input(shape=(rows, cols, 1))
tower_1 = Conv2D(20, (100, 5), padding='same', activation='relu')(input_shape)
tower_1 = MaxPooling2D((1, 11), strides=(1, 1), padding='same')(tower_1)
tower_2 = Conv2D(20, (100, 7), padding='same', activation='relu')(input_shape)
tower_2 = MaxPooling2D((1, 9), strides=(1, 1), padding='same')(tower_2)
tower_3 = Conv2D(20, (100, 10), padding='same', activation='relu')(input_shape)
tower_3 = MaxPooling2D((1, 6), strides=(1, 1), padding='same')(tower_3)
merged = keras.layers.concatenate([tower_1, tower_2, tower_3], axis=1)
merged = Flatten()(merged)
out = Dense(200, activation='relu')(merged)
out = Dense(num_classes, activation='softmax')(out)
model = Model(input_shape, out)
plot_model(model, to_file=img_path)
return model
The image of this network will look like

My approach is to create other model that defines all parallel convolution and pulling operations and concat all parallel result tensors to single output tensor. Now you can add this parallel model graph in your sequential model just like layer. Here is my solution, hope it solves your problem.
# variable initialization
from keras import Input, Model, Sequential
from keras.layers import Conv2D, MaxPooling2D, Concatenate, Activation, Dropout, Flatten, Dense
nb_filters =100
kernel_size= {}
kernel_size[0]= [3,3]
kernel_size[1]= [4,4]
kernel_size[2]= [5,5]
input_shape=(32, 32, 3)
pool_size = (2,2)
nb_classes =2
no_parallel_filters = 3
# create seperate model graph for parallel processing with different filter sizes
# apply 'same' padding so that ll produce o/p tensor of same size for concatination
# cancat all paralle output
inp = Input(shape=input_shape)
convs = []
for k_no in range(len(kernel_size)):
conv = Conv2D(nb_filters, kernel_size[k_no][0], kernel_size[k_no][1],
border_mode='same',
activation='relu',
input_shape=input_shape)(inp)
pool = MaxPooling2D(pool_size=pool_size)(conv)
convs.append(pool)
if len(kernel_size) > 1:
out = Concatenate()(convs)
else:
out = convs[0]
conv_model = Model(input=inp, output=out)
# add created model grapg in sequential model
model = Sequential()
model.add(conv_model) # add model just like layer
model.add(Conv2D(nb_filters, kernel_size[1][0], kernel_size[1][0]))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=pool_size))
model.add(Dropout(0.25))
model.add(Flatten(input_shape=input_shape))
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(nb_classes))
model.add(Activation('tanh'))
For more information refer similar question: Combining the outputs of multiple models into one model

Related

Keras target shape is incorrect

I am relatively new to keras so i played around with a simple seq2seq architecture.
model = Sequential()
model.add(Embedding(22, 10, input_length=32, mask_zero=True))
model.add(LSTM(4, return_sequences = True))
model.add(TimeDistributed(Dense(output_dim=3)))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
model.fit(x,y,nb_epoch =1, batch_size = 1, verbose = 2)
Exception: Error when checking model target: expected activation_6 to have shape (None, 32, 3) but got array with shape (2, 4, 3)
x has shape of (2,32) and y has shape of (2,4,3).
According to my understanding, it means that y has 2 examples with each sequence have a length of 4 and one hot-encoded into 3 dimension. However, when i ran model.fit it seems its not the shape that i am expecting. Why is this so?

CNN binary classifier performing poorly

I'm building a neural network to classify images that have an email address written on them. The positive folder contains images with email addresses written on top of the picture, in different fonts, colors, sizes and positions.
The negative folder contains images without text on top and also images with text on top that doesn't have the format of an email address (no # sign).
The pictures are 300 x 225 x 3 (rgb).
It should be a simple a simple classification task (the NN should be able to pick up that when there's an #, the image has an email) but my model isn't performing well. It's stuck at 83% test accuracy after 25 epochs. Also, it's taking 10 hours to train, which sounds excessive to me.
Can you help me to analyse the structure of my CNN and suggest improvements (or help me avoid pitfalls)?
The model I wrote is this:
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense
from keras.preprocessing.image import ImageDataGenerator
input_size = (64, 48)
# Initialising the CNN
classifier = Sequential()
# Step 1 - Convolution
classifier.add(Conv2D(32, (3, 3), input_shape = (*input_size, 3), activation = 'relu'))
# Step 2 - Pooling
classifier.add(MaxPooling2D(pool_size = (2, 2)))
# Adding a second convolutional layer
classifier.add(Conv2D(32, (3, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))
# Step 3 - Flattening
classifier.add(Flatten())
# Step 4 - Full connection
classifier.add(Dense(units = 128, activation = 'relu'))
classifier.add(Dense(units = 1, activation = 'sigmoid'))
# Compiling the CNN
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
# Part 2 - Fitting the CNN to the images
train_datagen = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = True)
test_datagen = ImageDataGenerator(rescale = 1./255)
training_set = train_datagen.flow_from_directory('./training_Set',
target_size = input_size,
batch_size = 32,
class_mode = 'binary')
test_set = test_datagen.flow_from_directory('./test_set',
target_size = input_size,
batch_size = 32,
class_mode = 'binary')
classifier.fit_generator(training_set,
steps_per_epoch = 8000,
epochs = 25,
validation_data = test_set,
validation_steps = 2000)

Combining the outputs of multiple models into one model

I am currently looking for a way i can combine the output of multiple model into one model, I need to create a CNN network that does classification.
The image is separated into sections (as seen by the colors), each section is given as input to a certain model (1,2,3,4) the structure of each model is the same, but each section is given to a separate model to ensure that the the same weight is not applied on whole image - My attempt to avoid full weight sharing, and keeping the weight sharing local. Each model then perform convolution and max pooling, and generate some sort of output that has to fed into a dense layer that takes the outputs from the prior models (model 1,2,3,4,) and performs classifications.
My question here is it possible to create model 1,2,3,4 and connect it to the fully connected layer and train all the models given the input sections and and the output class - without having to define the outputs of the convolution and pooling layer in keras?
Yes, you can create such models using Multi-input and multi-output models, refer keras documentation for more details. Here I am sharing code sample, hope this helps
import numpy as np
import keras
from keras.optimizers import SGD
from keras.models import Sequential, Model
from keras.layers import Activation, Dense, Dropout, Flatten, Input, Merge, Convolution2D, MaxPooling2D
# Generate dummy data
train1 = np.random.random((100, 100, 100, 3))
train2 = np.random.random((100, 100, 100, 3))
train3 = np.random.random((100, 100, 100, 3))
train4 = np.random.random((100, 100, 100, 3))
y_train = keras.utils.to_categorical(np.random.randint(10, size=(100, 1)), num_classes=10)
#parallel ip for different sections of image
inp1 = Input(shape=train1.shape[1:])
inp2 = Input(shape=train2.shape[1:])
inp3 = Input(shape=train3.shape[1:])
inp4 = Input(shape=train4.shape[1:])
# paralle conv and pool layer which process each section of input independently
conv1 = Conv2D(64, (3, 3), activation='relu')(inp1)
conv2 = Conv2D(64, (3, 3), activation='relu')(inp2)
conv3 = Conv2D(64, (3, 3), activation='relu')(inp3)
conv4 = Conv2D(64, (3, 3), activation='relu')(inp4)
maxp1 = MaxPooling2D((3, 3))(conv1)
maxp2 =MaxPooling2D((3, 3))(conv2)
maxp3 =MaxPooling2D((3, 3))(conv3)
maxp4 =MaxPooling2D((3, 3))(conv4)
# can add multiple parallel conv, pool layes to reduce size
flt1 = Flatten()(maxp1)
flt2 = Flatten()(maxp2)
flt3 = Flatten()(maxp3)
flt4 = Flatten()(maxp4)
mrg = Merge(mode='concat')([flt1,flt2,flt3,flt4])
dense = Dense(256, activation='relu')(mrg)
op = Dense(10, activation='softmax')(dense)
model = Model(input=[inp1, inp2, inp3, inp4], output=op)
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit([train1,train2,train3,train4], y_train,
nb_epoch=10, batch_size=28)

Keras : How to merge a dense layer and an embedding layer

I use Keras and I try to concatenate two different layers into a vector (first values of the vector would be values of the first layer, and the other part would be the values of the second layer).
One of these layers is a Dense layer and the other layer is a Embedding layer.
I know how to merge two embedding layers or two dense layers but I don't know how to merge a embedding layer and a dense layer (dimensional problem).
A simple example would be like this:
L_branch = Sequential()
L_branch.add(Dense(10, input_shape = (4,) , activation = 'relu'))
L_branch.add(BatchNormalization())
R_branch = Sequential()
R_branch.add(Embedding(1000, 64, input_length=5))
final_branch.add(Merge([L_branch, R_branch], mode = 'concat'))
But this will not work because you can't merge layers with different dimensionalities.
PS : Sorry, english is not my native languague and I hope you will understand my problem.
Best regards.
Use Flatten layer.
L_branch = Sequential()
L_branch.add(Dense(10, input_shape = (4,) , activation = 'relu'))
L_branch.add(BatchNormalization())
R_branch = Sequential()
R_branch.add(Embedding(1000, 64, input_length=5))
R_branch.add(Flatten()) # <--
final_branch = Sequential() # <--
final_branch.add(Merge([L_branch, R_branch], mode = 'concat'))

Keras model classifying well but predicted probabilities are always 1.0 or 0.0

I am using Keras to build a multi-class (3 classes) image classifier.
I trained the following model with a dataset of approximately 2000 images (1500 training/ 500 validation).
batch_size = 128
nb_classes = 3
nb_epoch = 25
img_rows, img_cols = 128, 128
input_shape = (1, img_rows, img_cols)
Y_train = np_utils.to_categorical(y_train, nb_classes)
Y_test = np_utils.to_categorical(y_test, nb_classes)
model = Sequential()
model.add(Convolution2D(32, 5, 5, border_mode='same', input_shape=input_shape))
model.add(Activation('relu'))
model.add(Convolution2D(64, 5, 5, border_mode='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.25))
model.add(Dense(nb_classes, activation='softmax'))
lrate = 0.001
decay = lrate/nb_epoch
sgd = SGD(lr=lrate, momentum=0.9, decay=decay, nesterov=False)
model.compile(loss='categorical_crossentropy',
optimizer=sgd,
metrics=['accuracy'])
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_test /= 255
history = model.fit(X_train, Y_train,
batch_size=batch_size,
nb_epoch=nb_epoch,
validation_data=(X_test, Y_test),
shuffle=True,
callbacks=early_stopping)
These are the figures for the training/validation accuracy and loss.
I achieve a 95% training accuracy, 92% validation accuracy and 94% on another separate chunk of images (aside from the 2000 of the dataset) that I have.
Therefore, the model seems to classify reasonably well. However, my problem is that the predicted probabilities for an input image (obtained with the function predict_proba()) are always either 1.0 or 0.0.
Likewise, if I give as an input an image that doesn't belong to any of the 3 classes I would expect some low probabilities (perhaps higher in the most similar class) but I still get 1.0 in one of the classes and 0.0 in the others.
What could be causing that? It seems to me that there is no over fitting. Is there any issue with the model?
Could it be that the images of each class are quite similar between them so somehow the model is quickly too confident on its decision?