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:

Signal Image
plt.imshow(np.squeeze(x_train[3]), cmap="gray");

Output:

Grayscale image 

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

Your email address will not be published. Required fields are marked *