Improving the accuracy of image classification model - python

My aim is to build an image classification model for flowers. The data RAR file consists of a folder named train data which consists of about 16000 images labelled from 0- 16000. Similarly there is a folder for test data also.
Apart from this there are two csv workbooks. The first csv workbook consists of two attributes - label & flower class. There are 104 labels & flower classes. The second workbook also consists of two attributes - id & flower class. This csv is the link between the train images folder & flower classes. ID is the linking attribute. I.e for eg assume that image labelled 10 in train images folder is the image of a sunflower. Hence in the csv workbook the flower class entry corresponding to id = 10 is a sunflower.
For eg assume that image labelled 10 in train data folder is a sunflower. Hence in the (second) workbook the flower class entry corresponding to id =10 is a sunflower.
This is my code
# Import relavant libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
import keras
from keras.models import Sequential
from keras.layers import Dense, Flatten
from sklearn.model_selection import train_test_split
from PIL import Image
# Load the csv files
# Workbook no.1
label_csv = pd.read_csv('/content/flowers_label.csv')
# Workbook no.2
train = pd.read_csv('/content/flowers_idx.csv')
# To sort the train csv id wise from 0 - 16464
train.sort_values('id')
# Creating inputs and targets
X = [] #images
y = [] # labels
base = "/content/flower_tpu/flower_tpu/flowers_google/flowers_google//"
row = 0;
for idx in range(len(train)):
# get the flower row
flower = train.iloc[idx]
# create flower path
path = f"{base}{flower.id}.jpeg"
#load image
img = Image.open(path)
# convert to numpy
img = np.array(img)
#save to X
X.append(img)
# get label
label = label_csv[label_csv['flower_class'] == flower.flower_cls].label.values[0]
# save to y
y.append(label)
# Train Validation split
X_train, X_validation, y_train, y_validation = train_test_split(X, y, random_state=12, test_size=0.2)
# The model
output_size = 104
hidden_layer_size = 150
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=(224, 224, 3)),
tf.keras.layers.Dense(hidden_layer_size, activation='relu'),
tf.keras.layers.Dense(hidden_layer_size, activation='relu'),
tf.keras.layers.Dense(output_size, activation='softmax')
])
# Converting all data into ndarrays
X_train = np.asarray(X_train)
y_train = np.asarray(y_train)
X_validation = np.asarray(X_validation)
y_validation = np.asarray(y_validation)
# Compilation
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# Fitting
model.fit(X_train, y_train, epochs=3, validation_data=(X_validation, y_validation), validation_steps=10, verbose =2)
I code is running but the train & validation accuracy is as poor as 6%. :/
How can I improve this code?

Related

I have the same number of files, and still having different shape on them, ANN machine learning

I am trying to create neural network with python, it is kind of ANN network to use in classification problem. The purpose of the neural network is to classify who is speaking, whether it is me or someone else. I have the data in 2 folders.
folders image
one is called me, they are audios of me speaking, and another is called other, audios of other people speaking.
View of the wav files(audio data)
The problem is that it cannot train the network because the data is not the same length, and if it does!, there are 18 in each folder, not one more, not one less.
When I do
print(X.shape)
print(y.shape)
gives this.
Result of X, y shapes
Is not the same shape even there are 18 audio files on each folder
model.py
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import tensorflow as tf
import numpy as np
from scipy.io import wavfile
from pathlib import Path
import os
### DATASET
pathlist = Path(os.path.abspath('Voiceclassification/Data/me/')).rglob('*.wav')
# My voice data
for path in pathlist:
filename = str(path)
# convert audio to numpy array and then 2D to 1D np Array
samplerate, data = wavfile.read(filename)
#print(f"sample rate: {samplerate}")
data = data.flatten()
#print(f"data: {data}")
pathlist2 = Path(os.path.abspath('Voiceclassification/Data/other/')).rglob('*.wav')
# other voice data
for path2 in pathlist2:
filename2 = str(path2)
samplerate2, data2 = wavfile.read(filename2)
data2 = data2.flatten()
#print(data2)
### ADAPTING THE DATA FOR THE MODEL
X = data # My voice
y = data2 # Other data
#print(X.shape)
#print(y.shape)
### Trainig the model
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=0)
# Performing future scaling
sc = StandardScaler()
x_train = sc.fit_transform(x_train)
x_test = sc.transform(x_test)
### Creating the ANN
ann = tf.keras.models.Sequential()
# First hidden layer of the ann
ann.add(tf.keras.layers.Dense(units=6, activation="relu"))
# Second one
ann.add(tf.keras.layers.Dense(units=6, activation="relu"))
# Output layer
ann.add(tf.keras.layers.Dense(units=6, activation="sigmoid"))
# Compile our neural network
ann.compile(optimizer="adam",
loss="binary_crossentropy",
metrics=['accuracy'])
# Fit ANN
ann.fit(x_train, y_train, batch_size=32, epochs=100)
ann.save('train_model.model')
Any idea?
Is because your wav audio files maybe have different sizes, they can be 10 seconds all, but if millisecond are different, that will affect your data shape, what you can do is trim your wav files so all of them are 10.00sec with no millisenconds

