generated from javidahmed64592/template-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from javidahmed64592/add-nn
Add NeuralNetwork and other required classes
- Loading branch information
Showing
17 changed files
with
1,065 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,8 @@ verify_ssl = true | |
name = "pypi" | ||
|
||
[packages] | ||
|
||
numpy = "*" | ||
pytest = "*" | ||
|
||
[dev-packages] | ||
isort = "*" | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import datetime | ||
|
||
import numpy as np | ||
|
||
from src.nn.neural_network import NeuralNetwork | ||
|
||
|
||
def main(): | ||
num_inputs = 2 | ||
num_hidden = 4 | ||
num_outputs = 1 | ||
|
||
inputs = [[0.0, 1.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0]] | ||
outputs = [[1.0], [1.0], [0.0], [0.0]] | ||
|
||
nn = NeuralNetwork(num_inputs, num_hidden, num_outputs) | ||
|
||
for _ in range(20000): | ||
random_choice = np.random.randint(low=0, high=len(inputs)) | ||
nn.train(inputs[random_choice], outputs[random_choice]) | ||
|
||
print(f"Guessing inputs {inputs[0]}: Calculated outputs {nn.feedforward(inputs[0])} \t| Expected: {outputs[0]}") | ||
print(f"Guessing inputs {inputs[1]}: Calculated outputs {nn.feedforward(inputs[1])} \t| Expected: {outputs[1]}") | ||
print(f"Guessing inputs {inputs[2]}: Calculated outputs {nn.feedforward(inputs[2])} \t| Expected: {outputs[2]}") | ||
print(f"Guessing inputs {inputs[3]}: Calculated outputs {nn.feedforward(inputs[3])} \t| Expected: {outputs[3]}") | ||
|
||
|
||
def time_feedforward(): | ||
num_inputs = 16 | ||
num_hidden = 8 | ||
num_outputs = 4 | ||
|
||
nn = NeuralNetwork(num_inputs, num_hidden, num_outputs) | ||
|
||
num_iters = 12000 * 100 | ||
|
||
begin_time = datetime.datetime.now() | ||
print(f"Starting feedfoward: {num_iters} times") | ||
for i in range(num_iters): | ||
print(f"\rProgress: {i+1} / {num_iters}", flush=True, end="") | ||
inputs = np.random.uniform(low=-1, high=1, size=(num_inputs,)) | ||
nn.feedforward(inputs) | ||
|
||
dt = datetime.datetime.now() - begin_time | ||
dt_m = int(dt.total_seconds() // 60) | ||
dt_s = int(dt.total_seconds() - (dt_m * 60)) | ||
print(f"\nDone! The time it took is {dt_m}m {dt_s}s.") | ||
|
||
|
||
if __name__ == "__main__": | ||
time_feedforward() |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
from typing import cast | ||
|
||
import numpy as np | ||
|
||
|
||
class ActivationFunctions: | ||
""" | ||
This class is used to define activation functions. | ||
""" | ||
|
||
@staticmethod | ||
def linear(x: float) -> float: | ||
return x | ||
|
||
@staticmethod | ||
def relu(x: float) -> float: | ||
return max(x, 0) | ||
|
||
@staticmethod | ||
def sigmoid(x: float) -> float: | ||
return cast(float, 1 / (1 + np.exp(-x))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
from __future__ import annotations | ||
|
||
from typing import Callable, List, Optional | ||
|
||
import numpy as np | ||
from numpy.typing import NDArray | ||
|
||
|
||
class Matrix: | ||
""" | ||
This class handles the matrix mathematics required to pass data through neural networks. | ||
""" | ||
|
||
def __init__(self, rows: int, cols: int, data: Optional[NDArray] = None) -> None: | ||
""" | ||
Initialise Matrix with number of rows and columns, and optionally the matrix values. | ||
Parameters: | ||
rows (int): Number of rows in matrix | ||
cols (int): Number of columns in matrix | ||
data (Optional[NDArray]): Matrix values if specified | ||
""" | ||
self._rows = rows | ||
self._cols = cols | ||
self._data = data | ||
|
||
def __str__(self) -> str: | ||
return str(self.data) | ||
|
||
@property | ||
def data(self): | ||
if self._data is None: | ||
self._data = np.zeros(shape=self.shape) | ||
return self._data | ||
|
||
@property | ||
def shape(self) -> tuple: | ||
return (self._rows, self._cols) | ||
|
||
@classmethod | ||
def from_array(cls, matrix_array: NDArray | List[List[float]] | List[float]) -> Matrix: | ||
""" | ||
Create a Matrix from an array. | ||
Parameters: | ||
matrix_array (NDArray | List[List[float]] | List[float]): Array of matrix values | ||
Returns: | ||
matrix (Matrix): Matrix with assigned values | ||
""" | ||
matrix_array = np.array(matrix_array) | ||
try: | ||
_rows, _cols = matrix_array.shape | ||
except ValueError: | ||
matrix_array = np.expand_dims(matrix_array, axis=1) | ||
_rows, _cols = matrix_array.shape | ||
|
||
matrix = cls(_rows, _cols, matrix_array) | ||
return matrix | ||
|
||
@classmethod | ||
def random_matrix(cls, rows: int, cols: int, low: float, high: float) -> Matrix: | ||
""" | ||
Create Matrix of specified shape with random values in specified range. | ||
Parameters: | ||
rows (int): Number of rows in matrix | ||
cols (int): Number of columns in matrix | ||
low (float): Lower boundary for random number | ||
high (float): Upper boundary for random number | ||
Returns: | ||
matrix (Matrix): Matrix with random values | ||
""" | ||
_data = np.random.uniform(low=low, high=high, size=(rows, cols)) | ||
matrix = cls.from_array(_data) | ||
return matrix | ||
|
||
@classmethod | ||
def random_column(cls, rows: int, low: float, high: float) -> Matrix: | ||
""" | ||
Create column Matrix with random values in specified range. | ||
Parameters: | ||
rows (int): Number of rows in matrix | ||
low (float): Lower boundary for random number | ||
high (float): Upper boundary for random number | ||
Returns: | ||
matrix (Matrix): Column Matrix with random values | ||
""" | ||
matrix = cls.random_matrix(rows=rows, cols=1, low=low, high=high) | ||
return matrix | ||
|
||
@staticmethod | ||
def add(matrix: Matrix, other_matrix: Matrix) -> Matrix: | ||
""" | ||
Add two Matrix objects. | ||
Parameters: | ||
matrix (Matrix): Matrix to use in sum | ||
other_matrix (Matrix): Other Matrix to use in sum | ||
Returns: | ||
new_matrix (Matrix): Sum of both matrices | ||
""" | ||
new_matrix = matrix.data + other_matrix.data | ||
return Matrix.from_array(new_matrix) | ||
|
||
@staticmethod | ||
def subtract(matrix: Matrix, other_matrix: Matrix) -> Matrix: | ||
""" | ||
Subtract two Matrix objects. | ||
Parameters: | ||
matrix (Matrix): Matrix to use in subtraction | ||
other_matrix (Matrix): Other Matrix to use in subtraction | ||
Returns: | ||
new_matrix (Matrix): Difference between both matrices | ||
""" | ||
new_matrix = matrix.data - other_matrix.data | ||
return Matrix.from_array(new_matrix) | ||
|
||
@staticmethod | ||
def multiply(matrix: Matrix, val: Matrix | float) -> Matrix: | ||
""" | ||
Multiply Matrix with scalar or Matrix. | ||
Parameters: | ||
matrix (Matrix): Matrix to to use for multiplication | ||
val (Matrix | float): Matrix or scalar to use for multiplication | ||
Returns: | ||
new_matrix (Matrix): Multiplied Matrix | ||
""" | ||
if isinstance(val, Matrix): | ||
val = val.data | ||
new_matrix = matrix.data.dot(val) | ||
return Matrix.from_array(new_matrix) | ||
|
||
@staticmethod | ||
def multiply_element_wise(matrix: Matrix, other_matrix: Matrix) -> Matrix: | ||
""" | ||
Multiply Matrix element wise with Matrix. | ||
Parameters: | ||
matrix (Matrix): Matrix to use for multiplication | ||
other_matrix (Matrix): Other Matrix to use for multiplication | ||
Returns: | ||
new_matrix (Matrix): Multiplied Matrix | ||
""" | ||
new_matrix = matrix.data * other_matrix.data | ||
return Matrix.from_array(new_matrix) | ||
|
||
@staticmethod | ||
def transpose(matrix: Matrix) -> Matrix: | ||
""" | ||
Return transpose of Matrix. | ||
Parameters: | ||
matrix (Matrix): Matrix to transpose | ||
Returns: | ||
new_matrix (Matrix): Transposed Matrix | ||
""" | ||
new_matrix = matrix.data.transpose() | ||
return Matrix.from_array(new_matrix) | ||
|
||
@staticmethod | ||
def map(matrix: Matrix, func: Callable) -> Matrix: | ||
""" | ||
Map all values of Matrix through specified function. | ||
Parameters: | ||
matrix (Matrix): Matrix to map | ||
Returns: | ||
new_matrix (Matrix): Matrix with mapped values | ||
""" | ||
new_matrix = np.vectorize(func)(matrix.data) | ||
return Matrix.from_array(new_matrix) |
Oops, something went wrong.