I'm new to Keras. With transfer learning following an online tutorial, I tried to train a model for my custom dataset and below is my code. Now how should I perform classification given an image?
Here is the training code:
def build_finetune_model(base_model, dropout, fc_layers, num_classes):
for layer in base_model.layers:
layer.trainable = False
x = base_model.output
x = Flatten()(x)
for fc in fc_layers:
# New FC layer, random init
x = Dense(fc, activation='relu')(x)
x = Dropout(dropout)(x)
# New softmax layer
predictions = Dense(num_classes, activation='softmax')(x)
finetune_model = Model(inputs=base_model.input, outputs=predictions)
return finetune_model
train_datagen = ImageDataGenerator(preprocessing_function=preprocess_input)
train_generator = train_datagen.flow_from_directory(TRAIN_DIR,
target_size=(HEIGHT, WIDTH),
batch_size=BATCH_SIZE)
base_model = MobileNetV2(weights='imagenet', include_top=False, input_shape=(HEIGHT, WIDTH, 3))
root=TRAIN_DIR
class_list = [ item for item in os.listdir(root) if os.path.isdir(os.path.join(root, item)) ]
print (class_list)
FC_LAYERS = [1024, 1024]
dropout = 0.5
finetune_model = build_finetune_model(base_model, dropout=dropout, fc_layers=FC_LAYERS, num_classes=len(class_list))
adam = Adam(lr=0.00001)
finetune_model.compile(adam, loss='categorical_crossentropy', metrics=['accuracy'])
filepath="./checkpoints/" + "MobileNetV2_{epoch:02d}_{acc:.2f}" +"_model_weights.h5"
checkpoint = ModelCheckpoint(filepath, monitor=["acc"], verbose=1, mode='max', save_weights_only=True)
callbacks_list = [checkpoint]
history = finetune_model.fit_generator(train_generator, epochs=NUM_EPOCHS, workers=8,
steps_per_epoch=steps_per_epoch,
shuffle=True, callbacks=callbacks_list)
And here is my classify code, which only returns an array of float numbers!
if __name__ == '__main__':
model = load_model('ResNet50_model_weights.h5')
img_path = 'test.jpg'
img = image.load_img(img_path, target_size=(300, 300))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
print('Input image shape:', x.shape)
results = model.predict(x)
print('Predicted:', results)
Your models' last layer is softmax, which means that it outputs probabilities for each class between 0 and 1. In order to tell which class the input image is predicted to be, take the argmax of results. argmax returns the index of the maximum element in the array.
predicted_class_label = np.argmax(results)
print("network predicted input image is class {}".format(predicted_class_label))
Related
I'm trying to implement a Fully Convolutional Neural Network and can successfully test the accuracy of the model on the test set after training. However, I'd like to use the model to make a prediction on a single sample only. Training was in batches. I believe what I'm missing is related to batch size and input shape. Here is the configuration for the network:
def read(file_name):
data = np.loadtxt(file_name, delimiter="\t")
y = data[:, 0]
x = data[:, 1:]
return x, y.astype(int)
train_data, train_labels = read("FordA_TRAIN.tsv")
test_data, test_labels = read("FordA_TEST.tsv")
train_data = train_data.reshape((train_data.shape[0], train_data.shape[1], 1))
test_data = test_data.reshape((test_data.shape[0], test_data.shape[1], 1))
num_classes = len(np.unique(train_labels))
#print(train_data[0])
# Shuffle the data to prepare for validation_split (and prevent overfitting for class order)
idx = np.random.permutation(len(train_data))
train_data = train_data[idx]
train_labels = train_labels[idx]
#Standardize labels to have a value between 0 and 1 rather than -1 and 1.
train_labels[train_labels == -1] = 0
test_labels[test_labels == -1] = 0
def make_model(input_shape):
input_layer = keras.layers.Input(input_shape)
conv1 = keras.layers.Conv1D(filters=64, kernel_size=3, padding="same")(input_layer)
conv1 = keras.layers.BatchNormalization()(conv1)
conv1 = keras.layers.ReLU()(conv1)
conv2 = keras.layers.Conv1D(filters=64, kernel_size=3, padding="same")(conv1)
conv2 = keras.layers.BatchNormalization()(conv2)
conv2 = keras.layers.ReLU()(conv2)
conv3 = keras.layers.Conv1D(filters=64, kernel_size=3, padding="same")(conv2)
conv3 = keras.layers.BatchNormalization()(conv3)
conv3 = keras.layers.ReLU()(conv3)
gap = keras.layers.GlobalAveragePooling1D()(conv3)
output_layer = keras.layers.Dense(num_classes, activation="softmax")(gap)
return keras.models.Model(inputs=input_layer, outputs=output_layer)
model = make_model(input_shape=train_data.shape[1:])
keras.utils.plot_model(model, show_shapes=True)
epochs = 500
batch_size = 32
callbacks = [
keras.callbacks.ModelCheckpoint(
"best_model.h5", save_best_only=True, monitor="val_loss"
),
keras.callbacks.ReduceLROnPlateau(
monitor="val_loss", factor=0.5, patience=20, min_lr=0.0001
),
keras.callbacks.EarlyStopping(monitor="val_loss", mode = 'min', patience=50, verbose=1),
]
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["sparse_categorical_accuracy"],
)
history = model.fit(
train_data,
train_labels,
batch_size=batch_size,
epochs=epochs,
callbacks=callbacks,
validation_split=0.2,
verbose=1,
)
model = keras.models.load_model("best_model.h5")
test_loss, test_acc = model.evaluate(test_data, test_labels)
print("Test accuracy", test_acc)
print("Test loss", test_loss)
The above code can successfully display where the accuracy converged. Now, I'd like to make predictions on single samples. So far I have:
def read(file_name):
data = np.loadtxt(file_name, delimiter="\t")
y = data[:, 0]
x = data[:, 1:]
return x, y.astype(int)
test_data, test_labels = read("FordA_TEST_B.tsv")
test_data = test_data.reshape((test_data.shape[0], test_data.shape[1], 1))
test_labels[test_labels == -1] = 0
print(test_data)
model = keras.models.load_model("forda_original_model.h5")
q = model.predict(test_data[0])
This raises the error: ValueError: Error when checking input: expected input_1 to have 3 dimensions, but got array with shape (500, 1)
How does the input have to be reshaped and what is the rule to go by? Any help is much appreciated!
Copied from a comment:
The model expects a batch dimension. Thus, to predict for a single model, just expand the dimensions to create a single-sized batch by running:
q = model.predict(test_data[0][None,...])
or
q = model.predict(test_data[0][np.newaxis,...])
I am working on image dataset
I first resized all images
im_size1 = 128
im_size2 = 128
i = 0
for f, breed in tqdm(df_train.values):
if type(cv2.imread('train/{}.jpeg'.format(f)))==type(None):
continue
else:
img = cv2.imread('train/{}.jpeg'.format(f))
label = one_hot_labels[i]
x_train.append(cv2.resize(img, (im_size1, imt_size2)))
y_train.append(label)
i += 1
np.save('x_train2',x_train)
np.save('y_train2',y_train)
print('Done')
On the second run i passed Histogram of Gradient Feature
Note: Model was same in both cases. Ran on different projects, got different results
i = 0
for f, breed in tqdm(df_train.values):
if type(cv2.imread('train/{}.jpeg'.format(f)))==type(None):
continue
else:
img = cv2.imread('train/{}.jpeg'.format(f))
label = one_hot_labels[i]
resizedImage = cv2.resize(img, (im_size1, im_size2))
hog_vec, hog_vis = feature.hog(resizedImage, visualize=True)
resizedImageVec = cv2.resize(hog_vec, (im_size1, im_size2))
x_train.append(resizedImageVec)
#np.concatenate(x_train, hog_vec[:])
y_train.append(label)
i += 1
np.save('x_train2hog',x_train)
np.save('y_train2hog',y_train)
print('Done')
Then configured the model like so
base_model = ResNet50(weights = None, include_top=False, input_shape=(im_size1, im_size2, 3))
# Add a new top layer
x = base_model.output
x = Flatten()(x)
x = Dropout(0.2)(x)
x = Dense(32, activation='relu')(x)
x = Dense(16, activation='relu')(x)
predictions = Dense(num_class, activation='softmax')(x)
# This is the model we will train
model = Model(inputs=base_model.input, outputs=predictions)
# First: train only the top layers (which were randomly initialized)
#for layer in base_model.layers:
# layer.trainable = False
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
callbacks_list = [keras.callbacks.EarlyStopping(monitor='val_acc', verbose=1)]
model.summary()
Now my professor has asked me this.
"Train last layer using images, then train last layer using features (different representation of images). Concatenate these two layers, and then train one more layer."
Please guide me how can i accomplish this
Have a look at the Merge layers from Keras API
keras.layers.Concatenate(axis=-1)
and the functional version:
keras.layers.concatenate(inputs, axis=-1)
This is an abstract idea, I dont know the correct pipeline for implementing; I have used a RestNet50 architecture for training a model to classify image into 3 categories; one of the ways i was thinking of exploring was using the textual data of the image;
train_gen = image.ImageDataGenerator().flow_from_directory(dataset_path_train, target_size=input_shape[:2], batch_size=batch_size, class_mode='categorical', shuffle=True, seed=seed)
test_gen = image.ImageDataGenerator().flow_from_directory(dataset_path_valid, target_size=input_shape[:2], batch_size=batch_size, class_mode='categorical', shuffle=True, seed=seed)
Data prep for model;
now for each image i also have {text},{label} as key value pair for individual image;
if i have to pass
1. WordtoVec
2. TFIDF
I have read about embedding layer in Keras; I am not sure how to embed the text-data along with test_gen and train_gen in the model( in any intermediate layer or after Flatten().
base_model = ResNet50(weights='imagenet', include_top=False,
input_shape=input_shape)
from keras.models import Model, load_model
x = base_model.output
x = Flatten(name='flatten')(x)
predictions = Dense(3, activation='softmax', name='predictions')(x)
model = Model(inputs=base_model.input, outputs=predictions)
for layer in model.layers[0:141]:
layer.trainable = True
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
model.fit_generator(train_gen,steps_per_epoch=1000 , epochs=2,validation_steps=100, validation_data=test_gen,verbose=1)
So this is solved after reading through this Multi-input and multi-output models
The text input were TFIDF'ed using sklearn tfidf it resulted in 26038 features for matrix ;
x = base_model.output
x = Flatten(name='flatten')(x)
x2= Input(shape=(26078,), dtype='float32', name='tfidf_input')
combinedInput = concatenate([x2, x])
x = Dense(1024, activation="relu")(combinedInput)
# adding a regularizer with x sch as x=Dense(1024,activation="relu",activity_regularizer=regularizers.l1(0.01))
#x1= Dense(512, activation='softmax', name='predictions')(x)
predictions = Dense(3, activation='softmax', name='predictions')(x)
model = Model(inputs=[base_model.input,x2], outputs=predictions)
for layer in model.layers[0:141]:
layer.trainable = True
I have added an Input layer of dimension (26078,) which would be from the text after transforming it to TFIDF ( now this would add as text feature)
While fitting the data on the model
model.fit([image_data, text_feature], label,epochs=50,validation_split=0.10,steps_per_epoch=100,validation_steps=8, shuffle = True)
It takes 2 inputs one is the ResNet input of image and the other an array of [datasize,26078].
I have a CSV file with 2 columns of data. I built a regression approach model to make predictions. But currently, I can only get 1 prediction, what can I do to get 2 predictions. I previously used the following model
def build_model():
model = keras.Sequential([
layers.Dense(64, activation=tf.nn.relu, input_shape=[len(train_dataset.keys())]),
layers.Dense(64, activation=tf.nn.relu),
layers.Dense(1)
])
But I found a new model, so I used that one as shown below.
This is how I'm loading the data
column_names = ['longitude', 'Latitude']
raw_dataset = pd.read_csv('loglat.csv', names=column_names)
train_dataset = dataset.sample(random_state=0)
test_dataset = dataset.drop(train_dataset.index)
train_stats = train_dataset.describe()
train_stats = train_stats.transpose()
train_stats
train_labels = train_dataset.pop('longitude')
test_labels = test_dataset.pop('longitude')
normed_train_data = train_dataset
normed_test_data = test_dataset
The new model
from tf.keras.layers import Input, Dense
from tf.keras.models import Model
def build_model():
X = Input(shape=[len(train_dataset.keys())])
hidden_1 = Dense(64, activation=tf.nn.relu)(X)
hidden_2 = Dense(64, activation=tf.nn.relu)(hidden_1)
out_1 = Dense(1)(hidden_2)
out_2 = Dense(1)(hidden_2)
model = Model(inputs=[X], outputs=[out_1, out_2])
optimizer = tf.keras.optimizers.RMSprop(0.001)
model.compile(loss='mean_squared_error',
optimizer=optimizer,
metrics=['mean_absolute_error', 'mean_squared_error'])
return model
model = build_model()
linreg = model.fit(normed_train_data, train_labels, epochs=1000, verbose=0)
test_predictions = model.predict(normed_test_data).flatten()
The error with this is:
ValueError: Error when checking model target: the list of Numpy arrays that you are passing to your model is not the size the model expected. Expected to see 2 array(s), but instead got the following list of 1 arrays: [array([[130.4998]])]...
This is my first time creating a multi-input keras model, and I am not sure if I am doing something wrong as my training accuracy is not rising above 50 percent. If I use a single-input model, I can get to 90 percent plus pretty easily. This model uses the same input but different sizes of the input and then takes the max of the softmax prediction as the final prediction. So, I would assume it would be easier to train the model.
Here is the code:
def full_model_2(model_key):
base_model, preprocess = basemodel(model_key) #base model is just an imported imagenet model
base_model2, preprocess = basemodel(model_key)
for layer in base_model.layers:
layer.name = layer.name + "dup"
#first model
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(2048, activation='relu')(x)
x = BatchNormalization()(x)
x = Dense(512, activation='relu')(x)
x = BatchNormalization()(x)
predictions_x = Dense(classes, activation='softmax')(x)
#second model
y = base_model2.output
y = GlobalAveragePooling2D()(y)
y = Dense(2048, activation='relu')(y)
y = BatchNormalization()(y)
y = Dense(512, activation='relu')(y)
y = BatchNormalization()(y)
predictions_y = Dense(classes, activation='softmax')(y)
#predictions = Average()([predictions_x, predictions_y])
predictions = Maximum()([predictions_x, predictions_y])
model = Model(inputs= [base_model.input,base_model2.input], outputs=predictions)
for layer in model.layers[:-10]:
layer.trainable = False
return model, preprocess
My generator looks something like this (take two generators and creates two inputs)
def train_generator():
train_gen, _ = create_generators(batch_size, preprocess, img_size)
train_gen2, _ = create_generators(batch_size, preprocess, img_size2)
print(train_gen.seed)
print(train_gen2.seed)
while True:
X1i = train_gen.next()
X2i = train_gen2.next()
yield [X1i[0], X2i[0]], X1i[1]
Here is the original generator function:
train_datagen = ImageDataGenerator(preprocessing_function = preprocess)
train_generator = train_datagen.flow_from_directory(
train_data_dir,
shuffle = True,
seed = seed,
target_size = (img_size, img_size),
batch_size = batch_size,
class_mode = 'categorical')
return train_generator
model.compile(optimizer= r_optimizer,
loss='categorical_crossentropy',
metrics = ['accuracy'])
I have plotted the inputs from the generators, and I am indeed getting the same images but different sizes, so the input from generators seems to be okay.
I am thinking my model setup is off.
Thank you for your suggestions.