How to convert a folder of images into X and Y batches with Keras?

Say I have a folder of images such as:
PetData
|
Dog - images
|
Cat - images
How would I transform it into (x_train, y_train),(x_test, y_test) format? I see this format used extensively with the MNIST dataset which goes like:
mnist = tf.keras.datasets.mnist
(x_train, y_train),(x_test, y_test) = mnist.load_data()
However i'd like to do this with my own folder of images.
mnist.load_data() returns two tuples with the content of the images and the labels in uint8 arrays. You should get those arrays by loading the images of your folders (you can use modules such as PIL.Image in order to load X, your y is just the set labels provided by the folder name).
PIL.Image use example:
from PIL import Image
import glob
for infile in glob.glob("*.jpg"):
im = Image.open(infile)
To split train/test you can use sklearn.model_selection.train_test_split:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33)
Suppose your train or test images are in folder PetData each class in separate folder as Dog and Cat. You can use ImageDataGenerator to prepare your train/test data as below:
from keras import layers
from keras import models
model = models.Sequential()
#define your model
#..........
#......
#Using ImageDataGenerator to read images from directories
from keras.preprocessing.image import ImageDataGenerator
train_dir = "PetData/"
#PetData/Dog/ : dog images
#PetData/Cat/ : cat images
train_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory( train_dir, target_size=(150, 150), batch_size=20)
history = model.fit_generator( train_generator, steps_per_epoch=100, epochs=30) #fit the model using train_generator
Hope this helps!
If you want to import images from a folder in your computer you can import images 1 by 1 from the folder in insert the in a list.
Your folder format is as you have shown:
PetData
|
Dog - images
|
Cat - images
Assume path is a variable storing the address of PetData folder. We will use OpenCV to import images but you can use other libraries as well.
data = []
label = []
Files = ['Dog', 'Cat']
label_val = 0
for files in Files:
cpath = os.path.join(path, files)
cpath = os.path.join(cpath, 'images')
for img in os.listdir(cpath):
image_array = cv2.imread(os.path.join(cpath, img), cv2.IMREAD_COLOR)
data.append(image_array)
label.append(label_val)
label_val = 1
Convert the list to a numpy array.
data = np.asarray(data)
label = np.asarray(label)
After importing the images you can use train_test_split to split the data for training and testing.
X_train, X_test, y_train, y_test = train_test_split(data, label, test_size=0.33, random_state=42)

Approach of training a large image data set using keras, running out of memory

