I've already looked into similar topics but none of the tips helped me. My model predicts and outputs only 1 class, even in the console I see only 1 array value. I have to check if the font in the account number is fake or real. It prints an accuracy of 0.99 even 1.00 but after manually checking it with model.predicts it only outputs 0's. I train it on 1000 pictures of each class. Any solutions? My code:
train = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1/255)
validation = train_set = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1/255)
validation_set = validation.flow_from_directory('Samples', class_mode='binary', batch_size=30, target_size=(500, 50), shuffle=True, seed=42, color_mode='rgb')
train_set = train.flow_from_directory(directory='Train', class_mode='binary', batch_size=30, target_size=(500, 50), shuffle=True, seed=42, color_mode='rgb')
print(train_set.classes)
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(16, kernel_size = (3, 3), activation='relu', input_shape=(500, 50, 3)),
tf.keras.layers.MaxPool2D(pool_size = (2, 2)),
tf.keras.layers.Conv2D(32, kernel_size = (3, 3), activation='relu'),
tf.keras.layers.MaxPool2D(pool_size = (2, 2)),
tf.keras.layers.Conv2D(64, kernel_size = (3, 3), activation='relu'),
tf.keras.layers.MaxPool2D(pool_size = (2, 2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(512, activation='relu'),
tf.keras.layers.Dense(1, activation='sigmoid')
])
print(train_set.class_indices)
model.compile(loss='binary_crossentropy', optimizer='adam', metrics= ['accuracy'])
model.fit(train_set, epochs=2, validation_data=validation_set)
path = 'Samples/'
DIRECTORIES = ['Fake', 'Real']
for dir in DIRECTORIES:
for file in os.listdir(path+dir):
img = tf.keras.preprocessing.image.load_img(path+dir+'/'+file)
img = tf.keras.preprocessing.image.img_to_array(img)
img = np.expand_dims(img, axis=0)
images = np.vstack([img])
val = np.argmax(model.predict(images))
print(val)
Photos to compare:
Real
Fake
Output
You're using your model as if you had two output neurons in your output layer. np.argmax(model.predict(images)) would return the index of the neuron with the maximum value, but since you only have 1, it will always return 0. Just check if the value returned by predict exceeds the threshhold or alternativly use two neurons.
Related
I built a CNN model to detect two kinds of defects on an image. These classes are 'big' and 'small' and the accuracy is really good. The architecture of my model is in the below:
inputs = tf.keras.Input(shape=(120, 120, 3))
x = tf.keras.layers.Conv2D(filters=16, kernel_size=(3, 3), activation='relu')(inputs)
x = tf.keras.layers.MaxPool2D(pool_size=(2, 2))(x)
x = tf.keras.layers.Conv2D(filters=32, kernel_size=(3, 3), activation='relu')(x)
x = tf.keras.layers.MaxPool2D(pool_size=(2, 2))(x)
x = tf.keras.layers.GlobalAveragePooling2D()(x)
outputs = tf.keras.layers.Dense(1, activation='sigmoid')(x)
model = tf.keras.Model(inputs=inputs, outputs=outputs)
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy']
)
print(model.summary())
history = model.fit(
train_data,
validation_data=val_data,
epochs=100,
callbacks=[
tf.keras.callbacks.EarlyStopping(
monitor='val_loss',
patience=3,
restore_best_weights=True
)
]
)
Now, I want to use this CNN model for multi classes and the classes would be 'big', 'small', 'other'. I have the data set, but I don't know how to change the model for three classes. Also, at the end I want to test one image to my CNN model and get the label if the inserted image is big, small or other, but I don't know how.
Try this:
model = tf.keras.Sequential()
model.add(tf.keras.layers.Conv2D(input_shape = (120, 120, 3), filters=16, kernel_size=(3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPool2D(pool_size=(2, 2)))
model.add(tf.keras.layers.Conv2D(filters=32, kernel_size=(3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPool2D(pool_size=(2, 2)))
model.add(tf.keras.layers.GlobalAveragePooling2D())
model.add(tf.keras.layers.Dense(3, activation='softmax'))
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
to predict, you can use this code:
from PIL import Image
import numpy as np
from skimage import transform
def load(filename):
np_image = Image.open(filename)
np_image = np.array(np_image).astype('float32')/255
np_image = transform.resize(np_image, (120, 120, 3))
np_image = np.expand_dims(np_image, axis=0)
return np_image
folder_path = 'Dataset/test/4.jpg'
image = load(folder_path)
pred = model.predict_classes(image)
pred.tolist()[0]
I have model trained and saved using following code
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import tensorflow as tf
from tensorflow.python.keras.optimizer_v2.rmsprop import RMSprop
train_data_gen = ImageDataGenerator(rescale=1 / 255)
validation_data_gen = ImageDataGenerator(rescale=1 / 255)
# Flow training images in batches of 120 using train_data_gen generator
train_generator = train_data_gen.flow_from_directory(
'datasets/train/',
classes=['bad', 'good'],
target_size=(200, 200),
batch_size=120,
class_mode='binary')
validation_generator = validation_data_gen.flow_from_directory(
'datasets/valid/',
classes=['bad', 'good'],
target_size=(200, 200),
batch_size=19,
class_mode='binary',
shuffle=False)
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(16, (3, 3), activation='relu', input_shape=(200, 200, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(32, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
# Flatten the results to feed into a DNN
tf.keras.layers.Flatten(),
# 512 neuron hidden layer
tf.keras.layers.Dense(512, activation='relu'),
# Only 1 output neuron. It will contain a value from 0-1
# where 0 for 1 class ('bad') and 1 for the other ('good')
tf.keras.layers.Dense(1, activation='sigmoid')])
model.compile(loss='binary_crossentropy',
optimizer=RMSprop(lr=0.001),
metrics='accuracy')
model.fit(train_generator,
steps_per_epoch=10,
epochs=25,
verbose=1,
validation_data=validation_generator,
validation_steps=8)
print("Evaluating the model :")
model.evaluate(validation_generator)
print("Predicting :")
validation_generator.reset()
predictions = model.predict(validation_generator, verbose=1)
print(predictions)
model.save("models/saved")
Then this model is converted to tflite using
import tensorflow as tf
def saved_model_to_tflite(model_path, quantize):
converter = tf.lite.TFLiteConverter.from_saved_model(model_path)
model_saving_path = "models/converted/model.tflite"
if quantize:
converter.optimizations = [tf.lite.Optimize.DEFAULT]
model_saving_path = "models/converted/model-quantized.tflite"
tflite_model = converter.convert()
with open(model_saving_path, 'wb') as f:
f.write(tflite_model)
Then model is tested for single image using
import tensorflow as tf
def run_tflite_model(tflite_file, test_image):
interpreter = tf.lite.Interpreter(model_path=str(tflite_file))
interpreter.allocate_tensors()
print(interpreter.get_input_details())
input_details = interpreter.get_input_details()[0]
output_details = interpreter.get_output_details()[0]
interpreter.set_tensor(input_details["index"], test_image)
interpreter.invoke()
output = interpreter.get_tensor(output_details["index"])[0]
prediction = output.argmax()
return prediction
main.py
if __name__ == '__main__':
converted_model = "models/converted/model.tflite"
bad_image_path = "datasets/experiment/bad/b.png"
good_image_path = "datasets/experiment/good/g.png"
img = io.imread(bad_image_path)
resized = resize(img, (200, 200)).astype('float32')
test_image = np.expand_dims(resized, axis=0)
prediction = run_tflite_model(converted_model, test_image)
print(prediction)
despite what I image I feed into the model I am always getting prediction as 0. What is wrong here?
You forgot to normalize the image before passing it to the tflite model.
resized = resize(img, (200, 200)).astype('float32')
resized = resized / 255.
test_image = np.expand_dims(resized, axis=0)
prediction = run_tflite_model(converted_model, test_image)
Edit:
You are performing a binary classification task not a multi-class classification task so you do not need to take the max value in the output array as it only produces a single value in the range of 0 to 1. You can interpret the results as being a positive example if the value is greater than or equal to 0.5 and a negative example if it is less than 0.5.
import tensorflow as tf
def run_tflite_model(tflite_file, test_image):
interpreter = tf.lite.Interpreter(model_path=str(tflite_file))
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
interpreter.set_tensor(input_details[0]["index"], test_image)
interpreter.invoke()
predictions = interpreter.get_tensor(output_details[0]["index"])
return 1 if predictions >= 0.5 else 0 # 1 = good, 0 = bad
I would like to integrate the weighted_cross_entropy_with_logits to deal with data imbalance. I am not sure how to do it. Class 0 has 10K images, while class 1 has 500 images. Here is my code.
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(32, (3, 3), input_shape=(dim, dim, 3), activation='relu'),
....
tf.keras.layers.Dense(2, activation='softmax')
])
model.compile(optimizer="nadam",
loss=tf.keras.losses.CategoricalCrossentropy(),
metrics=['accuracy'])
class_weight = {0: 1.,
1: 20.}
model.fit(
train_ds,
val_ds,
epochs=epc,
verbose=1,
class_weight=class_weight)
You can simply wrap tf.nn.weighted_cross_entropy_with_logits inside a custom loss function.
Remember also that tf.nn.weighted_cross_entropy_with_logits expects logits so your network must produce it and not probabilities (remove softmax activation from the last layer)
Here a dummy example:
X = np.random.uniform(0,1, (10,32,32,3))
y = np.random.randint(0,2, (10,))
y = tf.keras.utils.to_categorical(y)
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(32, (3, 3), input_shape=(32, 32, 3), activation='relu'),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(2) ### must be logits (remove softmax)
])
def my_loss(weight):
def weighted_cross_entropy_with_logits(labels, logits):
loss = tf.nn.weighted_cross_entropy_with_logits(
labels, logits, weight
)
return loss
return weighted_cross_entropy_with_logits
model.compile(optimizer="nadam",
loss=my_loss(weight=0.8),
metrics=['accuracy'])
model.fit(X,y, epochs=3)
At inference time you obtain the probabilities in this way:
tf.nn.softmax(model.predict(X))
I'm doing a project on Neural network and was trying a python code using keras and tensorflow package. Currently, I'm experiencing a problem of not getting the validation accurary to going up at all. I have a training set of 9815 images and 200 test set images. I'm really stuck here please help.
Right now, the validation result is at exactly 0.5000 for almost all 100 epoch and not going up at all.
#Image Processing Stage
train_data = ImageDataGenerator(rescale = 1./255, shear_range = 0.2, zoom_range = 0.2, horizontal_flip = True)
test_data = ImageDataGenerator(rescale = 1./255)
training_set = train_data.flow_from_directory('dataset/train_data', target_size = (128, 128), batch_size = 42, class_mode = 'binary')
test_set = test_data.flow_from_directory('dataset/test_data', target_size = (128, 128), batch_size = 42, class_mode = 'binary')
# Starting Convolutional Neural Network
start_cnn = load_model('CNN.h5')
start_cnn.get_weights()
start_cnn = Sequential()
start_cnn.add(Conv2D(32, (3, 3), input_shape = (128, 128, 3), activation = 'relu', padding='same')) #3*3*3*32+32
start_cnn.add(Conv2D(32, (3, 3), activation = 'relu'))
start_cnn.add(MaxPooling2D(pool_size = (2, 2)))
for i in range(0,2):
start_cnn.add(Conv2D(128, (3, 3), activation = 'relu', padding='same'))
start_cnn.add(MaxPooling2D(pool_size = (2, 2)))
for i in range(0,2):
start_cnn.add(Conv2D(128, (3, 3), activation = 'relu', padding='same'))
start_cnn.add(MaxPooling2D(pool_size = (2, 2)))
# Flattening
start_cnn.add(Flatten())
# Step 4 - Full connection
start_cnn.add(Dense(activation="relu", units=128))
start_cnn.add(Dense(activation="relu", units=64))
start_cnn.add(Dense(activation="relu", units=32))
start_cnn.add(Dense(activation="softmax", units=1))
start_cnn.summary()
# Compiling the CNN
start_cnn.compile(Adam(learning_rate=0.001), loss = 'binary_crossentropy', metrics = ['accuracy'])
start_cnn.fit(training_set, steps_per_epoch=234, epochs = 100, validation_data = test_set)
start_cnn.save('CNN.h5')
You cannot use the softmax activation with one neuron, like you are doing here:
start_cnn.add(Dense(activation="softmax", units=1))
To do binary classification with one neuron, you have to use the sigmoid activation:
start_cnn.add(Dense(activation="sigmoid", units=1))
I'm trying to create a neural network that will get two or more faces of PersonA and PersonB and ect... and will identify the name of the person for each face.
For example the NN get those pictures:
1
2
and the NN will say - 1 is sheldon, 2 is leonard.
So I did the following code -
import numpy as np
import tensorflow as tf
from pathlib import Path
import cv2
from random import shuffle
X = []
Y = []
NAMES = {
}
i = 0
for filename in Path('data').rglob('*.jpg'):
i += 1
img = cv2.imread(str(filename), cv2.IMREAD_UNCHANGED)
resized = cv2.resize(img, (150, 150), interpolation=cv2.INTER_AREA)
X.append(np.asarray(resized))
thisName = str(filename).split("_")[0].split("\\")[1]
if i == 1:
NAMES[thisName] = 0
if thisName in NAMES.keys():
Y.append(np.asarray(NAMES[thisName]))
else:
print(NAMES.values())
NAMES[thisName] = max(NAMES.values()) + 1
Y.append(np.asarray(NAMES[thisName]))
Z = list(zip(X, Y))
shuffle(Z) # WE SHUFFLE X,Y TO PERFORM RANDOM ON THE TEST LEVEL
X, Y = zip(*Z)
X = np.asarray(X)
Y = np.asarray(Y)
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(16, (3, 3), activation='relu', input_shape=(150, 150, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(32, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(1024, activation='relu'),
tf.keras.layers.Dense(7, activation='softmax', name='pred')
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# -------------- OUR TENSOR FLOW NEURAL NETWORK MODEL -------------- #
print("fitting")
history = model.fit(X, Y, epochs=1, batch_size=20)
print("testing")
model.evaluate(X, Y)
( the lines that come before the model are just came up to take a picture from the dataset and give her a number that customize to the name of the picture, let's say it was a picture of sheldon than she put as output 0 and as input the image himself ... )
I took this : test + training data and I had tested the model on it after I was fitting it but unfortuenntly instead of get excepted results of 90% I got ONLY 25%.
Am I doing something wrong?
Thanks alot and sorry for my english
EDIT : my data set looks fine except the pictures of penny ( but it should not affect so much )
EDIT 2: After I added some conv2d I got 75% instead of 25%, I still want more but it's Absoulutly Better
this is my new model :
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(64, (3, 3), activation='relu', input_shape=(150, 150, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(256, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(512, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(1024, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(2048, activation='relu'),
tf.keras.layers.Dense(7, activation='softmax', name='pred')
])
The only obvious flaw that I see in your code is that you only ran one epoch. Set epochs to like 10, 20, or any amount you have enough patience for.
Things that might help:
Make a deeper net (add more layers)
Increase the number of neurons (yours are quite small for 150x150x3 input shape)