CVNN

This shows a simple example on how to use this library.

First lets import what we need

import numpy as np
import cvnn.layers as complex_layers
import tensorflow as tf

We will assume you have a get_dataset() function that has it’s complex dtype data.

If you don’t yet have it and you want first to test any working example, you can use the following code.

def get_dataset():
        (train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.cifar10.load_data()
        train_images = train_images.astype(dtype=np.complex64) / 255.0
        test_images = test_images.astype(dtype=np.complex64) / 255.0
        return (train_images, train_labels), (test_images, test_labels)

Warning

This will just make it have a nul imaginary part (z = x + 1j*0), it makes no sense to use a complex network for this dataset. It is just for an example.

Ok, we are now ready to create our model! Let’s create a Complex-Valued Convolutional Neural Netowrk (CV-CNN)

Warning

Tensorflow casts the input automatically to real! To avoid that, use always the ComplexInput layer as the input.

# Assume you already have complex data... example numpy arrays of dtype np.complex64
(train_images, train_labels), (test_images, test_labels) = get_dataset()        # to be done by each user

model = tf.keras.models.Sequential()
model.add(complex_layers.ComplexInput(input_shape=(32, 32, 3)))                     # Always use ComplexInput at the start
model.add(complex_layers.ComplexConv2D(32, (3, 3), activation='cart_relu'))
model.add(complex_layers.ComplexAvgPooling2D((2, 2)))
model.add(complex_layers.ComplexConv2D(64, (3, 3), activation='cart_relu'))
model.add(complex_layers.ComplexMaxPooling2D((2, 2)))
model.add(complex_layers.ComplexConv2D(64, (3, 3), activation='cart_relu'))
model.add(complex_layers.ComplexFlatten())
model.add(complex_layers.ComplexDense(64, activation='cart_relu'))
model.add(complex_layers.ComplexDense(10, activation='convert_to_real_with_abs'))
model.compile(optimizer='adam',
        loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
        metrics=['accuracy'])
model.summary()

Note

An activation that casts to real must be used at the last layer as the loss function cannot minimize a complex number.

The last code will output the model summary:

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
complex_conv2d (ComplexConv2 (None, 30, 30, 32)        1792
_________________________________________________________________
complex_avg_pooling2d (Compl (None, 15, 15, 32)        0
_________________________________________________________________
complex_conv2d_1 (ComplexCon (None, 13, 13, 64)        36992
_________________________________________________________________
complex_flatten (ComplexFlat (None, 10816)             0
_________________________________________________________________
complex_dense (ComplexDense) (None, 64)                1384576
_________________________________________________________________
complex_dense_1 (ComplexDens (None, 10)                1300
=================================================================
Total params: 1,424,660
Trainable params: 1,424,660
Non-trainable params: 0
_________________________________________________________________

Great! we have our model done, now we are ready to train!

history = model.fit(train_images, train_labels, epochs=6, validation_data=(test_images, test_labels))

Training output:

Epoch 1/6
1563/1563 [==============================] - 21s 13ms/step - loss: 1.4151 - accuracy: 0.4932 - val_loss: 1.1865 - val_accuracy: 0.5854
Epoch 2/6
1563/1563 [==============================] - 17s 11ms/step - loss: 1.0378 - accuracy: 0.6339 - val_loss: 1.0505 - val_accuracy: 0.6415
Epoch 3/6
1563/1563 [==============================] - 17s 11ms/step - loss: 0.8625 - accuracy: 0.6968 - val_loss: 0.9945 - val_accuracy: 0.6575
Epoch 4/6
1563/1563 [==============================] - 15s 10ms/step - loss: 0.7133 - accuracy: 0.7499 - val_loss: 0.9414 - val_accuracy: 0.6774
Epoch 5/6
1563/1563 [==============================] - 16s 11ms/step - loss: 0.5716 - accuracy: 0.7999 - val_loss: 0.9673 - val_accuracy: 0.6895
Epoch 6/6
1563/1563 [==============================] - 18s 11ms/step - loss: 0.4350 - accuracy: 0.8490 - val_loss: 1.0668 - val_accuracy: 0.6848

To evaluate the models performance you can use

test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)

Output:

313/313 - 2s - loss: 1.0668 - accuracy: 0.6848

You can now predict using either model(test_images) or model.predict(test_images).