I'm new in computer vision and ML area, I'm trying to develop an image recognition model that I'm training with a large data set of images (50 000 images, 18 GB in size) but on a laptop like Acer Predator that has 16 GB memory and 7th gen Core i7 cpu, GTX 1060 Nvidia, I'm running out of memory even though I'm using GPU on tensorflow.
If I train this model with few images like 2000, to 4000 then it's working fine. It seems there is some wrong approach I'm using to train this model but I'm not able to figure out the right approach. I think if I load images into small multiple batches and then train then it could help but I don't know how to achieve this.
Below is the code snippet of my train model request.
My train.py is as below
import matplotlib
matplotlib.use("Agg")
from keras.preprocessing.image import ImageDataGenerator
from keras.optimizers import Adam
from keras.preprocessing.image import img_to_array
from keras.preprocessing import image
from sklearn.preprocessing import MultiLabelBinarizer
from sklearn.model_selection import train_test_split
from pyimagesearch.smallervggnet import SmallerVGGNet
import matplotlib.pyplot as plt
from imutils import paths
import numpy as np
import random
import pickle
import os
import json
import tensorflow as tf
with tf.device('/device:CPU:0'):
a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a')
b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2], name='b')
c = tf.matmul(a, b)
#config = tf.ConfigProto(log_device_placement=True)
session = tf.Session(config=tf.ConfigProto(log_device_placement=True))
print(session.run(c))
with open('conf/conf.json') as f:
config = json.load(f)
# config variables
dataset = config["dataset"]
model_path = config["model"]
labelbin = config["labelbin"]
plot = config["plot"]
test_image = config["test_image"]
print('dataset: %s '+dataset)
EPOCHS = 75
INIT_LR = 1e-3
BS = 32
IMAGE_DIMS = (96, 96, 3)
# grab the image paths and randomly shuffle them
print("[INFO] loading images...")
imagePaths = sorted(paths.list_images(dataset))
random.seed(42)
random.shuffle(imagePaths)
# initialize the data and labels
data = []
labels = []
for imagePath in imagePaths:
img = image.load_img(imagePath,target_size=(IMAGE_DIMS[1], IMAGE_DIMS[0]))
img = img_to_array(img)
data.append(img)
l = label = imagePath.split(os.path.sep)[-2].split("_")
labels.append(l)
print("[INFO] images loading done...")
# scale the raw pixel intensities to the range [0, 1]
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)
print("[INFO] data matrix: {} images ({:.2f}MB)".format(
len(imagePaths), data.nbytes / (1024 * 1000.0)))
# binarize the labels using scikit-learn's special multi-label
# binarizer implementation
print("[INFO] class labels:")
mlb = MultiLabelBinarizer()
labels = mlb.fit_transform(labels)
# loop over each of the possible class labels and show them
for (i, label) in enumerate(mlb.classes_):
print("{}. {}".format(i + 1, label))
# partition the data into training and testing splits using 80% of
# the data for training and the remaining 20% for testing
(trainX, testX, trainY, testY) = train_test_split(data,
labels, test_size=0.2, random_state=42)
# construct the image generator for data augmentation
aug = ImageDataGenerator(rotation_range=25, width_shift_range=0.1,
height_shift_range=0.1, shear_range=0.2, zoom_range=0.2,
horizontal_flip=True, fill_mode="nearest")
# initialize the model using a sigmoid activation as the final layer
# in the network so we can perform multi-label classification
print("[INFO] compiling model...")
model = SmallerVGGNet.build(
width=IMAGE_DIMS[1], height=IMAGE_DIMS[0],
depth=IMAGE_DIMS[2], classes=len(mlb.classes_),
finalAct="sigmoid")
# initialize the optimizer (SGD is sufficient)
opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)
# compile the model using binary cross-entropy rather than
# categorical cross-entropy -- this may seem counterintuitive for
# multi-label classification, but keep in mind that the goal here
# is to treat each output label as an independent Bernoulli
# distribution
model.compile(loss="binary_crossentropy", optimizer=opt,
metrics=["accuracy"])
# train the network
print("[INFO] training network...")
H = model.fit_generator(
aug.flow(trainX, trainY, batch_size=BS),
validation_data=(testX, testY),use_multiprocessing=True,
steps_per_epoch=len(trainX) // BS,
epochs=EPOCHS, verbose=1)
# save the model to disk
print("[INFO] serializing network...")
model.save(model_path)
# save the multi-label binarizer to disk
print("[INFO] serializing label binarizer...")
f = open(labelbin, "wb")
f.write(pickle.dumps(mlb))
f.close()
Conf.json is:
{
"dataset" : "data-images",
"model" : "output/fashion.model",
"labelbin" : "output/mlb.pickle",
"plot" : "output/plot.png",
"test_image" : "examples/example_01.jpg"
}

