{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Classification of Galaxies According to their Structure(Morphology) using the Galaxy Zoo Project Dataset\n\n## Background\n\nGalaxy classification is fandamental when investigating properties of galaxies in statistical analysis in order to understand their evolution prosess. The galaxies are classified following the Hubble classifications as either spirals, ellipticals or irregulars if they do not fit in any of the previous classifications. Traditionally, galaxies are classified by visualy inspecting galaxy images. With the increase in the number of observed samples, visual classification is not only time consuming or labour intensive, but nearly imposible to classify large galaxy samples. Their is a need to automate the classifications that can replace the visual classifications with high accuracy . \n\nThe Galaxy Zoo Project 2 classfied around 200,000 galaxy images obtained from the Sloan Digital Sky Survey (SDSS), DR7 and other similar surveys. The images are classified into respective categories (37) following a set of 11 questions with the help of the public (citizen scientist).\n\nThe project will use the Galaxy Zoo dataset from kaggle consisting of 61,578 galaxy images in the training dataset and 79,973 images for the test dataset.","metadata":{"id":"Ftad4UBF6JUt"}},{"cell_type":"markdown","source":"### Overview\n\nThe main aim of this project is to build a model that can automate the galaxy classification in to two main categories (spirals and ellipticals) with very high accuracy.\n\nThis notebook contain the following sections,\n- Data Exploration\n- Selection Method\n- Data Preprocessing\n- Methodology\n- Model Training \n- Model Visualization\n- Conclusions and Recommendations\n\n\n\n## Exploring and Understanding the Dataset\n\nWhile the traing dataset contain 61,578 images, the training_solution_rev1.csv file has the information regarding the probablities of a galaxies belonging to the respective classes. From the 37 classes, the main categories of interest are classes 1.1 and 1.2. Based on the first classification question, class 1.1 give the probability of a galaxy being smooth (elliptical) and class 1.2 gives the probability of it having features or disk(spirals). \n\nFor a more clean sample, we will use the images classified with a more than 0.8 probability as belonging to the two classes and labeling then appropriatly. Out of all the traing dataset images, only 24,273 satisfied our requement (>= 0.8 probability in either class 1.1 or 1.2). We separated the data that satisfied our requarements into a new dataframe. When inspecting the new dataframe, no duplicates or missing values were found.\n","metadata":{"id":"klhj05kk7DqI"}},{"cell_type":"code","source":"#importing required libraries for data exploration\nimport pandas as pd\nimport numpy as np","metadata":{"id":"TGRwSYr7-72m","execution":{"iopub.status.busy":"2023-06-21T00:24:45.624110Z","iopub.execute_input":"2023-06-21T00:24:45.624396Z","iopub.status.idle":"2023-06-21T00:24:45.656876Z","shell.execute_reply.started":"2023-06-21T00:24:45.624313Z","shell.execute_reply":"2023-06-21T00:24:45.656177Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#reading the training csv file and displaying the first 5 row \n#to have a better understanding of the classes\ndata = pd.read_csv(\"../input/galaxy-zoo-the-galaxy-challenge/training_solutions_rev1.zip\",\n                   compression=\"zip\")\n\n#data = pd.read_csv('training_solutions_rev1.csv')\ndata.head(5)","metadata":{"id":"jQmhuGCuCx0s","outputId":"3e7e1d58-fd0e-4505-f435-965c4ebe40eb","execution":{"iopub.status.busy":"2023-06-21T00:24:45.658594Z","iopub.execute_input":"2023-06-21T00:24:45.658881Z","iopub.status.idle":"2023-06-21T00:24:46.202595Z","shell.execute_reply.started":"2023-06-21T00:24:45.658843Z","shell.execute_reply":"2023-06-21T00:24:46.201585Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#looking for the number of rows and colunm in the dataframe\ndata.shape","metadata":{"id":"oKrXhjE2EHv5","outputId":"4c4dcb76-117e-4783-c103-0e2d5c76a2ea","execution":{"iopub.status.busy":"2023-06-21T00:24:46.204054Z","iopub.execute_input":"2023-06-21T00:24:46.204481Z","iopub.status.idle":"2023-06-21T00:24:46.211787Z","shell.execute_reply.started":"2023-06-21T00:24:46.204433Z","shell.execute_reply":"2023-06-21T00:24:46.210756Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We define a fuction that will be used to add the image type extection to the GalaxyID. Since our images are 'jpg', we will use this extection in the defined fuction. The function is then used to add the extection on the dataframe colunm GalaxyID.","metadata":{"id":"7G5AJJnzFUzz"}},{"cell_type":"code","source":"#definig a function to add image extections to the GalaxyID\n#adding the image extections to the GalaxyID\n\ndef append_ext(filename):\n    \"\"\" Appends `.jpg` file extension to a filename \"\"\"\n    return f\"{filename}.jpg\"\n    #return filename + '.jpg'\n\n#applying the function to the GalaxyID colunm\ndata[\"GalaxyID\"] = data[\"GalaxyID\"].apply(append_ext)\n\n#printing the first five row of the dataframe to view the changes\ndata.head(5)","metadata":{"id":"XuielA_JFMB1","outputId":"5b51b47c-62f3-4d3f-dcd2-55004723dcc6","execution":{"iopub.status.busy":"2023-06-21T00:24:46.214476Z","iopub.execute_input":"2023-06-21T00:24:46.215052Z","iopub.status.idle":"2023-06-21T00:24:46.279070Z","shell.execute_reply.started":"2023-06-21T00:24:46.215010Z","shell.execute_reply":"2023-06-21T00:24:46.277958Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#creating a new dataframe with galaxies having a probability of 0.8 in either class1.1 \n#or class1.2\nnew_data = data[((data[\"Class1.1\"] >= .8) | (data[\"Class1.2\"] >= .8))].reset_index(drop=True)\nprint(new_data.shape)\nnew_data.head(5)","metadata":{"id":"ANU9ap9DF55S","outputId":"5ed6aa46-bf6d-457d-9359-1d8b9a9edbdb","execution":{"iopub.status.busy":"2023-06-21T00:24:46.280617Z","iopub.execute_input":"2023-06-21T00:24:46.280878Z","iopub.status.idle":"2023-06-21T00:24:46.321973Z","shell.execute_reply.started":"2023-06-21T00:24:46.280844Z","shell.execute_reply":"2023-06-21T00:24:46.321024Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#looking for duplicate data\nnew_data.drop_duplicates(inplace=True)\nnew_data.shape\n\n#the are no duplicate images in the dataset\n","metadata":{"id":"e01VJuMyGF5c","outputId":"23ccb2bd-a810-4969-e80b-a1e1a52db3f8","execution":{"iopub.status.busy":"2023-06-21T00:24:46.323630Z","iopub.execute_input":"2023-06-21T00:24:46.323912Z","iopub.status.idle":"2023-06-21T00:24:46.390763Z","shell.execute_reply.started":"2023-06-21T00:24:46.323874Z","shell.execute_reply":"2023-06-21T00:24:46.389856Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#inspecting missing data\nnew_data.isnull().sum().sum()","metadata":{"id":"IkNM5NDjGfFX","outputId":"1419e17d-936a-411c-d0e4-15244fd32d14","execution":{"iopub.status.busy":"2023-06-21T00:24:46.392265Z","iopub.execute_input":"2023-06-21T00:24:46.392553Z","iopub.status.idle":"2023-06-21T00:24:46.405906Z","shell.execute_reply.started":"2023-06-21T00:24:46.392515Z","shell.execute_reply":"2023-06-21T00:24:46.404227Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#adding a new colunm with labels for the galaxies with probability greater than 0.8.\n#we label those in class1.1 as ellipticals and those in class1.2 as spirals\n\n#define conditions\nconditions = [new_data[\"Class1.1\"] >= 0.8, \n              new_data[\"Class1.2\"] >= 0.8]\n\n#define choices\nchoices = [\"elliptical\", \"spiral\"]\n\n#create new column in DataFrame that displays results of comparisons\nnew_data[\"class\"] = np.select(conditions, choices, default=\"Tie\")\n\nnew_data","metadata":{"id":"u_A5kXrMGr1-","outputId":"ee5036dd-0eb9-4d6a-aa3e-1977795ce809","execution":{"iopub.status.busy":"2023-06-21T00:24:46.407690Z","iopub.execute_input":"2023-06-21T00:24:46.407917Z","iopub.status.idle":"2023-06-21T00:24:46.459029Z","shell.execute_reply.started":"2023-06-21T00:24:46.407888Z","shell.execute_reply":"2023-06-21T00:24:46.458039Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Exploring the distributing of the new dataframe\nprint(new_data[new_data[\"class\"] == \"elliptical\"].shape)\n\nprint(new_data[new_data[\"class\"] == \"spiral\"].shape)","metadata":{"id":"ImhdmpI8G18D","outputId":"6a038311-da2c-4f88-e81d-ab919a6c0951","execution":{"iopub.status.busy":"2023-06-21T00:24:46.462067Z","iopub.execute_input":"2023-06-21T00:24:46.462409Z","iopub.status.idle":"2023-06-21T00:24:46.486321Z","shell.execute_reply.started":"2023-06-21T00:24:46.462372Z","shell.execute_reply":"2023-06-21T00:24:46.485560Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Selection Method\nFrom the new dataframe with elliptical and spiral labels (24,273), we have 8,132 elliptical galaxy images and 16,141 spirals. Since our main interest is on the model accuracy, it is important to balance the number of sample used from both classes to prevent the model from learning to classify only one class. To balance the training dataset, we selected 8000 random samples from each of the two categories. However we first copied a small sample of our data, 500 images from each of the two class, to a new folder for visual inspection. This sample was later manually cropped and used for the Minimum Valuable Product (MVP).\n\nWe at some point considered the inclusion of a few antifacts to improve model traing in identifing what is not a spiral or elliptical galaxy. The antifacts category corresponds to Class 1.3. However, this was not included in the final product.","metadata":{"id":"lBMRFccqHHOP"}},{"cell_type":"code","source":"#sort the main data by class 1.3 (artifacts/stars)\ndata.sort_values(\"Class1.3\", \n                 ascending=False,\n                 inplace=True)\ndata.head(10)","metadata":{"id":"J2yBHOuCs118","outputId":"f29d41dd-36cc-44d0-ce6f-c098b17e3a5a","execution":{"iopub.status.busy":"2023-06-21T00:24:46.487479Z","iopub.execute_input":"2023-06-21T00:24:46.487977Z","iopub.status.idle":"2023-06-21T00:24:46.553251Z","shell.execute_reply.started":"2023-06-21T00:24:46.487938Z","shell.execute_reply":"2023-06-21T00:24:46.552474Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Stars/Artifacts classifed with a percentage fraction of 0.8 are only 2. Those with a percentage fraction of 0.6 are 24 and 44 have a fraction of 0.5. It would have been important to visually inspect this subset of objects to ensure they a trully antifacts and will not mislead the model.","metadata":{"id":"EzqenfTCtFU_"}},{"cell_type":"code","source":"#printing out samples of antifacts based on specified selections\n\ndata[data[\"Class1.3\"] >= .8 ].shape #only 2\n# data[data[\"Class1.3\"] >= .6 ].shape # 24\n# data[data[\"Class1.3\"] >= .5 ].shape #44","metadata":{"id":"54BCkz2Qthtk","outputId":"e91a4932-b135-4bd2-bef0-5ad8f3624b47","execution":{"iopub.status.busy":"2023-06-21T00:24:46.554408Z","iopub.execute_input":"2023-06-21T00:24:46.555017Z","iopub.status.idle":"2023-06-21T00:24:46.563349Z","shell.execute_reply.started":"2023-06-21T00:24:46.554973Z","shell.execute_reply":"2023-06-21T00:24:46.562449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#dataframe for the artifacts/stars\ndf_antifacts = data[data[\"Class1.3\"] >= .5 ]\ndf_antifacts.shape","metadata":{"id":"5NVl6uiEuPgk","outputId":"ed07ecaf-ebcb-46ec-d375-d51ac67f486d","execution":{"iopub.status.busy":"2023-06-21T00:24:46.564764Z","iopub.execute_input":"2023-06-21T00:24:46.565369Z","iopub.status.idle":"2023-06-21T00:24:46.574159Z","shell.execute_reply.started":"2023-06-21T00:24:46.565326Z","shell.execute_reply":"2023-06-21T00:24:46.573265Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data Preprocessing\n\nSince our model was to mainly classify the spirals and the elliptical galaxy images, we procceded with the selection and preprocessing stage in preparation for model training. For the MVP, only 1000 galaxy samples were selected (500 for both the spiral and elliptical galaxaies). We copied the images into a folder in the local machine for visual verification and cropping with the code below.\n\nFor the final product a total of 16,000 images were randomly selected as a subset of the filtered data.","metadata":{"id":"rZ3Vas4ouhH6"}},{"cell_type":"code","source":"# randomly selecting 500 samples in each category for the mvp and \n# saving it in to a new dataframe\ndf_spiral_new = new_data[new_data[\"class\"] == \"spiral\"].sample(n=500)\nprint(\"This is a sample of spiral galaxies\")\nprint(df_spiral_new.head(5))\nprint(df_spiral_new.shape)\n\ndf_elliptical_new =new_data[new_data[\"class\"] == \"elliptical\"].sample(n=500)\nprint(\"And this is a sample of elliptical galaxies\")\nprint(df_elliptical_new.head(5))\nprint(df_elliptical_new.shape)","metadata":{"id":"o52t6RHUsohB","outputId":"5739c01c-9704-4581-9d77-e7c3e71e8497","execution":{"iopub.status.busy":"2023-06-21T00:24:46.575890Z","iopub.execute_input":"2023-06-21T00:24:46.576476Z","iopub.status.idle":"2023-06-21T00:24:46.623630Z","shell.execute_reply.started":"2023-06-21T00:24:46.576436Z","shell.execute_reply":"2023-06-21T00:24:46.622930Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The cell below was previously used to copy images based on a dataframe into diffent folders for the mvp model training. We created new directories for the defferent categories, defined the source and destination directories and finally looped over your desired files from the dataframe and copying the content of the source directiry to the desired destination.","metadata":{}},{"cell_type":"code","source":"# # importing shutil module\n# import os\n# from shutil import copyfile\n\n# #creating new directories for the defferent categories\n# os. mkdir(\"/home/marcelina/Desktop/DSI/project/data/spirals\") \n# os. mkdir(\"/home/marcelina/Desktop/DSI/project/data/ellipticals\") \n\n# # define your source and destination directories\n# #spriral\n# source_directory1 = \"/home/marcelina/Desktop/DSI/project/images_training_rev1\"\n# destination_directory1 = \"/home/marcelina/Desktop/DSI/project/data/spirals\"\n# #elliptical\n# # source_directory2 = \"/home/marcelina/Desktop/DSI/project/images_training_rev1\"\n# destination_directory2 = \"/home/marcelina/Desktop/DSI/project/data/ellipticals\"\n\n\n# # loop over your desired files from the dataframe to copy them\n# # Copy the content of source to destination\n# for fileName in df_spiral_new[\"GalaxyID\"]: \n#     source_file1 = source_directory1 + \"/\" + fileName \n#     destination_file1 = destination_directory1 + \"/\" + fileName\n#     #copyfile(source_file1, destination_file1)\n\n\n# for fileName in df_elliptical_new[\"GalaxyID\"]: \n#     source_file2 = source_directory2 + \"/\" + fileName \n#     destination_file2 = destination_directory2 + \"/\" + fileName\n#     #copyfile(source_file2, destination_file2)\n","metadata":{"id":"oxgKovlOsuUJ","execution":{"iopub.status.busy":"2023-06-21T00:24:46.624920Z","iopub.execute_input":"2023-06-21T00:24:46.625365Z","iopub.status.idle":"2023-06-21T00:24:46.630578Z","shell.execute_reply.started":"2023-06-21T00:24:46.625328Z","shell.execute_reply":"2023-06-21T00:24:46.629575Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Preprocessing for the final product","metadata":{"id":"e8b7xJIJ0g2H"}},{"cell_type":"code","source":"# selecting equal number of spiral\n# and elliptical galaxies\n# randomly selecting 8,000 samples in each categiry\ndf_spiral = new_data[new_data[\"class\"] == \"spiral\"].sample(n=8000,random_state = 42)\nprint(\"This is a sample of spiral galaxies\")\nprint(df_spiral.head(5))\nprint(df_spiral.shape)\n\ndf_elliptical =new_data[new_data[\"class\"] == \"elliptical\"].sample(n=8000,random_state = 42)\nprint(\"And this is a sample of elliptical galaxies\")\nprint(df_elliptical.head(5))\nprint(df_elliptical.shape)","metadata":{"id":"GFEg6syXHE3n","outputId":"0843138a-fea4-4a6e-bc5b-0eb4729d1750","execution":{"iopub.status.busy":"2023-06-21T00:24:46.631955Z","iopub.execute_input":"2023-06-21T00:24:46.632666Z","iopub.status.idle":"2023-06-21T00:24:46.686410Z","shell.execute_reply.started":"2023-06-21T00:24:46.632623Z","shell.execute_reply":"2023-06-21T00:24:46.685661Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#merging the two dataframes together to make the traing dataframe\n#sellecting only the galaxyid and classes columns\nframes = [df_spiral, df_elliptical]\ndf_galaxies = pd.concat(frames)\ndf_galaxies = df_galaxies[[\"GalaxyID\", \"class\"]]\ndf_galaxies.head(5)","metadata":{"id":"jNq75D1VIinV","outputId":"fd4c0713-99f9-4eca-de32-b3556c0e88ff","execution":{"iopub.status.busy":"2023-06-21T00:24:46.687770Z","iopub.execute_input":"2023-06-21T00:24:46.688260Z","iopub.status.idle":"2023-06-21T00:24:46.707468Z","shell.execute_reply.started":"2023-06-21T00:24:46.688217Z","shell.execute_reply":"2023-06-21T00:24:46.706569Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# printing the shape of the final dataframe\ndf_galaxies.shape","metadata":{"id":"KXPAVkKgsjb9","outputId":"e5eb4aee-4bdc-449b-c3a3-56ebe7dd3a54","execution":{"iopub.status.busy":"2023-06-21T00:24:46.709248Z","iopub.execute_input":"2023-06-21T00:24:46.709548Z","iopub.status.idle":"2023-06-21T00:24:46.715430Z","shell.execute_reply.started":"2023-06-21T00:24:46.709510Z","shell.execute_reply":"2023-06-21T00:24:46.714445Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#unziping the test image folder\nimport zipfile\nwith zipfile.ZipFile(\"../input/galaxy-zoo-the-galaxy-challenge/images_training_rev1.zip\", 'r') as zip_ref:\n    zip_ref.extractall()","metadata":{"execution":{"iopub.status.busy":"2023-06-21T00:24:46.717277Z","iopub.execute_input":"2023-06-21T00:24:46.717642Z","iopub.status.idle":"2023-06-21T00:25:10.314150Z","shell.execute_reply.started":"2023-06-21T00:24:46.717597Z","shell.execute_reply":"2023-06-21T00:25:10.313343Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# visualing one of the images and the image size\nfrom tensorflow.keras.preprocessing import image\nimport matplotlib.pyplot as plt\n\n#images\nimg= image.load_img(\"./images_training_rev1/104934.jpg\")\nimg2 = image.load_img(\"./images_training_rev1/582003.jpg\")\n\n#Subplots\nplt.figure(figsize=(12,4.5))\nplt.subplot(141)\nplt.imshow(img)\nplt.title(\"Spiral Galaxy\", y=1.02, fontsize=12)\n\nplt.subplot(142)\nplt.imshow(img2)\nplt.title(\"Elliptical Galaxy\", y=1.02, fontsize=12)\n\n;","metadata":{"execution":{"iopub.status.busy":"2023-06-21T00:25:10.315742Z","iopub.execute_input":"2023-06-21T00:25:10.316015Z","iopub.status.idle":"2023-06-21T00:25:17.305822Z","shell.execute_reply.started":"2023-06-21T00:25:10.315976Z","shell.execute_reply":"2023-06-21T00:25:17.305045Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\n\nprint(\"The images are of size: \")\ncv2.imread(\"./images_training_rev1/104934.jpg\").shape\n\n#the images have the shape 424,424,3","metadata":{"execution":{"iopub.status.busy":"2023-06-21T00:25:17.306851Z","iopub.execute_input":"2023-06-21T00:25:17.307391Z","iopub.status.idle":"2023-06-21T00:25:17.544162Z","shell.execute_reply.started":"2023-06-21T00:25:17.307330Z","shell.execute_reply":"2023-06-21T00:25:17.543402Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Methodology\nFor the mvp, the 1000 cropped images were used to train the model while trying both gray scale and the RGB scale. The models trained with the RGB scale performed better which showed the importance of colour in galaxy classifcations. Unfortunately, it was harder to get a good performance with such a small sample. We later included the earlier selected sample of 16,000 galaxies in RGB colour as the training sample and tried optimizing on the number of layers, filters and other parameters to improve the model performance.\n\nTo prepare the data for model training we used the ImageDataGenerator and the training dataframe for the image id and the class columns to lable the images. We resized the image size to 212 x 212, used the RGB colour and a batch_size of 32. The training (80%) and the validation (20%) datasets were separated by the 80-20 rule. We randomly shuffled the images so that the model will not learn to classfy one category more. The elliptical galaxies have the zero lable (0) while the spiral galaxies have the one (1).\n\nThe model that gave us an optimum performance was a cnn model with seven layers which include an input layer, three fully connected layers and the final three dense layers with relu activation functions for all layers as shown in the model summary. We used the categorical_crossentropy loss function, Adam optimizer with a learning rate of 0.001 and measured the accuracy. Checkpoints and early stoppings where used to prevent the model from overfitting and only saving the best model.","metadata":{}},{"cell_type":"markdown","source":"## Model Training","metadata":{"id":"3ppBLYLr4vj5"}},{"cell_type":"code","source":"#importing libraries for data visualization and model training\n\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.optimizers import Adam, RMSprop\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras.callbacks import ModelCheckpoint\nfrom tensorflow.keras.callbacks import EarlyStopping\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nimport cv2\n\nimport tensorflow.keras.backend as K\nfrom tensorflow.keras.applications.inception_v3 import preprocess_input\n\nimport numpy as np\nimport os\n#from google.colab.patches import cv2_imshow # cv2.imshow does not work on \n#Google Colab notebooks, which is why we are using cv2_imshow instead","metadata":{"id":"72scQUkG4BzY","execution":{"iopub.status.busy":"2023-06-21T00:25:17.545745Z","iopub.execute_input":"2023-06-21T00:25:17.546270Z","iopub.status.idle":"2023-06-21T00:25:17.556970Z","shell.execute_reply.started":"2023-06-21T00:25:17.546227Z","shell.execute_reply":"2023-06-21T00:25:17.556222Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ImageDataGenerator??","metadata":{"execution":{"iopub.status.busy":"2023-06-21T00:25:17.558552Z","iopub.execute_input":"2023-06-21T00:25:17.558876Z","iopub.status.idle":"2023-06-21T00:25:17.568752Z","shell.execute_reply.started":"2023-06-21T00:25:17.558835Z","shell.execute_reply":"2023-06-21T00:25:17.567937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Using the ImageDataGenerator to prepare the data for training\ndatagen = ImageDataGenerator(rescale=1./255.,\n                           validation_split=0.2,\n\n)\n\n\ntrain_generator = datagen.flow_from_dataframe(dataframe = df_galaxies,\n                                          target_size = (212,212),\n                                          directory = \"./images_training_rev1\",\n                                          batch_size = 32,\n                                          x_col=\"GalaxyID\",\n                                          y_col=\"class\",\n                                          color_mode=\"rgb\",\n                                          class_mode=\"categorical\",\n                                          subset=\"training\",\n                                          shuffle=True,\n                                          seed=42\n                                         )\nvalid_generator = datagen.flow_from_dataframe(dataframe = df_galaxies,\n                                            target_size=(212, 212),\n                                            directory = \"./images_training_rev1\",\n                                            batch_size=32,\n                                            x_col=\"GalaxyID\",\n                                            y_col=\"class\",\n                                            color_mode=\"rgb\",\n                                            class_mode=\"categorical\",\n                                            subset=\"validation\",\n                                            shuffle=True,\n                                            seed=42\n                                           )                                        ","metadata":{"id":"NjchTKv-5pqU","outputId":"1739c807-cd01-4bf3-eb81-5600e9ec340a","execution":{"iopub.status.busy":"2023-06-21T00:25:17.569961Z","iopub.execute_input":"2023-06-21T00:25:17.570688Z","iopub.status.idle":"2023-06-21T00:25:17.909229Z","shell.execute_reply.started":"2023-06-21T00:25:17.570638Z","shell.execute_reply":"2023-06-21T00:25:17.908413Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n#printing the generated class and the index class\ntrain_generator.class_indices","metadata":{"id":"vaolewMx7mqC","execution":{"iopub.status.busy":"2023-06-21T00:25:17.913855Z","iopub.execute_input":"2023-06-21T00:25:17.914638Z","iopub.status.idle":"2023-06-21T00:25:17.920706Z","shell.execute_reply.started":"2023-06-21T00:25:17.914596Z","shell.execute_reply":"2023-06-21T00:25:17.919850Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#the cnn model architecture\nmodel = tf.keras.models.Sequential([tf.keras.layers.Conv2D(16,(6,6),activation = 'relu',\n                                                           input_shape=(212,212,3)),\n                                  #tf.keras.layers.BatchNormalization(),\n                                  tf.keras.layers.MaxPool2D(2,2),\n                                  #tf.keras.layers.Dropout(0.1),\n                                    \n                                  #\n                                  tf.keras.layers.Conv2D(32,(5,5),activation = 'relu'),\n                                  #tf.keras.layers.BatchNormalization(),\n                                  tf.keras.layers.MaxPool2D(2,2),\n                                  tf.keras.layers.Dropout(0.1),\n                                    \n                                  #\n                                  tf.keras.layers.Conv2D(64,(3,3),activation = 'relu'),\n                                  #tf.keras.layers.BatchNormalization(),\n                                  tf.keras.layers.MaxPool2D(2,2),\n                                  #tf.keras.layers.Dropout(0.1),\n                                    \n                                  #\n                                  tf.keras.layers.Conv2D(128,(3,3),activation = 'relu'),\n                                  #tf.keras.layers.BatchNormalization(),\n                                  tf.keras.layers.MaxPool2D(2,2),\n                                  tf.keras.layers.Dropout(0.1),\n                                    \n                                  #\n                                  tf.keras.layers.Flatten(),\n                                  \n                                  #\n                                  tf.keras.layers.Dense(512, activation='relu'),\n                                  #tf.keras.layers.Dropout(0.1),\n                                    \n                                  tf.keras.layers.Dense(256, activation='relu'),\n                                  #tf.keras.layers.Dropout(0.1),\n                                    \n                                   #\n                                  tf.keras.layers.Dense(2, activation='softmax')\n                                  ])","metadata":{"id":"ji2aGoCv7323","execution":{"iopub.status.busy":"2023-06-21T00:25:17.922435Z","iopub.execute_input":"2023-06-21T00:25:17.922878Z","iopub.status.idle":"2023-06-21T00:25:22.356450Z","shell.execute_reply.started":"2023-06-21T00:25:17.922837Z","shell.execute_reply":"2023-06-21T00:25:22.354829Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#printing and saving the model summary and architecture\nsummary = model.summary()\ntf.keras.utils.plot_model(model, to_file=\"model_plot3.png\", \n                          show_shapes=True, show_layer_names=True)","metadata":{"id":"Um9NVtXg7-N3","execution":{"iopub.status.busy":"2023-06-21T00:25:22.357962Z","iopub.execute_input":"2023-06-21T00:25:22.358249Z","iopub.status.idle":"2023-06-21T00:25:23.504297Z","shell.execute_reply.started":"2023-06-21T00:25:22.358209Z","shell.execute_reply":"2023-06-21T00:25:23.503454Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#creating a checkpoint to save the best model\ncheckpoint = ModelCheckpoint(\"best_model3.h5\", \n                             monitor = \"val_loss\",\n                             verbose = 0, \n                             save_best_only = True, \n                             mode = \"auto\")\n#Specifying an earlystopping to avoid overfitting\nstopping = EarlyStopping(monitor = \"val_loss\",\n                         patience = 10,#after this many epochs,stop the model training\n                         verbose = 0,\n                         mode = \"auto\")","metadata":{"id":"a0pwcYX_8M6q","execution":{"iopub.status.busy":"2023-06-21T00:25:23.506096Z","iopub.execute_input":"2023-06-21T00:25:23.510686Z","iopub.status.idle":"2023-06-21T00:25:23.516230Z","shell.execute_reply.started":"2023-06-21T00:25:23.510648Z","shell.execute_reply":"2023-06-21T00:25:23.515389Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#compliling the model \nmodel.compile(\nloss=\"categorical_crossentropy\",\noptimizer=Adam(learning_rate=0.001),\nmetrics=[\"accuracy\"])\n","metadata":{"id":"oH_qECAA8SIf","execution":{"iopub.status.busy":"2023-06-21T00:25:23.517950Z","iopub.execute_input":"2023-06-21T00:25:23.518223Z","iopub.status.idle":"2023-06-21T00:25:23.539714Z","shell.execute_reply.started":"2023-06-21T00:25:23.518188Z","shell.execute_reply":"2023-06-21T00:25:23.538832Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# model fitting\nhist = model.fit(train_generator, epochs = 10, validation_data=valid_generator, \n                callbacks = [checkpoint, stopping])\n\n# epochs=30\n\n#To avoid retraing the model again, we will upload the downloded model \n#loadig the trained model\n# model = tf.keras.models.load_model(\"../input/mymodel/best_model3.h5\")","metadata":{"id":"ZUuIBzcC8WiT","execution":{"iopub.status.busy":"2023-06-21T00:25:23.543112Z","iopub.execute_input":"2023-06-21T00:25:23.543344Z","iopub.status.idle":"2023-06-21T00:36:00.046227Z","shell.execute_reply.started":"2023-06-21T00:25:23.543317Z","shell.execute_reply":"2023-06-21T00:36:00.045330Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The code below was used to plot the training history that has been displayed as an image in the cell after.","metadata":{}},{"cell_type":"code","source":"#creating subplots for traing plots\nfig, axes = plt.subplots(1, 2, figsize=(12,6))\n\n# summarize history for accuracy\naxes[0].plot(hist.history['accuracy'])\naxes[0].plot(hist.history['val_accuracy'])\naxes[0].set_ylabel('accuracy')\naxes[0].set_xlabel('epoch')\naxes[0].legend(['train', 'test'], loc='upper left')\n\n\n# summarize history for loss\naxes[1].plot(hist.history['loss'])\naxes[1].plot(hist.history['val_loss'])\naxes[1].set_ylabel('loss')\naxes[1].set_xlabel('epoch')\naxes[1].legend(['train', 'test'], loc='upper left')\n\n# fig.title('Model Accuracy')\n\nplt.savefig('model_Accuracy_plot.png')\nplt.show()\n","metadata":{"id":"uKhdbSvv8fQB","execution":{"iopub.status.busy":"2023-06-21T00:36:32.298948Z","iopub.execute_input":"2023-06-21T00:36:32.299255Z","iopub.status.idle":"2023-06-21T00:36:32.752206Z","shell.execute_reply.started":"2023-06-21T00:36:32.299216Z","shell.execute_reply":"2023-06-21T00:36:32.751220Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# #seens the model is now preloaded we will plot\n# img3= image.load_img(\"../input/the-model-training-graph/Screenshot from 2022-05-09 12-34-35.png\")\n# plt.figure(figsize=(20,10))\n# plt.imshow(img3)","metadata":{"execution":{"iopub.status.busy":"2023-06-21T00:41:41.034364Z","iopub.execute_input":"2023-06-21T00:41:41.035071Z","iopub.status.idle":"2023-06-21T00:41:41.039001Z","shell.execute_reply.started":"2023-06-21T00:41:41.035026Z","shell.execute_reply":"2023-06-21T00:41:41.038194Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# #getting a link to dowmload the the model and the plots \nos.chdir(r\"../working\")\n# from IPython.display import FileLink\n\n# FileLink(r\"model_Accuracy_plot.png\")\n\n# FileLink(r\"model_plot3.png\")\n\n# FileLink(r\"best_model3.h5\")\n         \n","metadata":{"execution":{"iopub.status.busy":"2023-06-21T00:41:42.433705Z","iopub.execute_input":"2023-06-21T00:41:42.433992Z","iopub.status.idle":"2023-06-21T00:41:42.438289Z","shell.execute_reply.started":"2023-06-21T00:41:42.433959Z","shell.execute_reply":"2023-06-21T00:41:42.437487Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Testing the model with a new dataset not used in training","metadata":{"id":"5qHm8rPi8zaZ"}},{"cell_type":"code","source":"#Trying to obtain the rows that were not in the traing set \n#for final testing of our trained model\n\n# we start by appening the traing datast in the whole dataframe \n#for spirals and elliptical galaxies \ndf_spiral_all = new_data.append(df_spiral)\ndf_all = df_spiral_all.append(df_elliptical)\n\n#drop rows which contain duplicates, Drop all duplicates.\ndf_test_all = df_all.drop_duplicates(keep=False)\ndf_test_all.shape\n","metadata":{"id":"3V4Fyii58u3j","execution":{"iopub.status.busy":"2023-06-21T00:41:48.565742Z","iopub.execute_input":"2023-06-21T00:41:48.566023Z","iopub.status.idle":"2023-06-21T00:41:48.659484Z","shell.execute_reply.started":"2023-06-21T00:41:48.565992Z","shell.execute_reply":"2023-06-21T00:41:48.658575Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# printing the shape of the dataframe for the specific categories\nprint(df_test_all[df_test_all[\"class\"] == \"spiral\"].shape)\nprint(df_test_all[df_test_all[\"class\"] == \"elliptical\"].shape)","metadata":{"id":"ETKloqvq9Xk3","execution":{"iopub.status.busy":"2023-06-21T00:41:50.945818Z","iopub.execute_input":"2023-06-21T00:41:50.946815Z","iopub.status.idle":"2023-06-21T00:41:50.960911Z","shell.execute_reply.started":"2023-06-21T00:41:50.946761Z","shell.execute_reply":"2023-06-21T00:41:50.959998Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Preparing an equal sample of text data for the model\ndf_spiral_test = df_test_all[df_test_all[\"class\"] == \"spiral\"].sample(n=130,\n                                                                      random_state = 42)\n#\ndf_elliptical_test = df_test_all[df_test_all[\"class\"] == \"elliptical\"].sample(\n    n=130, random_state = 42)\n\n#merging the two dataframes together to make the testing dataframe\n#sellecting only the galaxyid and classes colunms\nframe = [df_spiral_test, df_elliptical_test]\ndf_test_new = pd.concat(frame)\ndf_test_new = df_test_new[[\"GalaxyID\", \"class\"]]\ndf_test_new.shape\n","metadata":{"id":"TM9k-8W1-APM","execution":{"iopub.status.busy":"2023-06-21T00:42:09.027958Z","iopub.execute_input":"2023-06-21T00:42:09.028269Z","iopub.status.idle":"2023-06-21T00:42:09.048969Z","shell.execute_reply.started":"2023-06-21T00:42:09.028235Z","shell.execute_reply":"2023-06-21T00:42:09.048123Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#labling the test images with ImageDataGenerator\ndatagen=ImageDataGenerator(rescale=1./255.,\n                           )\n\ntest_generator = datagen.flow_from_dataframe(dataframe = df_test_new,\n                                          target_size = (212,212),\n                                          directory = \"./images_training_rev1\",\n                                          batch_size = 32,\n                                          x_col=\"GalaxyID\",\n                                          y_col=\"class\",\n                                          color_mode='rgb',\n                                          class_mode='categorical',\n                                          shuffle=True,\n                                          seed=42)","metadata":{"id":"qE7jccax-Isw","execution":{"iopub.status.busy":"2023-06-21T00:43:04.545927Z","iopub.execute_input":"2023-06-21T00:43:04.546265Z","iopub.status.idle":"2023-06-21T00:43:04.564103Z","shell.execute_reply.started":"2023-06-21T00:43:04.546227Z","shell.execute_reply":"2023-06-21T00:43:04.563200Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Printing the loss value and the accuracy for the evaluation with test data\nscore = model.evaluate(test_generator, verbose=0)\nprint(\"Test loss:\", score[0])\nprint(\"Test accuracy:\", score[1])\n","metadata":{"id":"CnwAXnQo-Qp2","execution":{"iopub.status.busy":"2023-06-21T00:43:16.020859Z","iopub.execute_input":"2023-06-21T00:43:16.021148Z","iopub.status.idle":"2023-06-21T00:43:17.166874Z","shell.execute_reply.started":"2023-06-21T00:43:16.021118Z","shell.execute_reply":"2023-06-21T00:43:17.165205Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model Visualization","metadata":{"id":"fNXn1Q5y4fq3"}},{"cell_type":"code","source":"# printing the sumary \nmodel.summary()","metadata":{"id":"zMuZGQZze3vx","outputId":"fd63408a-85a3-4567-a8bc-c78a2e5f0e64","execution":{"iopub.status.busy":"2023-06-21T00:44:31.386910Z","iopub.execute_input":"2023-06-21T00:44:31.387230Z","iopub.status.idle":"2023-06-21T00:44:31.400347Z","shell.execute_reply.started":"2023-06-21T00:44:31.387177Z","shell.execute_reply":"2023-06-21T00:44:31.399481Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Visualizing a disc like spiral galaxies","metadata":{}},{"cell_type":"code","source":"# uploading an image for prediction\nimg_upload = \"/kaggle/input/demospiral/spiral.jpg\"\n\nimg = image.load_img(img_upload, target_size=(212, 212))\n# img.size\nplt.imshow(cv2.imread(img_upload));# Visualize image","metadata":{"id":"mGag_p7VhJj1","outputId":"a884e994-c39c-4c95-a529-e33e6c07c7a9","execution":{"iopub.status.busy":"2023-06-21T01:06:08.364954Z","iopub.execute_input":"2023-06-21T01:06:08.365245Z","iopub.status.idle":"2023-06-21T01:06:09.223341Z","shell.execute_reply.started":"2023-06-21T01:06:08.365214Z","shell.execute_reply":"2023-06-21T01:06:09.222467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# image.load_img??","metadata":{"execution":{"iopub.status.busy":"2023-06-21T01:10:09.912494Z","iopub.execute_input":"2023-06-21T01:10:09.913348Z","iopub.status.idle":"2023-06-21T01:10:09.916860Z","shell.execute_reply.started":"2023-06-21T01:10:09.913307Z","shell.execute_reply":"2023-06-21T01:10:09.915939Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#the first class is elliptical while the second class is spiral\nx = image.img_to_array(img)\n# print(x)\nx = np.expand_dims(x, axis=0)\n# print(x)\n\nx = preprocess_input(x)\n# print(x)\n\n#making a prediction\npreds = model.predict(x)\nprint(preds)","metadata":{"id":"SWSKRXayis3a","outputId":"7d27ef9e-dfe7-4c8b-e4dc-9c036444b1fa","execution":{"iopub.status.busy":"2023-06-21T01:14:05.477622Z","iopub.execute_input":"2023-06-21T01:14:05.478613Z","iopub.status.idle":"2023-06-21T01:14:05.536815Z","shell.execute_reply.started":"2023-06-21T01:14:05.478564Z","shell.execute_reply":"2023-06-21T01:14:05.535214Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Defining a fuction that takes an input and outputs a \n#Gradient Class Activation Map for the final spacified layer\nwith tf.GradientTape() as tape:\n  last_conv_layer = model.get_layer(\"conv2d_3\")\n  iterate = tf.keras.models.Model([model.inputs], [model.output, last_conv_layer.output])\n  model_out, last_conv_layer = iterate(x)\n  class_out = model_out[:, np.argmax(model_out[0])]\n  grads = tape.gradient(class_out, last_conv_layer)\n  pooled_grads = K.mean(grads, axis=(0, 1, 2))\n  \nheatmap = tf.reduce_mean(tf.multiply(pooled_grads, last_conv_layer), axis=-1)","metadata":{"id":"GLkILEeGixjx","execution":{"iopub.status.busy":"2023-06-21T00:56:10.233115Z","iopub.execute_input":"2023-06-21T00:56:10.233578Z","iopub.status.idle":"2023-06-21T00:56:10.552319Z","shell.execute_reply.started":"2023-06-21T00:56:10.233523Z","shell.execute_reply":"2023-06-21T00:56:10.551553Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#visualizing the heat map\n\nheatmap = np.maximum(heatmap, 0)\nheatmap /= np.max(heatmap)\nheatmap = heatmap.reshape((21, 21))\nplt.matshow(heatmap)\nplt.savefig(\"Astromomy.png\")\nplt.show()","metadata":{"id":"yfh7RIkBi4Ml","outputId":"776fb741-2913-4e83-aba0-fabc946be73b","execution":{"iopub.status.busy":"2023-06-21T00:56:39.341831Z","iopub.execute_input":"2023-06-21T00:56:39.342124Z","iopub.status.idle":"2023-06-21T00:56:39.647403Z","shell.execute_reply.started":"2023-06-21T00:56:39.342091Z","shell.execute_reply":"2023-06-21T00:56:39.646449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#getting a link to dowmload the the heatmap image\nos.chdir(r\"../working\")\nfrom IPython.display import FileLink\nFileLink(r\"Astromomy.png\")","metadata":{"execution":{"iopub.status.busy":"2023-06-21T00:36:00.794443Z","iopub.status.idle":"2023-06-21T00:36:00.795099Z","shell.execute_reply.started":"2023-06-21T00:36:00.794832Z","shell.execute_reply":"2023-06-21T00:36:00.794863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Visualizing an elliptical galaxy","metadata":{}},{"cell_type":"code","source":"# uploading an image for prediction\nimg_upload = \"/kaggle/input/images123/100018.jpg\"\n\nimg = image.load_img(img_upload, target_size=(212, 212))\n\nplt.imshow(cv2.imread(img_upload));# Visualize image","metadata":{"execution":{"iopub.status.busy":"2023-06-21T00:59:02.342483Z","iopub.execute_input":"2023-06-21T00:59:02.343177Z","iopub.status.idle":"2023-06-21T00:59:02.615041Z","shell.execute_reply.started":"2023-06-21T00:59:02.343136Z","shell.execute_reply":"2023-06-21T00:59:02.614353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#the first class is elliptical while the second class is spiral\nx = image.img_to_array(img)\nx = np.expand_dims(x, axis=0)\nx = preprocess_input(x)\n\n#making a prediction\npreds = model.predict(x)\nprint(preds)","metadata":{"execution":{"iopub.status.busy":"2023-06-21T00:59:06.020117Z","iopub.execute_input":"2023-06-21T00:59:06.020398Z","iopub.status.idle":"2023-06-21T00:59:06.074326Z","shell.execute_reply.started":"2023-06-21T00:59:06.020364Z","shell.execute_reply":"2023-06-21T00:59:06.072839Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Defining a fuction that takes an input and outputs a \n#Gradient Class Activation Map for the final spacified layer\nwith tf.GradientTape() as tape:\n  last_conv_layer = model.get_layer(\"conv2d_3\")\n  iterate = tf.keras.models.Model([model.inputs], [model.output, last_conv_layer.output])\n  model_out, last_conv_layer = iterate(x)\n  class_out = model_out[:, np.argmax(model_out[0])]\n  grads = tape.gradient(class_out, last_conv_layer)\n  pooled_grads = K.mean(grads, axis=(0, 1, 2))\n  \nheatmap = tf.reduce_mean(tf.multiply(pooled_grads, last_conv_layer), axis=-1)","metadata":{"execution":{"iopub.status.busy":"2023-06-21T00:59:20.217058Z","iopub.execute_input":"2023-06-21T00:59:20.217338Z","iopub.status.idle":"2023-06-21T00:59:20.244506Z","shell.execute_reply.started":"2023-06-21T00:59:20.217306Z","shell.execute_reply":"2023-06-21T00:59:20.243663Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#visualizing the heat map\n\nheatmap = np.maximum(heatmap, 0)\nheatmap /= np.max(heatmap)\nheatmap = heatmap.reshape((21, 21))\nplt.matshow(heatmap)\nplt.savefig(\"Astromomy2.png\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-06-21T00:59:22.469894Z","iopub.execute_input":"2023-06-21T00:59:22.470666Z","iopub.status.idle":"2023-06-21T00:59:22.787352Z","shell.execute_reply.started":"2023-06-21T00:59:22.470607Z","shell.execute_reply":"2023-06-21T00:59:22.786316Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#getting a link to dowmload the the heatmap image\nos.chdir(r\"../working\")\nfrom IPython.display import FileLink\nFileLink(r\"Astromomy2.png\")","metadata":{"execution":{"iopub.status.busy":"2023-06-21T00:36:00.804043Z","iopub.status.idle":"2023-06-21T00:36:00.804699Z","shell.execute_reply.started":"2023-06-21T00:36:00.804403Z","shell.execute_reply":"2023-06-21T00:36:00.804434Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Conclusion and Recommendations\n### Conclusion\nThe model architecture seem to perform considerably well for our sample with an optimized  validation and test accuracy within the range (96 - 98)%. More augmentation is needed for the model to generalise well. However,from random image predictions and plotting the heat maps form the model, it seemed that most of the galaxies well classified as spiral galaxies were the disk like spiral galaxy type (See the first image and the corresponding image heat map in the Model Visualization). Surprisingly, galaxies with very well defined and observed arms are strongly mis-classified as elliptical. But going back to the images, it was evident that our selected sample of spriral galaxies was heavily bias towards the disk like structures. The small number of spiral galaxies were maybe consided outliers by our model.\n\n### Recommendations\n- Based on the type of galaxies classifed as spiral glaxies, it maybe important for the sample of spiral galaxies to be balanced between the two or more classifications added for an improvement in the classifications.\n- The traing data could be increased by including the galaxies with a lower percentage fraction in our selection criteria.\n- Linear based models can be used to compare our model perfomance with.","metadata":{}},{"cell_type":"markdown","source":"# > **Inception_V3**","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nimport cv2\nimport tensorflow.keras.backend as K\nfrom tensorflow.keras.applications.inception_v3 import preprocess_input\n\nimport numpy as np\nimport os\n\n\n","metadata":{"execution":{"iopub.status.busy":"2023-06-21T01:25:35.109964Z","iopub.execute_input":"2023-06-21T01:25:35.110374Z","iopub.status.idle":"2023-06-21T01:25:35.125486Z","shell.execute_reply.started":"2023-06-21T01:25:35.110326Z","shell.execute_reply":"2023-06-21T01:25:35.120723Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Using the ImageDataGenerator to prepare the data for training\ndatagen = ImageDataGenerator(preprocessing_function=preprocess_input,\n                             validation_split=0.2)\n\ntrain_generator = datagen.flow_from_dataframe(dataframe=df_galaxies,\n                                              target_size=(224, 224),\n                                              directory=\"./images_training_rev1\",\n                                              batch_size=32,\n                                              x_col=\"GalaxyID\",\n                                              y_col=\"class\",\n                                              color_mode=\"rgb\",\n                                              class_mode=\"categorical\",\n                                              subset=\"training\",\n                                              shuffle=True,\n                                              seed=42)\n\nvalid_generator = datagen.flow_from_dataframe(dataframe=df_galaxies,\n                                              target_size=(224, 224),\n                                              directory=\"./images_training_rev1\",\n                                              batch_size=32,\n                                              x_col=\"GalaxyID\",\n                                              y_col=\"class\",\n                                              color_mode=\"rgb\",\n                                              class_mode=\"categorical\",\n                                              subset=\"validation\",\n                                              shuffle=True,\n                                              seed=42)\n","metadata":{"execution":{"iopub.status.busy":"2023-06-21T01:25:53.297564Z","iopub.execute_input":"2023-06-21T01:25:53.297861Z","iopub.status.idle":"2023-06-21T01:25:53.644315Z","shell.execute_reply.started":"2023-06-21T01:25:53.297829Z","shell.execute_reply":"2023-06-21T01:25:53.643538Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define the Inception V3 pretrained model\npretrained_model = tf.keras.applications.InceptionV3(include_top=False,\n                                                     weights='imagenet',\n                                                     input_shape=(224, 224, 3))\npretrained_model.trainable = False\n\n# Construct the CNN model architecture\nmodel = tf.keras.models.Sequential()\nmodel.add(pretrained_model)\nmodel.add(tf.keras.layers.Flatten())\nmodel.add(tf.keras.layers.Dense(512, activation='relu'))\nmodel.add(tf.keras.layers.Dense(256, activation='relu'))\nmodel.add(tf.keras.layers.Dense(2, activation='softmax'))\n\n# Creating a checkpoint to save the best model\ncheckpoint = ModelCheckpoint(\"best_model.h5\",\n                             monitor=\"val_loss\",\n                             verbose=0,\n                             save_best_only=True,\n                             mode=\"auto\")\n\n# Specifying an early stopping to avoid overfitting\nstopping = EarlyStopping(monitor=\"val_loss\",\n                         patience=10,\n                         verbose=0,\n                         mode=\"auto\")\n\n# Compile the model\nmodel.compile(loss=\"categorical_crossentropy\",\n              optimizer=Adam(learning_rate=0.001),\n              metrics=[\"accuracy\"])\n\n","metadata":{"execution":{"iopub.status.busy":"2023-06-21T01:26:39.349419Z","iopub.execute_input":"2023-06-21T01:26:39.350025Z","iopub.status.idle":"2023-06-21T01:26:42.757205Z","shell.execute_reply.started":"2023-06-21T01:26:39.349985Z","shell.execute_reply":"2023-06-21T01:26:42.756327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Train the model\nhist = model.fit(train_generator,\n                 epochs=10,\n                 validation_data=valid_generator,\n                 callbacks=[checkpoint, stopping])\n","metadata":{"execution":{"iopub.status.busy":"2023-06-21T01:26:52.822453Z","iopub.execute_input":"2023-06-21T01:26:52.822799Z","iopub.status.idle":"2023-06-21T01:38:32.051057Z","shell.execute_reply.started":"2023-06-21T01:26:52.822766Z","shell.execute_reply":"2023-06-21T01:38:32.050196Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# > **VGG16**","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nimport cv2\nimport tensorflow.keras.backend as K\nfrom tensorflow.keras.applications.vgg16 import preprocess_input\nfrom tensorflow.keras.applications.vgg16 import VGG16\n\nimport numpy as np\nimport os\n\n# Using the ImageDataGenerator to prepare the data for training\ndatagen = ImageDataGenerator(preprocessing_function=preprocess_input,\n                             validation_split=0.2)\n\ntrain_generator = datagen.flow_from_dataframe(dataframe=df_galaxies,\n                                              target_size=(224, 224),\n                                              directory=\"./images_training_rev1\",\n                                              batch_size=32,\n                                              x_col=\"GalaxyID\",\n                                              y_col=\"class\",\n                                              color_mode=\"rgb\",\n                                              class_mode=\"categorical\",\n                                              subset=\"training\",\n                                              shuffle=True,\n                                              seed=42)\n\nvalid_generator = datagen.flow_from_dataframe(dataframe=df_galaxies,\n                                              target_size=(224, 224),\n                                              directory=\"./images_training_rev1\",\n                                              batch_size=32,\n                                              x_col=\"GalaxyID\",\n                                              y_col=\"class\",\n                                              color_mode=\"rgb\",\n                                              class_mode=\"categorical\",\n                                              subset=\"validation\",\n                                              shuffle=True,\n                                              seed=42)\n\n# Define the VGG16 pretrained model\npretrained_model = VGG16(include_top=False,\n                         weights='imagenet',\n                         input_shape=(224, 224, 3))\npretrained_model.trainable = False\n\n# Construct the CNN model architecture\nmodel = tf.keras.models.Sequential()\nmodel.add(pretrained_model)\nmodel.add(tf.keras.layers.Flatten())\nmodel.add(tf.keras.layers.Dense(512, activation='relu'))\nmodel.add(tf.keras.layers.Dense(256, activation='relu'))\nmodel.add(tf.keras.layers.Dense(2, activation='softmax'))\n\n# Creating a checkpoint to save the best model\ncheckpoint = ModelCheckpoint(\"best_model.h5\",\n                             monitor=\"val_loss\",\n                             verbose=0,\n                             save_best_only=True,\n                             mode=\"auto\")\n\n# Specifying an early stopping to avoid overfitting\nstopping = EarlyStopping(monitor=\"val_loss\",\n                         patience=10,\n                         verbose=0,\n                         mode=\"auto\")\n\n# Compile the model\nmodel.compile(loss=\"categorical_crossentropy\",\n              optimizer=Adam(learning_rate=0.001),\n              metrics=[\"accuracy\"])\n\n# Train the model\nhist = model.fit(train_generator,\n                 epochs=10,\n                 validation_data=valid_generator,\n                 callbacks=[checkpoint, stopping])\n","metadata":{"execution":{"iopub.status.busy":"2023-06-21T01:42:39.358477Z","iopub.execute_input":"2023-06-21T01:42:39.359047Z","iopub.status.idle":"2023-06-21T01:55:46.814289Z","shell.execute_reply.started":"2023-06-21T01:42:39.359003Z","shell.execute_reply":"2023-06-21T01:55:46.813409Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **RESNET**","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.applications import ResNet50\nfrom tensorflow.keras.layers import GlobalAveragePooling2D\n\n# Pretrained model\nbase_model = ResNet50(weights='imagenet', include_top=False, input_shape=(212, 212, 3))\n\n# Freeze the base model\nbase_model.trainable = False\n\n# Add your own classification layers on top\nmodel = tf.keras.models.Sequential([\n    base_model,\n    GlobalAveragePooling2D(),\n    tf.keras.layers.Dense(512, activation='relu'),\n    tf.keras.layers.Dense(256, activation='relu'),\n    tf.keras.layers.Dense(2, activation='softmax')\n])\n\n# ... Rest of the code (ImageDataGenerator, checkpoint, stopping, compilation, etc.) ...\n","metadata":{"execution":{"iopub.status.busy":"2023-06-21T02:03:41.126925Z","iopub.execute_input":"2023-06-21T02:03:41.127309Z","iopub.status.idle":"2023-06-21T02:03:43.923069Z","shell.execute_reply.started":"2023-06-21T02:03:41.127270Z","shell.execute_reply":"2023-06-21T02:03:43.922274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Creating a checkpoint to save the best model\ncheckpoint = ModelCheckpoint(\"best_model.h5\",\n                             monitor=\"val_loss\",\n                             verbose=0,\n                             save_best_only=True,\n                             mode=\"auto\")\n\n# Specifying an early stopping to avoid overfitting\nstopping = EarlyStopping(monitor=\"val_loss\",\n                         patience=10,\n                         verbose=0,\n                         mode=\"auto\")\n\n# Compile the model\nmodel.compile(loss=\"categorical_crossentropy\",\n              optimizer=Adam(learning_rate=0.001),\n              metrics=[\"accuracy\"])\n\n# Train the model\nhist = model.fit(train_generator,\n                 epochs=10,\n                 validation_data=valid_generator,\n                 callbacks=[checkpoint, stopping])","metadata":{"execution":{"iopub.status.busy":"2023-06-21T02:05:17.764655Z","iopub.execute_input":"2023-06-21T02:05:17.764969Z","iopub.status.idle":"2023-06-21T02:18:22.977418Z","shell.execute_reply.started":"2023-06-21T02:05:17.764935Z","shell.execute_reply":"2023-06-21T02:18:22.976567Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Xception**","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.applications import Xception\nfrom tensorflow.keras.layers import GlobalAveragePooling2D\n\n# Pretrained model\nbase_model = Xception(weights='imagenet', include_top=False, input_shape=(212, 212, 3))\n\n# Freeze the base model\nbase_model.trainable = False\n\n# Add your own classification layers on top\nmodel = tf.keras.models.Sequential([\n    base_model,\n    GlobalAveragePooling2D(),\n    tf.keras.layers.Dense(512, activation='relu'),\n    tf.keras.layers.Dense(256, activation='relu'),\n    tf.keras.layers.Dense(2, activation='softmax')\n])\n\n\n","metadata":{"execution":{"iopub.status.busy":"2023-06-21T02:18:22.979650Z","iopub.execute_input":"2023-06-21T02:18:22.980226Z","iopub.status.idle":"2023-06-21T02:18:25.079365Z","shell.execute_reply.started":"2023-06-21T02:18:22.980181Z","shell.execute_reply":"2023-06-21T02:18:25.078556Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Creating a checkpoint to save the best model\ncheckpoint = ModelCheckpoint(\"best_model.h5\",\n                             monitor=\"val_loss\",\n                             verbose=0,\n                             save_best_only=True,\n                             mode=\"auto\")\n\n# Specifying an early stopping to avoid overfitting\nstopping = EarlyStopping(monitor=\"val_loss\",\n                         patience=10,\n                         verbose=0,\n                         mode=\"auto\")\n\n# Compile the model\nmodel.compile(loss=\"categorical_crossentropy\",\n              optimizer=Adam(learning_rate=0.001),\n              metrics=[\"accuracy\"])\n\n# Train the model\nhist = model.fit(train_generator,\n                 epochs=10,\n                 validation_data=valid_generator,\n                 callbacks=[checkpoint, stopping])","metadata":{"execution":{"iopub.status.busy":"2023-06-21T02:18:25.081008Z","iopub.execute_input":"2023-06-21T02:18:25.081317Z","iopub.status.idle":"2023-06-21T02:31:44.971947Z","shell.execute_reply.started":"2023-06-21T02:18:25.081275Z","shell.execute_reply":"2023-06-21T02:31:44.970875Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}