# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # Feedforward Neural Network (FFNN)

import numpy as np
import matplotlib.pyplot as plt

# ## 1. Download the data stored in the file data FFNN.txt available on the course website. This dataset consists of three columns: x1, x2 and y.
#

data = np.loadtxt("data_FFNN.txt")
data.shape

X = data[:,:2]
Y = data[:,2]

Y = Y.reshape(51,1)
Ys = []
for y in Y:
    if (y == 1):
        Ys = np.append(Ys,np.array([0,1]))
    else:
        Ys = np.append(Ys,np.array([1,0]))
Y = Ys.reshape(51,2)


# ## 2. Implement the aforementioned classifier using the feedforward neural network (FFNN) approach by learning its parameter values using the provided dataset. This FFNN should consist of three layers, in which the hidden layer has 5 neurons.

def add_bias(inputs):
    inputs = np.append(0,inputs)
    return inputs.reshape(len(inputs),1)


def sigmoid(inputs):
    return 1/(1+np.exp(-inputs)) 


def hidden_layer(inputs,weights):
    outputs = []
    for w in weights: #for each neurons
        outputs = np.append(outputs,np.dot(inputs.T,w))
    return sigmoid(outputs)


def forward(X,V,W):
    X = add_bias(X)       # (3,1)
    F = hidden_layer(X,V) # (5,1)
    F = add_bias(F)       # (6,1)
    Y = hidden_layer(F,W) # (2,1)
    return np.argmax(Y)


V = np.random.random_sample((5, 3)) # 5 neurons k, 3 inputs n: x0,x1,x2
W = np.random.random_sample((2, 6)) # 2 neurons j, 6 inputs: f0,f1,f2,f3,f4,f5

forward(X[0].reshape(2,1),V,W)


# ## 3. What are the optimal parameter values for the hidden layer (v) and for the output layer (ω)?

def inputs_weight(inputs, weights): #Compute for one example  
    return inputs*weights


def update_values(X,V,W):
    X = add_bias(X)
    X_bar = []
    for x in X:
        for v in V:
            X_bar_bar = np.append(X_bar,inputs_weight(x, v))
    F = np.sum(X_bar)
    F_bar = sigmoid(F)
    for f in F:
        for w in W:
            F_bar_bar = np.append(F_bar_bar,inputs_weight(f, w))
    G = 
    return X_bar, F, F_bar, G


def forward2(X,V,W):
    X = add_bias(X)       # (3,1)
    F = hidden_layer(X,V) # (5,1)
    F = add_bias(F)       # (6,1)
    pred = hidden_layer(F,W) # (2,1)
    return pred.reshape(2,1)


def get_predictions(X,V,W):
    predictions = []
    for x in X:
        predictions = np.append(predictions,forward2(x.reshape(2,1),V,W))
    return predictions.reshape(51,2)


def sse(y,predictions):
    return 0.5*np.sum(np.square(predictions-y)) #SSE


sse(Y,get_predictions(X,V,W))


def backpropagation():
    W = update_W(W, alpha1, F ,pred, Y)
    V = update_V(W, V, alpha2, X ,F, pred, Y)
    return V,W


def update_W(W, alpha, F, pred, Y):
    for w in W: # W(2,6), w(6,)
        w = w - alpha*np.sum((pred-y)*pred*(1-pred)*F)
    return W


def update_V():
    return V


# ## 4. Show that your classifier can correctly classify for (x 1 , x 2 )=(2, 2) and for (x 1 , x 2 )=(4, 4).

forward(np.array([[2],[2]]),V,W)

forward(np.array([[4],[4]]),V,W)



StarcoderdataJupyterScriptsDedupFiltered