Simple Neural Network

I have created a basic neural network with both Tensorflow and Numpy. Finally, I had compared the results.
Author

Vraj Shah

Published

September 4, 2023

Importing Libraries

import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
WARNING:tensorflow:From C:\Users\vrajs\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\keras\src\losses.py:2976: The name tf.losses.sparse_softmax_cross_entropy is deprecated. Please use tf.compat.v1.losses.sparse_softmax_cross_entropy instead.

Dataset

rng = np.random.default_rng(2)
X = rng.random(400).reshape(-1, 2)
X[:, 1] = X[:, 1] * 4 + 11.5
X[:, 0] = X[:, 0] * (285-150) + 150
Y = np.zeros(len(X))

i = 0
for t, d in X:
    y = -3/(260-175)*t + 21
    if (t > 175 and t < 260 and d > 12 and d < 15 and d <= y):
        Y[i] = 1
    else:
        Y[i] = 0
    i += 1

plt.scatter(X[Y == 1, 0], X[Y == 1, 1], s=70, marker='x',
            linewidth=3,  c='red', label="Good")
plt.scatter(X[Y == 0, 0], X[Y == 0, 1], s=50, marker='o', label="Bad")

tr = np.linspace(175, 260, 50)
plt.plot(tr, (-3 / 85) * tr + 21, linewidth=1)
plt.axhline(y=12, linewidth=1)
plt.axvline(x=175, linewidth=1)

plt.xlabel("Feature 1", size=12)
plt.ylabel("Feature 2", size=12)
plt.legend(loc='upper right')
plt.show()

Normalize the Data

Y = Y.reshape(-1, 1)
norm_l = tf.keras.layers.Normalization(axis=-1)
norm_l.adapt(X)
Xn = norm_l(X)
Xt = np.tile(Xn, (1000, 1))
Yt = np.tile(Y, (1000, 1))
WARNING:tensorflow:From C:\Users\vrajs\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\keras\src\backend.py:873: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.

Using Tensorflow

Setting the Pipeline

model = Sequential(
    [
        tf.keras.Input(shape=(2,)),
        Dense(3, activation='sigmoid', name='layer1'),
        Dense(1, activation='sigmoid', name='layer2')
    ]
)

model.summary()
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 layer1 (Dense)              (None, 3)                 9         
                                                                 
 layer2 (Dense)              (None, 1)                 4         
                                                                 
=================================================================
Total params: 13 (52.00 Byte)
Trainable params: 13 (52.00 Byte)
Non-trainable params: 0 (0.00 Byte)
_________________________________________________________________

Random Initial Weights

W1, b1 = model.get_layer("layer1").get_weights()        # Random Generation
W2, b2 = model.get_layer("layer2").get_weights()        # Random Generation
print("W1:\n", W1, "\nb1:", b1)
print("W2:\n", W2, "\nb2:", b2)
W1:
 [[ 1.0034692  -0.5364701  -0.61829925]
 [-0.45948058 -0.48300928 -0.2479465 ]] 
b1: [0. 0. 0.]
W2:
 [[ 0.795092  ]
 [ 0.50782764]
 [-0.8502825 ]] 
b2: [0.]

Fitting the model

model.compile(
    loss=tf.keras.losses.BinaryCrossentropy(),
    optimizer=tf.keras.optimizers.Adam(learning_rate=0.01),
)

model.fit(
    Xt, Yt,
    epochs=10,
)
Epoch 1/10
WARNING:tensorflow:From C:\Users\vrajs\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\keras\src\utils\tf_utils.py:492: The name tf.ragged.RaggedTensorValue is deprecated. Please use tf.compat.v1.ragged.RaggedTensorValue instead.

6250/6250 [==============================] - 11s 2ms/step - loss: 0.2032
Epoch 2/10
6250/6250 [==============================] - 10s 2ms/step - loss: 0.0970
Epoch 3/10
6250/6250 [==============================] - 11s 2ms/step - loss: 0.0321
Epoch 4/10
6250/6250 [==============================] - 12s 2ms/step - loss: 0.0198
Epoch 5/10
6250/6250 [==============================] - 10s 2ms/step - loss: 0.0146
Epoch 6/10
6250/6250 [==============================] - 10s 2ms/step - loss: 0.0116
Epoch 7/10
6250/6250 [==============================] - 10s 2ms/step - loss: 0.0095
Epoch 8/10
6250/6250 [==============================] - 11s 2ms/step - loss: 0.0080
Epoch 9/10
6250/6250 [==============================] - 11s 2ms/step - loss: 0.0068
Epoch 10/10
6250/6250 [==============================] - 10s 2ms/step - loss: 0.0059
<keras.src.callbacks.History at 0x278f700ac20>

