use of libSVM tool for performing a multi-class classification - scikit-learn

I am trying to perform classification on a satellite image using libSVM library. What I want is to display the classified image and save it,not only to get the accuracy results on my terminal. I have extracted the pixel values from teh training datasets (shown below) and I used the script csv2libsvm (https://github.com/zygmuntz/phraug/blob/master/csv2libsvm.py) to bring my data in the right format for libsvm. There are 4 different classes in the image to be classified. My satellite image and the training data are displayed below.
fig 1: Image to be classified with training data.
The steps I followed are based on the following tutorial https://www.csie.ntu.edu.tw/~cjlin/papers/libsvm.pdf.
split training and testing data (70% training and 30% testing).
svm - subset.py datasets 12000 training.tr testing.te
Train the model
svm-train training.tr
make prediction
svm-predict testing.te training.tr.model classification output
The accuracy of this classification was 95%, which was great.
What I am really interested in now, is to displayed the classified image. So, I need to construct my classified image out of the csv file which containes the classified labels. This is where the problem comes and do not know how to do it. What I have done (and did not work) is the following:
I imported the csv file produced by lbSVM into python using csv module.
I tried to reshape the csv file into the shape of my image
My code is shown below:
with open('/home/io/Desktop/training/1TESTING/libSVM_classification/classification_results', 'r') as csvfile:
reader = csv.reader(csvfile, delimiter=' ')
results = []
for row in reader:
results.append(row)
results_arr = np.asarray(results, dtype=int)
predicted = results_arr[results_arr>0] #here is my predicted labels
#load the image to be classified and read the projection system
raster_dataset = gdal.Open(sea_ice, gdal.GA_ReadOnly)
geo_transform = raster_dataset.GetGeoTransform()
proj = raster_dataset.GetProjectionRef()
#loop over all bands of the image and append them.
bands_data = []
for b in range(1, raster_dataset.RasterCount+1):
band = raster_dataset.GetRasterBand(b)
bands_data.append(band.ReadAsArray())
bands_data = np.dstack(bands_data)
row, col, n_bands = bands_data.shape
#get the classified labels from libsvm and reshape them into the initial image
#in order to display it using matplotlib
class_prediction = predicted.reshape(bands_data[:, :, 0].shape)
The size of the image to be classified is(303 x 498) and the size of the predicted classes produced by libsvm is 1807. Hence, the error I get when try to reshape the libsvm results i get the following error.
ValueError: cannot reshape array of size 1807 into shape (303,498)
This error makes sense. I have 1907 rows and try to reshape it to match my initial image, which is obviously impossible.
So, How can I display my classified image? I achieved an accuracy of 95% but have not found a way of seeing the classification results. I though that libsvm might have an option for exporting the classification results into tiff but it does not.
I would appreciate any help, thoughs or tips

Related

How to build a customized dataset from MNIST in pytorch

I am importing MNIST dataset as train_data_MNIST = torchvision.datasets.MNIST(root=path+"MNIST", train=True,transform=transforms, download=True)and I am trying to make a smaller dataset from MNIST, let's say the first 10,000 images and corresponding labels. I know this can be handled with torch.utils.data.Subset. But what I want is a torchvision.datasets object (if I directly apply torch.utils.data.Subset to the train_data_MNIST that I list above, the result is an object from torch.utils.data.Subset class).
Is there any possible way such that I can use a fraction of the original MNIST dataset to create a new dataset (not subset)?
Thanks in advance.
What about modifying data and targets directly? For example:
dataset = torchvision.datasets.MNIST(root=path+"MNIST", train=True,transform=transforms, download=True)
dataset.data = dataset.data[:10000]
dataset.targets = dataset.targets[:10000]

How am I able to visualize incorrect predictions from a binary image classifier and printing out the classification report

I have been trying to follow Francois example of a binary image classifier of cats and dogs. I have attempted to follow his example in another similar set in kaggle (https://www.kaggle.com/playlist/men-women-classification) and I want to achieve the following
Visualise the predictions that are wrong
Come out with the classification report
I already have a model with around 85% accuracy on the validation set but I want to know roughly what kind of images my model is getting wrong as well as coming up with a classification report with sklearn.metric's classification report.
However I do not know how does the image generator works and have a big problem trying to know how to pair the predictions with the labels of the test images.
from sklearn.metrics import classification_report
new_test_datagen = test_datagen.flow_from_directory(
directory = test_dir,
target_size=(150,150),
batch_size=1,
class_mode='binary',
seed = 42,
)
train_image = new_train_generator.next()
plt.imshow(train_image[0].reshape(150,150,-1))
print(train_image[1])
#I want to output images but I am not sure if this is the most efficient way of doing it
predictions = model.predict(test_generator)
predictions.shape
#The predictions is a numpy array of length 476 but I do not know what are the 'correct' labels found in my test set to validate it against this output.
model.evaluate(test_generator)
# [0.3109202980995178, 0.8886554837226868]

Keras: Load dataset and autocrop relevant area of image

I'm working on signature verification and there were a bunch of things I wanted to do using Keras/ OpenCV/ PIL but couldn't find relevant information. I have loaded the dataset folder using Keras.preprocessing.image_dataset_from_directory and now need to:
Crop the signature from the image stored in the dataset. There may be rectangular borders (or a side of the border) and the border pixels aren't the same in all images.
Resize the image and also take care of augmentation in the signature.
Example Images:
Since I'm working in Keras, I thought of working with its functions but couldn't find any. How can I auto crop/ extract a signature in the dataset I've loaded? About image augmentation, should I do this in this image preprocessing stage, or implement this in CNN model I am using? I am new to image processing and Keras.
Also, because of loading entire training folder as a dataset, the labels are "Genuine" and "Forged". However, there are multiple genuine and forged signatures of a person, and there are multiple people. How do I divide the data?
Organize your directories as follows
main_dir
-train_dir
``person1_fake_dir
```person1 fake image
```person1 fake image
---etc
``person1_real_dir
---person1 real image
---person1 real image
--- etc
--person2_fake_dir
--- person2 fake image
--- person2 fake image
--- etc
--person2_real_dir
---person2 real image
---person2 real image
---etc
.
.
.
--personN_fake_dir
---personN fake image
---personN fake image
---etc
--personN_real_dir
---personN real image
---personN real image
--- etc
-test_dir
same structure as train_dir but put test images here
-valid_dir
same structure as train_dir but put validation images here
If you have N persons then you will have 2 X N classes
You can then use tf.keras.preprocessing.image.ImageDataGenerator().flow_from_directory()
to input your data. Documentation is here. You don't have to worry about cropping the images just set the image size in flow to something like (256,256).
Code below show the rest of the code you need
data_gen=tf.keras.preprocessing.image.ImageDataGenerator(resize=1/255)
train_gen=data_gen.flow_from_directory(train_dir, target_size=(224,224), color-mode='grayscale')
valid_gen=data_gen.flow_from_directory(valid_dir, target_size=(224,224), color-mode='grayscale', shuffle=False)
test_gen=data_gen.flow_from_directory(test_dir, target_size=(224,224), color-mode='grayscale', shuffle=False)
model.compile(optimizer=tf.keras.optimizers.Adam(), loss=tf.keras.losses.CategoricalCrossentropy(), metrics='accuracy')
history=model.fit(train_gen, epochs=20, verbose=1)
accuracy=model.evaluate (test_gen)[1]*100
print ('Model accuracy is ', accuracy)
Note your model will not be able to tell fake from real in the general case. It should work for persons 1 through N. You could try putting all the fake images in one class directory and all the real images in another class directory and train it but I suspect it will not work well in telling real from fake for the general case.

Loading Training Images using Keras

To train a model using Keras, should I load all the images I have to an array to create something like
x_train, y_train
Or is there a better way to read the images on the fly while training. I am not looking for ImageDataGenerator class since my output is an array of points not classes based on directory names..
I managed to get my data csv file to contain the array of points and image file name in 9 columns as follows:
x1 x2 ..... x8 Image_file_name
You can use this data with ImageDataGenerator. You incorrectly assume that it needs folders for classes, but that only applies to flow_from_directory. The method flow_from_dataframe allows you to load data from a Pandas dataframe, from where you can load your data, for example:
idg = ImageDataGenerator(...)
df = pd.load_csv('your_data.csv')
generator = idf.flow_from_dataframe(directory='image folder', x_col = 'filename_column',
y_col = ['col1', 'col2', ..., 'coln'],
class_mode='other')
This generator will data from the dataframe, load the image filename in directory as specified by the value of x_col, and use the corresponding row to build the targets, which in this case will be a numpy array of the values of columns in y_col. More information about this method can be found in the keras documentation.
Loading the entire data set in memory in an array is not a great idea because the memory consumption could go out of control, so you should use a generator. ImageDataGenerator and flow_from_dataframe are a great way of loading images in Keras. Since you don't want to use ImageDataGenerator(can you mention why?) you can create your own generator function that loads chunks of images in memory. If you load your data in a generator make sure you use fit_generator and predict_generator functions.
To load unlabeled data you can do the following hack:
datagen = ImageDataGenerator()
test_data = datagen.flow_from_directory('.', classes=['directory_where_images_are_stored'])
For more information check out link [1].
[1] https://kylewbanks.com/blog/loading-unlabeled-images-with-imagedatagenerator-flowfromdirectory-keras

Using matrices as input to convolutional neural network

I am trying to use a convolutional neural network to identify patterns in binary matrices and classify them to one of two classes. At the moment I have a bunch of 15x15 matrices in csv format.
In order to get a handle on how convolutional nets work I have been following sentdex's tutorials on youtube. In this he uses a conv net to classify the MNIST dataset. The code he uses to specify the input is like this:
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("/tmp/data/", one_hot = True)
x = tf.placeholder('float', [None, 784])
y = tf.placeholder('float')
My question is how do I set up a file like 'input_data' which the conv net can read my matrices and labels from? Can I include ALL of my training data in one file or do I need to split them into train/test files?
I have set up an excel file in the following format but not sure if it will work in the same way MNIST does.
input data example file:
My favorite tutorials are from aymericdamien, below is a link to the convolutional tutorial in jupyter (go back up a few directories in github for all of the tutorials).
https://github.com/aymericdamien/TensorFlow-Examples/blob/master/notebooks/3_NeuralNetworks/convolutional_network_raw.ipynb
You'll notice that their input is the same as what you have posted:
X = tf.placeholder(tf.float32, [None, num_input])
Y = tf.placeholder(tf.float32, [None, num_classes])
And the first thing they do in the conv_net() function is to reshape it to a image:
x = tf.reshape(x, shape=[-1, 28, 28, 1])
The shape arguments are understood as follows:
-1: variable batch size
28: height of the image (mnist is 28x28 grayscale images)
28: width of the image
1: color channels, grayscale images have 1 color channel, RGB images have 3 typically.
Try reshaping the image using numpy and displaying it yourself to check that you got it right:
import scipy.misc as misc
import numpy as np
img = np.reshape(flat_image, (28,28,1))
misc.imshow(img)
As far as train and test process goes, tensorflow doesn't care anything about your structure. I generally would separate the files to make sure you don't accidentally pass your test set to your training process though. You will ultimately need to call sess.run separately on your training and test datasets. I think the tutorial I linked to provides a very good example of this process, so if you have more specific questions I'll leave them to a future post.

Resources