Gender Voice with Python coding

I am working on a sample data set from a link below.
https://www.kaggle.com/enirtium/gender-voice/data
I am trying to open .csv file(maybe I am opening it wrongly) and trying to create fully connected neural layers. Then, I am trying to train them but unfortunately, I am getting input shape not fitting problem.
"ValueError: Error when checking input: expected dense_1_input to have shape (None, 2800) but got array with shape (3168, 1)"
My codes like these:
import csv
import numpy
import string
from keras.models import Sequential
from sklearn.model_selection import train_test_split
import numpy as np
from keras import models
from keras import layers
path = r'/Users/username/Desktop/voice.csv'
meanfreq = []
sd = []
median = []
label = []
with open(path, 'r') as csv_file:
csv_reader = csv.reader(csv_file)
next(csv_reader)
for line in csv_reader:
#print(line['meanfreq'])
meanfreq.append(line[0])
sd.append(line[1])
median.append(line[2])
if line[20] == "female":
label.append(1)
else:
label.append(0)
network = models.Sequential()
network.add(layers.Dense(512, activation='relu', input_shape=(2800,)))
network.add(layers.Dense(1, activation='sigmoid'))
network.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
network.fit(meanfreq, label, epochs=5, batch_size=128)
scores = network.evaluate(meanfreq, label)
print("\n%s: %.2f%%" % (network.metrics_names[1], scores[1]*100))
I suppose that maybe, I can't open .csv file (it is opening "list" primitive) or there are any other problems. I am unfortunately fresh man at neural networks and python. I will open this csv file and will use its %70 data to train, %30 data for testing.
Yes,
It works as these;
import pandas as pd
import numpy as np
from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import train_test_split
# get data ready
data = pd.read_csv('voice.csv')
data.shape
# split out features and label
X = data.iloc[:, :-1].values
y = data.iloc[:, -1]
# map category to binary
y = np.where(y == 'male', 1, 0)
enc = OneHotEncoder()
# reshape y to be column vector
y_ = enc.fit_transform(y.reshape(-1, 1)).toarray()
X_train, X_test, y_train, y_test = train_test_split(
X, y_, train_size=0.80, random_state=42)
network = models.Sequential()
network.add(layers.Dense(512, activation='relu', input_shape=(20,)))
network.add(layers.Dense(2, activation='sigmoid'))
network.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
network.fit(X_train, y_train, epochs=100, batch_size=128)
network.evaluate(X_test, y_test)
Reading in the data seems to be fine.
I Imagine you have a data set that looks like:
mean_freq, label
.12 0
.45 1
And you want to train a classifier. Currently the model is expecting
a training example to have 2800 features. input shape=(2800,) but you only want 1 feature: the mean_freq
The mistake here is that you are trying to tell Keras how much training examples to use while declaring the model. You don't do that here, you'll do that later when you're fitting the model.
So the input_shape to keras's Dense Layer should be (1, ) for the single feature. If you're going to use mean and median freq then you would want two features (2, ) and so on.
# note change from 2800 to 1
network.add(layers.Dense(512, activation='relu', input_shape=(1,)))
And you can split your training and test sets in multiple ways. My suggestion is to do something like this:
train_size = 2800
X_train = mean_freq[:train_size]
y_train = label[:train_size]
X_test = mean_freq[train_size:]
y_test = label[:train_size]
Then fit the model with the training set and score with the test set.
network.fit(X_train, y_train, epochs=5, batch_size=128)
scores = network.evaluate(X_test, y_test)
Edit to reflect comments:
well if the case is that you training data has 20 features then
you tell keras that with:
# note change from 2800 to 1
network.add(layers.Dense(512, activation='relu', input_shape=(20,)))
You have do the work necessary to get the data in to the shape you need for training and testing but the template above is how you would fit and evaluate the model.
I would also note that there are better ways read in csv data if you're going to do modeling (as you are). Look at using a pandas dataframe.
Also better (more standard ways) of creating train and test split: look into sklearn's train_test_split
Edit 2: A quick model of the voice data
import pandas as pd
import numpy as np
from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import train_test_split
from keras.model import Model
from keras.layers import Dense, Input
# get data ready
data = pd.read_csv('voice.csv')
data.shape
# split out features and label
X = data.iloc[:, :-1].values
y = data.iloc[:, -1]
# map category to binary
y = np.where(y == 'male', 1, 0)
enc = OneHotEncoder()
# reshape y to be column vector
y_ = enc.fit_transform(y.reshape(-1, 1)).toarray()
X_train, X_test, y_train, y_test = train_test_split(
X, y_, train_size=0.80, random_state=42)
# model using keras functional style
inp = Input(shape =(20, ))
dense = Dense(128)(inp)
out = Dense(2, activation='sigmoid')(dense)
model = Model(inputs=[inp], outputs=[out])
model.compile(loss='binary_crossentropy', optimizer='adam',
metrics=['accuracy'])
model.fit(X_train, y_train, epochs=100, batch_size=128)
model.evaluate(X_test, y_test)

