From 7eb148ea9a71c78a68aca89f5d44cc6ccff78d25 Mon Sep 17 00:00:00 2001 From: hasnainroopawalla Date: Thu, 21 Jul 2022 09:43:52 +0530 Subject: [PATCH 1/3] Added a downloads badge to the README --- README.md | 7 ++++++- setup.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9a4eead..4815d5f 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![Deploy](https://github.com/hasnainroopawalla/ShowML/actions/workflows/deploy.yml/badge.svg)](https://github.com/hasnainroopawalla/ShowML/actions/workflows/deploy.yml) [![PyPi version](https://img.shields.io/pypi/v/showml.svg)](https://pypi.python.org/pypi/showml/) [![Python versions](https://img.shields.io/pypi/pyversions/showml.svg?style=plastic)](https://img.shields.io/pypi/pyversions/showml.svg?style=plastic) -![Status](https://img.shields.io/badge/status-stable-green.svg) +![Downloads](https://img.shields.io/pypi/dm/showml.svg) A Python package of Machine Learning Algorithms implemented from scratch. @@ -23,6 +23,7 @@ The aim of this package is to present the working behind fundamental Machine Lea - [Getting Started](#getting_started) - [Contents](#contents) - [Contributing](#contributing) +- [License](#license) ## 🏁 Getting Started @@ -104,3 +105,7 @@ _ShowML_ currently includes the following content, however, this repository will $ pytest ``` 5. Open a Pull Request and I'll review it. + + +## 📄 License +This project is licensed under the MIT License - see the [LICENSE](https://github.com/hasnainroopawalla/ShowML/blob/bbaacc81779437ea2ef09d7869b1f8a824f80353/LICENSE) file for details. diff --git a/setup.py b/setup.py index 73ccc29..7624ea0 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setup( name="showml", - version="1.5.11", + version="1.5.12", packages=find_packages(exclude="tests"), description="A Python package of Machine Learning Algorithms implemented from scratch", long_description=long_description, From c43db1d41d3bddfccdc218e135f8aae7b46076c5 Mon Sep 17 00:00:00 2001 From: hasnainroopawalla Date: Thu, 21 Jul 2022 09:45:47 +0530 Subject: [PATCH 2/3] Updated pre-commit hooks versions --- .pre-commit-config.yaml | 8 ++++---- showml/deep_learning/activations.py | 9 +++------ showml/deep_learning/base_layer.py | 3 +-- showml/deep_learning/layers.py | 3 +-- showml/deep_learning/model.py | 12 ++++-------- showml/linear_model/regression.py | 6 ++---- showml/losses/loss_functions.py | 6 ++---- showml/optimizers/base_optimizer.py | 3 +-- showml/simulations/conways_game_of_life/event.py | 6 ++---- .../conways_game_of_life/event_handler.py | 3 +-- .../conways_game_of_life/game_of_life.py | 15 +++++---------- .../conways_game_of_life/game_window.py | 9 +++------ showml/simulations/conways_game_of_life/grid.py | 6 ++---- showml/utils/dataset.py | 6 ++---- showml/utils/exceptions.py | 12 ++++-------- 15 files changed, 37 insertions(+), 70 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e20dc32..fd3d49b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,10 +1,10 @@ repos: - repo: https://github.com/ambv/black - rev: 19.3b0 + rev: 22.6.0 hooks: - - id: black + - id: black - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v4.3.0 hooks: - id: check-yaml - id: check-toml @@ -16,7 +16,7 @@ repos: args: - --maxkb=1000 - repo: https://github.com/Lucas-C/pre-commit-hooks - rev: v1.1.10 + rev: v1.3.0 hooks: - id: remove-crlf - id: remove-tabs diff --git a/showml/deep_learning/activations.py b/showml/deep_learning/activations.py index f000ee4..ee49ea8 100644 --- a/showml/deep_learning/activations.py +++ b/showml/deep_learning/activations.py @@ -3,8 +3,7 @@ class Sigmoid(Activation): - """A layer which applies the Sigmoid operation to an input. - """ + """A layer which applies the Sigmoid operation to an input.""" def forward(self, X: np.ndarray) -> np.ndarray: return 1 / (1 + np.exp(-X)) @@ -14,8 +13,7 @@ def backward(self, X: np.ndarray) -> np.ndarray: class Relu(Activation): - """A layer which applies the ReLU operation to an input. - """ + """A layer which applies the ReLU operation to an input.""" def forward(self, X: np.ndarray) -> np.ndarray: return abs(X) * (X > 0) @@ -25,8 +23,7 @@ def backward(self, X: np.ndarray) -> np.ndarray: class Softmax(Activation): - """A layer which applies the Softmax operation to an input. - """ + """A layer which applies the Softmax operation to an input.""" def forward(self, X: np.ndarray) -> np.ndarray: e_x = np.exp(X - np.max(X, axis=-1, keepdims=True)) diff --git a/showml/deep_learning/base_layer.py b/showml/deep_learning/base_layer.py index 548ad60..50fa3bd 100644 --- a/showml/deep_learning/base_layer.py +++ b/showml/deep_learning/base_layer.py @@ -5,8 +5,7 @@ class Layer(ABC): - """A layer class. - """ + """A layer class.""" def __init__( self, input_shape: Tuple[int] = (0,), has_weights: bool = True diff --git a/showml/deep_learning/layers.py b/showml/deep_learning/layers.py index 895662f..b95e440 100644 --- a/showml/deep_learning/layers.py +++ b/showml/deep_learning/layers.py @@ -5,8 +5,7 @@ class Dense(Layer): - """A Dense Layer. - """ + """A Dense Layer.""" def __init__(self, num_nodes: int, input_shape: Tuple[int] = (0,)): """Constructor for the Dense Layer. diff --git a/showml/deep_learning/model.py b/showml/deep_learning/model.py index 67c1a70..6519aa2 100644 --- a/showml/deep_learning/model.py +++ b/showml/deep_learning/model.py @@ -10,12 +10,10 @@ class Sequential: - """A Sequential model (deep neural network) with various types of layers and activation functions. - """ + """A Sequential model (deep neural network) with various types of layers and activation functions.""" def __init__(self) -> None: - """Constructor for the Sequential model class. - """ + """Constructor for the Sequential model class.""" self.layers: List[Layer] = [] def compile( @@ -39,8 +37,7 @@ def compile( self.initialize_layers() def initialize_layers(self) -> None: - """Initializes all the layers with the specified optimizer and parameters. - """ + """Initializes all the layers with the specified optimizer and parameters.""" for layer_idx, layer in enumerate(self.layers): if layer_idx > 0: # If this layer is NOT the first layer of the network, then input shape = output shape of previous layer @@ -132,8 +129,7 @@ def predict(self, X: np.ndarray) -> np.ndarray: return self.forward_pass(X) def summary(self) -> None: - """Summarizes the model by displaying all layers, their parameters and total number of trainable parameters. - """ + """Summarizes the model by displaying all layers, their parameters and total number of trainable parameters.""" total_params = 0 print(AsciiTable([[self.__class__.__name__]]).table) summary_data = [["Layer", "Params", "Output Shape"]] diff --git a/showml/linear_model/regression.py b/showml/linear_model/regression.py index 349ca86..d5f0259 100644 --- a/showml/linear_model/regression.py +++ b/showml/linear_model/regression.py @@ -11,8 +11,7 @@ class Regression(ABC): - """Base Regression class. - """ + """Base Regression class.""" def compile( self, optimizer: Optimizer, loss: Loss, metrics: List[Callable] = [] @@ -62,8 +61,7 @@ def evaluate(self, X: np.ndarray, y: np.ndarray) -> None: print(text_to_display) def plot_metrics(self) -> None: - """Display the plot after training for the specified metrics - """ + """Display the plot after training for the specified metrics""" for metric in self.history: generic_metric_plot(metric, self.history[metric]) diff --git a/showml/losses/loss_functions.py b/showml/losses/loss_functions.py index 18a1e79..2b58cda 100644 --- a/showml/losses/loss_functions.py +++ b/showml/losses/loss_functions.py @@ -23,8 +23,7 @@ def parameter_gradient( class BinaryCrossEntropy(Loss): def objective(self, y: np.ndarray, z: np.ndarray) -> float: - """Also known as Log Loss - """ + """Also known as Log Loss""" num_samples = len(y) # Avoid division by zero z = np.clip(z, 1e-15, 1 - 1e-15) @@ -46,8 +45,7 @@ def parameter_gradient( class CrossEntropy(Loss): def objective(self, y: np.ndarray, z: np.ndarray) -> float: - """param y: one hot encoded values - """ + """param y: one hot encoded values""" num_samples = len(z) z = np.clip(z, 1e-15, 1.0 - 1e-15) return -np.sum(y * np.log(z)) / num_samples diff --git a/showml/optimizers/base_optimizer.py b/showml/optimizers/base_optimizer.py index 6a4363d..b3d49af 100644 --- a/showml/optimizers/base_optimizer.py +++ b/showml/optimizers/base_optimizer.py @@ -4,8 +4,7 @@ class Optimizer(ABC): - """The Base Optimizer Class. - """ + """The Base Optimizer Class.""" def __init__(self, learning_rate: float): """Constructor for the Base Optimzer class. diff --git a/showml/simulations/conways_game_of_life/event.py b/showml/simulations/conways_game_of_life/event.py index b960e7c..ad2653a 100644 --- a/showml/simulations/conways_game_of_life/event.py +++ b/showml/simulations/conways_game_of_life/event.py @@ -3,8 +3,7 @@ class Action(Enum): - """This class defines the different Actions in the game. - """ + """This class defines the different Actions in the game.""" START = auto() STOP = auto() @@ -15,8 +14,7 @@ class Action(Enum): @dataclass class Event: - """This class defines an Event (and also the row, column if a cell is toggled) - """ + """This class defines an Event (and also the row, column if a cell is toggled)""" action: Action row: int = 0 diff --git a/showml/simulations/conways_game_of_life/event_handler.py b/showml/simulations/conways_game_of_life/event_handler.py index e5634eb..05d4453 100644 --- a/showml/simulations/conways_game_of_life/event_handler.py +++ b/showml/simulations/conways_game_of_life/event_handler.py @@ -4,8 +4,7 @@ class EventHandler: - """The EventHandler class responsible for observing events taking place in the window as well as initializing and managing the Grid. - """ + """The EventHandler class responsible for observing events taking place in the window as well as initializing and managing the Grid.""" def __init__(self, window: GameWindow) -> None: """Constructor for the EventHandler class. diff --git a/showml/simulations/conways_game_of_life/game_of_life.py b/showml/simulations/conways_game_of_life/game_of_life.py index 7107801..5a2eb4b 100644 --- a/showml/simulations/conways_game_of_life/game_of_life.py +++ b/showml/simulations/conways_game_of_life/game_of_life.py @@ -5,8 +5,7 @@ class GameOfLife: - """A simulation of Conway's Game of Life (Cellular Automaton): https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life - """ + """A simulation of Conway's Game of Life (Cellular Automaton): https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life""" def __init__(self, num_rows: int = 50, num_columns: int = 100) -> None: """Constructor for the GameOfLife class. @@ -28,20 +27,17 @@ def __init__(self, num_rows: int = 50, num_columns: int = 100) -> None: } def start_event(self, row: int, column: int) -> None: - """This method runs when the game starts. - """ + """This method runs when the game starts.""" self.game_running = True self.delay = 150 def stop_event(self, row: int, column: int) -> None: - """This method runs when the game is stopped. - """ + """This method runs when the game is stopped.""" self.game_running = False self.delay = 0 def reset_event(self, row: int, column: int) -> None: - """This method runs when the RESET button is pressed. - """ + """This method runs when the RESET button is pressed.""" self.game_running = False self.window.grid.reset_grid() self.delay = 0 @@ -59,8 +55,7 @@ def no_event(self, row: int, column: int) -> None: pass def run(self) -> None: - """This method runs the game loop by communicating with the EventHandler to receive event information. - """ + """This method runs the game loop by communicating with the EventHandler to receive event information.""" while True: if self.game_running: self.window.grid.update_grid() diff --git a/showml/simulations/conways_game_of_life/game_window.py b/showml/simulations/conways_game_of_life/game_window.py index a5b1f8f..b9a6963 100644 --- a/showml/simulations/conways_game_of_life/game_window.py +++ b/showml/simulations/conways_game_of_life/game_window.py @@ -11,8 +11,7 @@ class GameWindow: - """The GameWindow class responsible for observing events taking place in the window as well as initializing and managing the Grid. - """ + """The GameWindow class responsible for observing events taking place in the window as well as initializing and managing the Grid.""" def __init__(self, grid: Grid) -> None: """Constructor for the GameWindow class. @@ -55,8 +54,7 @@ def display_window_and_grid(self, delay: int) -> None: self.clock.tick(60) def _display_buttons_and_text(self) -> None: - """This private method displays the buttons and the text objects in the window. - """ + """This private method displays the buttons and the text objects in the window.""" self.SCREEN.fill(Color.BLACK) for button in self.buttons: # Button @@ -75,8 +73,7 @@ def _display_buttons_and_text(self) -> None: ) def _display_grid(self) -> None: - """This private method displays the entire grid in the window. - """ + """This private method displays the entire grid in the window.""" for row in range(self.grid.num_rows): for column in range(self.grid.num_columns): if self.grid.grid[row][column] == 1: diff --git a/showml/simulations/conways_game_of_life/grid.py b/showml/simulations/conways_game_of_life/grid.py index bed8b4d..7870691 100644 --- a/showml/simulations/conways_game_of_life/grid.py +++ b/showml/simulations/conways_game_of_life/grid.py @@ -2,8 +2,7 @@ class Grid: - """A 2D Grid class to display the cells. - """ + """A 2D Grid class to display the cells.""" def __init__(self, num_rows: int, num_columns: int) -> None: """[summary] @@ -60,8 +59,7 @@ def update_grid(self) -> None: self.grid = new_grid def reset_grid(self) -> None: - """This method resets the grid i.e., kills all the cells. - """ + """This method resets the grid i.e., kills all the cells.""" self.grid = np.zeros((self.num_rows, self.num_columns)) def toggle_cell_value(self, row: int, column: int) -> None: diff --git a/showml/utils/dataset.py b/showml/utils/dataset.py index 8f3c7a7..e987a48 100644 --- a/showml/utils/dataset.py +++ b/showml/utils/dataset.py @@ -23,14 +23,12 @@ def __init__(self, X: np.ndarray, y: np.ndarray) -> None: self.valid_dataset_length() def validate_data_types(self) -> None: - """Validates if X and y are NumPy arrays (np.ndarray). - """ + """Validates if X and y are NumPy arrays (np.ndarray).""" if not (isinstance(self.X, np.ndarray) and isinstance(self.y, np.ndarray)): raise DataTypeError("X and y must be NumPy arrays (np.ndarray)") def valid_dataset_length(self) -> None: - """Validates if X and y have the same number of samples. - """ + """Validates if X and y have the same number of samples.""" if self.X.shape[0] != self.y.shape[0]: raise DatasetSizeMismatchError( "Dimension 1 (number of samples) of X and y must the same" diff --git a/showml/utils/exceptions.py b/showml/utils/exceptions.py index 93b5696..528f54b 100644 --- a/showml/utils/exceptions.py +++ b/showml/utils/exceptions.py @@ -1,18 +1,14 @@ class DatasetSizeMismatchError(Exception): - """Raised when X and y have different lengths. - """ + """Raised when X and y have different lengths.""" class DataTypeError(Exception): - """Raised when a variable has an unexpected datatype. - """ + """Raised when a variable has an unexpected datatype.""" class InvalidShapeError(Exception): - """Raised when an unexpected array shape is encountered. - """ + """Raised when an unexpected array shape is encountered.""" class InvalidValueError(Exception): - """Raised when an unexpected value is encountered. - """ + """Raised when an unexpected value is encountered.""" From 4efec7daf422ce91b9dd24c00c1217f3661ec309 Mon Sep 17 00:00:00 2001 From: hasnainroopawalla Date: Thu, 21 Jul 2022 09:49:07 +0530 Subject: [PATCH 3/3] Type casted layer params count to int --- showml/deep_learning/layers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/showml/deep_learning/layers.py b/showml/deep_learning/layers.py index b95e440..6ac0d26 100644 --- a/showml/deep_learning/layers.py +++ b/showml/deep_learning/layers.py @@ -26,7 +26,7 @@ def initialize_params(self, optimizer: Optimizer) -> None: self.bias = np.zeros((1, self.num_nodes)) def get_params_count(self) -> int: - return np.prod(self.weights.shape) + np.prod(self.bias.shape) + return int(np.prod(self.weights.shape) + np.prod(self.bias.shape)) def get_output_shape(self) -> Tuple[int]: return (self.num_nodes,)