Classifying Radio Signals from Space using Keras in Python
Hello everyone, welcome to Classifying Radio Signals from Space using Keras in Python. In this article, you will learn about how to classify radio signal using CNN, how to display results and plot 2D spectrograms with Python in Jupyter Notebook.
Here, we will be using the dataset which is provided by the SETI Institute. The dataset is already normalized and divided into two directories i.e. testing and validation dataset. You can download the dataset from here.
So Now let’s start working on the project.
Importing Libraries
First, we will import all the necessary Python libraries. Please make sure all the libraries given below are installed on your system and if not, install them using pip.
from livelossplot.tf_keras import PlotLossesCallback import pandas as pd import numpy as np import matplotlib.pyplot as plt import tensorflow as tf from sklearn.metrics import confusion_matrix from sklearn import metrics import numpy as np np.random.seed(42) import warnings;warnings.simplefilter('ignore') %matplotlib inline
Loading and Preprocessing The Data
Then we will load the dataset which is in CSV format using pandas.
train_images = pd.read_csv('dataset/train/images.csv', header=None) train_labels = pd.read_csv('dataset/train/labels.csv', header=None) val_images = pd.read_csv('dataset/validation/images.csv', header=None) val_labels = pd.read_csv('dataset/validation/labels.csv', header=None)
Now, let’s see the dimensions of the training and validation dataset.
print("Training set shape:", train_images.shape, train_labels.shape) print("Validation set shape:", val_images.shape, val_labels.shape)
Output:
Training set shape: (3200, 8192) (3200, 4) Validation set shape: (800, 8192) (800, 4)
So now, we will reshape the data into the desired dimensions i.e. given below.
x_train = train_images.values.reshape(3200, 64, 128, 1) x_val = val_images.values.reshape(800, 64, 128, 1) y_train = train_labels.values y_val = val_labels.values
Plotting 2D Spectrograms
So now, we will convert the NumPy array into 2d spectrograms. We will get random images from our training dataset for every execution. So in the output, you will see 3 images of 2d spectrogram which is a coloured image but we have to convert it into a grayscale image.
plt.figure(0, figsize=(12,12)) for i in range(1,4): plt.subplot(1,3,i) img = np.squeeze(x_train[np.random.randint(0, x_train.shape[0])]) plt.xticks([]) plt.yticks([]) plt.imshow(img)
Output:
plt.imshow(np.squeeze(x_train[3]), cmap="gray");
Output:
Creating Training and Validation Data Generators
So now. we will perform real-time data augmentation using ImageDataGenerator. Here, we are flipping the images horizontally for the training and validation data.
from tensorflow.keras.preprocessing.image import ImageDataGenerator datagen_train = ImageDataGenerator(horizontal_flip=True) datagen_train.fit(x_train) datagen_val = ImageDataGenerator(horizontal_flip=True) datagen_val.fit(x_val)
Creating CNN Model
Before we start creating the model first we have to import all the layers, models, optimizers and callbacks. In this model, we will be using the following layers and optimizers as given below.
from tensorflow.keras.layers import Dense, Input, Dropout,Flatten, Conv2D from tensorflow.keras.layers import BatchNormalization, Activation, MaxPooling2D from tensorflow.keras.models import Model, Sequential from tensorflow.keras.optimizers import Adam, SGD from tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau from tensorflow.keras.utils import plot_model
First, we initialize the model as Sequential model. Then, We will create the first convolution in which we will add Conv2D, BatchNormalization, Activation = ‘relu’, MaxPooling2D and the dropout layers. The input is taken in this layer with the shape as 64 * 128 and 1 representing that the image is of grayscale format. In the first convolution, we are passing 32 feature maps with 5,5 as the filter size.
Similarly, we will create another convolution with 64 feature maps this time. Next, We will add a flattening layer and after that a fully connected dense layer with 1024 neurons. Finally, In the output layer for the activation function, we are using ‘softmax’.
model = Sequential() model.add(Conv2D(32,(5,5), padding='same', input_shape=(64, 128,1))) model.add(BatchNormalization()) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Conv2D(64,(5,5), padding='same')) model.add(BatchNormalization()) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(1024)) model.add(BatchNormalization()) model.add(Activation('relu')) model.add(Dropout(0.4)) model.add(Dense(4, activation='softmax'))
Now, let’s see the learning rate schedule. Initially, we will be setting the learning rate to 0.005 and using ExponentialDecay we will decay its value after 5 steps with decay rate as 0.96. We will use Adam optimizer here.
initial_learning_rate = 0.005 lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay( initial_learning_rate, decay_steps=5, decay_rate=0.96, staircase=True) optimizer = Adam(learning_rate=lr_schedule)
So, Let’s compile the model now and check its summary.
model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy']) model.summary()
Output:
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) (None, 64, 128, 32) 832 _________________________________________________________________ batch_normalization (BatchNo (None, 64, 128, 32) 128 _________________________________________________________________ activation (Activation) (None, 64, 128, 32) 0 _________________________________________________________________ max_pooling2d (MaxPooling2D) (None, 32, 64, 32) 0 _________________________________________________________________ dropout (Dropout) (None, 32, 64, 32) 0 _________________________________________________________________ conv2d_1 (Conv2D) (None, 32, 64, 64) 51264 _________________________________________________________________ batch_normalization_1 (Batch (None, 32, 64, 64) 256 _________________________________________________________________ activation_1 (Activation) (None, 32, 64, 64) 0 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 16, 32, 64) 0 _________________________________________________________________ dropout_1 (Dropout) (None, 16, 32, 64) 0 _________________________________________________________________ flatten (Flatten) (None, 32768) 0 _________________________________________________________________ dense (Dense) (None, 1024) 33555456 _________________________________________________________________ batch_normalization_2 (Batch (None, 1024) 4096 _________________________________________________________________ activation_2 (Activation) (None, 1024) 0 _________________________________________________________________ dropout_2 (Dropout) (None, 1024) 0 _________________________________________________________________ dense_1 (Dense) (None, 4) 4100 ================================================================= Total params: 33,616,132 Trainable params: 33,613,892 Non-trainable params: 2,240 _________________________________________________________________
Model Training
Before we start training the model, first we will do the checkpointing and save the weights for which the validation loss is minimum and accuracy is best. Then, using PlotLossesCallback function we will graphically show the loss and the accuracy after each epoch.
So for training, we will set the batch size as 32 and the number of epochs as 12. We will shuffle the inputs because if there is an order we can eliminate its possibility.
checkpoint = ModelCheckpoint("model_weights.h5", monitor='val_loss', save_weights_only=True, mode='min', verbose=0) callbacks = [PlotLossesCallback(), checkpoint]#, reduce_lr] batch_size = 32 history = model.fit( datagen_train.flow(x_train, y_train, batch_size=batch_size, shuffle=True), steps_per_epoch=len(x_train)//batch_size, validation_data = datagen_val.flow(x_val, y_val, batch_size=batch_size, shuffle=True), validation_steps = len(x_val)//batch_size, epochs=12, callbacks=callbacks )
Output:
Log-loss (cost function): training (min: 0.367, max: 0.564, cur: 0.368) validation (min: 0.362, max: 5.084, cur: 0.362) accuracy: training (min: 0.710, max: 0.764, cur: 0.756) validation (min: 0.250, max: 0.751, cur: 0.743) 100/100 [==============================] - 184s 2s/step - loss: 0.3682 - accuracy: 0.7556 - val_loss: 0.3623 - val_accuracy: 0.7425
Evaluating The Model
Finally, we will evaluate the model with validation data. Here, we can find that the validation accuracy of the model is 75%.
model.evaluate(x_val, y_val)
Output:
[0.3621701712545473, 0.75125]
So now, let’s check the classification report of the model for true and predicted values.
from sklearn.metrics import confusion_matrix from sklearn import metrics import seaborn as sns y_true = np.argmax(y_val, 1) y_pred = np.argmax(model.predict(x_val), 1) print(metrics.classification_report(y_true, y_pred)) print("Classification accuracy: %0.6f" % metrics.accuracy_score(y_true, y_pred))
Output:
precision recall f1-score support 0 1.00 0.99 0.99 200 1 0.50 0.94 0.66 200 2 0.54 0.07 0.13 200 3 1.00 1.00 1.00 200 accuracy 0.75 800 macro avg 0.76 0.75 0.70 800 weighted avg 0.76 0.75 0.70 800 Classification accuracy: 0.751250
For your reference, you can see the 4 different labels below which we used in our model.
labels = [“squiggle”, “narrowband”, “noise”, “narrowbanddrd”]
Thank you!
Leave a Reply