How to add data via directories for training images

I have been going through git repository by flyyufelix "https://github.com/flyyufelix/cnn_finetune" to fine tune an inception v3 network I want to train network to detect a disease so I have 2 set of images one with disease and without disease.
The git says X_train, Y_train, X_valid, Y_valid = load_data() he loads the cifar dataset ,The git asks us to create our own load_data() function.The author has the code as below
import cv2
import numpy as np
from keras.datasets import cifar10
from keras import backend as K
from keras.utils import np_utils
nb_train_samples = 3000 # 3000 training samples
nb_valid_samples = 100 # 100 validation samples
num_classes = 10
def load_cifar10_data(img_rows, img_cols):
# Load cifar10 training and validation sets
(X_train, Y_train), (X_valid, Y_valid) = cifar10.load_data()
# Resize trainging images
if K.image_dim_ordering() == 'th':
X_train = np.array([cv2.resize(img.transpose(1,2,0), (img_rows,img_cols)).transpose(2,0,1) for img in X_train[:nb_train_samples,:,:,:]])
X_valid = np.array([cv2.resize(img.transpose(1,2,0), (img_rows,img_cols)).transpose(2,0,1) for img in X_valid[:nb_valid_samples,:,:,:]])
else:
X_train = np.array([cv2.resize(img, (img_rows,img_cols)) for img in X_train[:nb_train_samples,:,:,:]])
X_valid = np.array([cv2.resize(img, (img_rows,img_cols)) for img in X_valid[:nb_valid_samples,:,:,:]])
# Transform targets to keras compatible format
Y_train = np_utils.to_categorical(Y_train[:nb_train_samples], num_classes)
Y_valid = np_utils.to_categorical(Y_valid[:nb_valid_samples],num_classes)
return X_train, Y_train, X_valid, Y_valid
can i know how to generate a function which loads
data X_train, Y_train, X_valid, Y_valid = load_data() when i have directries in pc
Use Keras' ImageDataGenerator() class and call flow_from_directory() on it. The labels will be automatically inferred from the directory names. So if you have a directory titled "disease," then Keras would infer that all images within that directory are labeled as "disease," and the same thing would be true for another directory titled "no disease," for example.
I demonstrate how to prepare image data for training a CNN in Keras in this video. The first half of the video is about image organization on disk, and then the second half goes through the process described above.
Follow this tutorial once and all your doubts will get cleared.
https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html

Categories