Final Weights

W1, b1 = model.get_layer("layer1").get_weights()
W2, b2 = model.get_layer("layer2").get_weights()
print("W1:\n", W1, "\nb1:", b1)
print("W2:\n", W2, "\nb2:", b2)
W1:
 [[13.708808   -0.04309544 13.338246  ]
 [ 0.2935187  10.918727   11.044739  ]] 
b1: [14.286802 13.310424  1.352872]
W2:
 [[ 27.669281]
 [ 27.278173]
 [-37.544296]] 
b2: [-35.913513]

Predictions

rng = np.random.default_rng(0)
X = rng.random(400).reshape(-1, 2)
X[:, 1] = X[:, 1] * 4 + 11.5
X[:, 0] = X[:, 0] * (285-150) + 150
Y = np.zeros(len(X))

i = 0
for t, d in X:
    y = -3/(260-175)*t + 21
    if (t > 180 and t < 260 and d > 12 and d < 15 and d <= y):
        Y[i] = 1
    else:
        Y[i] = 0
    i += 1

X_testn = norm_l(X)
predictions = model.predict(X_testn)

predictions_thresholded = (predictions > 0.5).astype(int).reshape(-1,)

plt.scatter(X[predictions_thresholded == 1, 0], X[predictions_thresholded == 1, 1], s=70, marker='x',
            linewidth=3,  c='red', label="Good")
plt.scatter(X[predictions_thresholded == 0, 0],
            X[predictions_thresholded == 0, 1], s=50, marker='o', label="Bad")

tr = np.linspace(175, 260, 50)
plt.plot(tr, (-3 / 85) * tr + 21, linewidth=1)
plt.axhline(y=12, linewidth=1)
plt.axvline(x=175, linewidth=1)

plt.xlabel("Feature 1", size=12)
plt.ylabel("Feature 2", size=12)
plt.legend(loc='upper right')

plt.show()
7/7 [==============================] - 0s 1ms/step

Using Numpy

Setting the Pipeline

def my_dense(a_in, W, b):
    units = W.shape[1]
    a_out = np.zeros(units)
    for j in range(units):
        w = W[:, j]
        z = np.dot(w, a_in) + b[j]
        a_out[j] = 1/(1+np.exp(-z))
    return (a_out)

def my_dense(a_in, W, b):
    a_out=1/(1+(np.exp(-(np.matmul(a_in,W)+b))))
    return (a_out)
def my_sequential(x, W1, b1, W2, b2):
    a1 = my_dense(x,  W1, b1)
    a2 = my_dense(a1, W2, b2)
    return (a2)
W1_tmp = np.array([[-8.93,  0.29, 12.9], [-0.1,  -7.32, 10.81]])
b1_tmp = np.array([-9.82, -9.28,  0.96])
W2_tmp = np.array([[-31.18], [-27.59], [-32.56]])
b2_tmp = np.array([15.41])

Prediction

def my_predict(X, W1, b1, W2, b2):
    m = X.shape[0]
    p = np.zeros((m, 1))
    for i in range(m):
        p[i, 0] = my_sequential(X[i], W1, b1, W2, b2)
    return (p)
rng = np.random.default_rng(0)
X = rng.random(400).reshape(-1, 2)
X[:, 1] = X[:, 1] * 4 + 11.5
X[:, 0] = X[:, 0] * (285-150) + 150
Y = np.zeros(len(X))

i = 0
for t, d in X:
    y = -3/(260-175)*t + 21
    if (t > 180 and t < 260 and d > 12 and d < 15 and d <= y):
        Y[i] = 1
    else:
        Y[i] = 0
    i += 1

X_tstn = norm_l(X)
predictions = my_predict(X_tstn, W1_tmp, b1_tmp, W2_tmp, b2_tmp)

predictions_thresholded = (predictions > 0.5).astype(int).reshape(-1,)

plt.scatter(X[predictions_thresholded == 1, 0], X[predictions_thresholded == 1, 1], s=70, marker='x',
            linewidth=3,  c='red', label="Good")
plt.scatter(X[predictions_thresholded == 0, 0],
            X[predictions_thresholded == 0, 1], s=50, marker='o', label="Bad")

tr = np.linspace(175, 260, 50)
plt.plot(tr, (-3 / 85) * tr + 21, linewidth=1)
plt.axhline(y=12, linewidth=1)
plt.axvline(x=175, linewidth=1)

plt.xlabel("Feature 1", size=12)
plt.ylabel("Feature 2", size=12)
plt.legend(loc='upper right')

plt.show()
C:\Users\vrajs\AppData\Local\Temp\ipykernel_14280\3457910700.py:5: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)
  p[i, 0] = my_sequential(X[i], W1, b1, W2, b2)