diff --git a/ReadMe.md b/ReadMe.md new file mode 100644 index 0000000000000000000000000000000000000000..6889b26b983446b5d55e08317a034344c7e3e3f3 --- /dev/null +++ b/ReadMe.md @@ -0,0 +1,121 @@ +# Image classification + +Legrand Frédéric - Project for the Deep Learning Course at ECL + +# Usage + +To download and run the project, open a terminal in the desired folder and run these commands, they will: +- Download the project +- Enter the project folder +- Add the data folder in the project folder +- Install the necessary dependancies +- Enter test folder +- Test that the code is functionnal with pytest (All 8 tests should run without issues) + +``` +git clone https://gitlab.ec-lyon.fr/flegrand/image-classification.git +cd image-classification +pip install -r requirements.txt +cd tests +pytest +``` + +If all tests are succesful, the project has all the necessary dependancies and everything should run normally. + +# Description + +This section of the readme goes through all the code and explains it. + +## Prepare the CIFAR dataset + +All the code for this section is in the read_cifar.py file. +Unit tests have been created in tests/test_read_cifar.py +Running pytest in tests folder will provide proof that algorithms work as expected. + +### 1- + +Data folder contains the cifar-10-batches-py folder with the relevant data for the image classification. +We focus on the cifar image dataset. + +### 2- + +read_cifar_batch takes in a file path and returns the corresponding data and labels +We import the data as float32 values to be able to use numpy. +Since values are between 0 and 256 for the data and between 0-10 for the labels we can import the labels as int64. + +```rb +def read_cifar_batch(filePath: str): + with open(filePath, 'rb') as fo: + dict = pickle.load(fo, encoding='bytes') + return (np.array(dict[b'data']).astype('float64'), np.array(dict[b'labels']).astype('int64')) +``` + +### 3- + +read_cifar takes in a folder path and returns the corresponding data and labels by making use of the previous read_cifar_batch function. + +```rb +def read_cifar(folderPath: str): + data, labels = read_cifar_batch(folderPath+"/test_batch") + for i in range(1,6): + tempData, tempLabels = read_cifar_batch(folderPath+"/data_batch_"+str(i)) + labels = np.concatenate((labels,tempLabels), axis=0) + data = np.concatenate((data, tempData), axis=0) + return data, labels +``` + +### 4- + +split_dataset takes in some numpy array that represents the data, some corresponding labels and a split pourcentage. + +The function finds a random permutation of these values with np.random.shuffle. +We then mix both data and labels in the same way. + +We return the first elements so that we reach the split pourcentage we wanted. + +```rb +def split_dataset(data: np.array, labels: list, split: float): + if not 0 < split < 1: + raise ValueError('Split is not a float between 0 and 1') + + # Generate random indices for shuffling the data + num_samples = len(labels) + indices = np.arange(num_samples) + np.random.shuffle(indices) + + # Shuffle the data and labels using the random indices + shuffled_data = data[indices] + shuffled_labels = np.array(labels)[indices] + + # Calculate the split index based on the given split ratio + split_index = int(split * num_samples) + + # Split the data and labels into training and testing sets + data_train, data_test = shuffled_data[:split_index], shuffled_data[split_index:] + labels_train, labels_test = shuffled_labels[:split_index], shuffled_labels[split_index:] + + return data_train, data_test, labels_train, labels_test +``` + +## k-nearest neighbors + +All the code for this section is in the knn.py file. +Functions have unit tests in the tests folder +Running pytest in tests folder will provide proof that algorithms work as expected. + +### 1- + +distance_matrix takes in two matrices which represents pictures. +It returns the L2 Euclidian distance of each image in the first set to each image in the second set. + +Because of this the result is a numpy array of size: number_of_items_in_the_first_set * number_of_items_in_the_second_set + +```rb +def distance_matrix(matrix1 : np.array, matrix2 : np.array): + sum_of_squares_matrix1 = np.sum(np.square(matrix1), axis=1, keepdims=True) + sum_of_squares_matrix2 = np.sum(np.square(matrix2), axis=1, keepdims=True) + + dot_product = np.dot(matrix1, matrix2.T) + + dists = np.sqrt(sum_of_squares_matrix1 + sum_of_squares_matrix2.T - 2 * dot_product) + return dists