# Flexible_Neural_Net
A simple and flexible python library that allows you to build custom Neural Networks where you can easily tweak parameters to change how your network behaves

## Installation
```pip install flexible-neural-network```

## Initialization
* First initialize a Neural Net object and pass number of inputs, outputs, and hidden layers
  
  ```myNN = NeuralNet(number_of_inputs, number_of_outputs, number_of_hidden_layers)```
* You can choose how what _activation function_ to use from: "relu", "sigmoid, "tanh"
  
  ```myNN = NeuralNet(number_of_inputs, number_of_outputs, number_of_hidden_layers, activation_func="sigmoid")```
* You can choose modify the _learning rate_
  
  ```myNN = NeuralNet(number_of_inputs, number_of_outputs, number_of_hidden_layers, learning_rate=0.1)```
* You can choose tweak the number of nodes in each _hidden layer_
  
  *   by assigning an integer number such as 3: _if there was 4 hidden layers then each layer will have 3 nodes => [3, 3, 3, 3]_
  
      ```myNN = NeuralNet(number_of_inputs, number_of_outputs, number_of_hidden_layers, nodes_in_each_layer=3)```

  *   by assigning a list of integers number such as [3, 5, 2, 3] that has a length of *number_of_hidden_layers*: _if there was 4 hidden layers then each layer will have different number of nodes nodes correspondingly => [3, 5, 2, 3]_
  
      ```myNN = NeuralNet(number_of_inputs, number_of_outputs, number_of_hidden_layers, nodes_in_each_layer=[3, 5, 2, 3])```


## How to use

#### Assuming you initialized your object and data as below:

```myNN = NeuralNet(2, 1, 2, nodes_in_each_layer=4, learning_rate=0.1, activation_func="sigmoid")```
```
data = np.array([
        [3,   1.5, 1],
        [2,   1,   0],
        [4,   1.5, 1],
        [3,   1,   0],
        [3.5, .5,  1],
        [2,   .5,  0],
        [5.5,  1,  1],
        [1,    1,  0]
        ])

mystery_data = [2, 1] # should be classified as 1
```

#### You can:

_Here we specified the number of epochs to be 1_
* *Train single entries:*  
  ```myNN.train(data[0, 0:2], data[0, 2], epochs=1)```
  
* *Train multiple entries*
  ```myNN.train_many(data[:, 0:2], data[:, 2], epochs=1)```

* *test single/multiple entries*
  ```output = myNN.test(mystery_flower)```
  where output is always an np.ndarray with size as the specfied in the object's constructor. _for the current example it's = [1.45327823]_
  
* *Save NN for later*
  ```myNN.save("file_name")```

* *Load NN without the need for retraining*
  ```myNN = NeuralNet.load("file_name")```

Obviously NNs **do not** give exact answers and its our job to determine which class is it belongs to and judging from the training data we only have class 0, or 1 and the output we got is nearer to 1 than 0 so we should **classify it as  1**
