8000 add a code file of the multi-layer perceptron classifier from scrach by WeiYFan · Pull Request #12754 · TheAlgorithms/Python · GitHub
[go: up one dir, main page]

Skip to content

add a code file of the multi-layer perceptron classifier from scrach #12754

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
Closed
Prev Previous commit
Next Next commit
Update multilayer_perceptron_classifier_from_scratch.py
  • Loading branch information
WeiYFan authored May 14, 2025
commit 38ee6e2a255f58f45cedfd75c308c35eb849d035
66 changes: 44 additions & 22 deletions machine_learning/multilayer_perceptron_classifier_from_scratch.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import numpy as np
from numpy.random import default_rng
from tqdm import tqdm

Check failure on line 3 in machine_learning/multilayer_perceptron_classifier_from_scratch.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

machine_learning/multilayer_perceptron_classifier_from_scratch.py:1:1: I001 Import block is un-sorted or un-formatted
rng = default_rng(42)
class Dataloader:
"""
Expand Down Expand Up @@ -51,7 +51,9 @@
self.y = np.array(labels)
self.class_weights = {0: 1.0, 1: 1.0}

def get_train_test_data(self) -> tuple[list[np.ndarray], list[np.ndarray], list[np.ndarray], list[np.ndarray]]:
def get_train_test_data(
self
) -> tuple[list[np.ndarray], list[np.ndarray], list[np.ndarray], list[np.ndarray]]:
"""
Splits the data into training and testing sets.
Here, we manually split the data.
Expand All @@ -63,13 +65,17 @@
- Test data
- Test labels
"""
train_data = np.array([self.X[0], self.X[1], self.X[2]]) # First 3 samples for training
train_labels = [np.array([self.y[0]]), np.array([self.y[1]]), np.array([self.y[2]])]
train_data = np.array([self.X[0], self.X[1], self.X[2]])

Check failure on line 68 in machine_learning/multilayer_perceptron_classifier_from_scratch.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W291)

machine_learning/multilayer_perceptron_classifier_from_scratch.py:68:65: W291 Trailing whitespace
train_labels = \
[np.array([self.y[0]]), np.array([self.y[1]]), np.array([self.y[2]])]
test_data = np.array([self.X[3]]) # Last sample for testing
test_labels = [np.array([self.y[3]])] # Labels as np.ndarray
return train_data, train_labels, test_data, test_labels

def shuffle_data(self, paired_data: list[tuple[np.ndarray, int]]) -> list[tuple[np.ndarray, int]]:
def shuffle_data(
self,
paired_data: list[tuple[np.ndarray, int]]
) -> list[tuple[np.ndarray, int]]:
"""
Shuffles the data randomly.

Expand All @@ -84,7 +90,8 @@
return paired_data

def get_inout_dim(self) -> tuple[int, int]:
train_data, train_labels, test_data, test_labels = self.get_train_test_data()
train_data, train_labels, test_data, test_labels = (
self.get_train_test_data())
in_dim = train_data[0].shape[0]
out_dim = len(train_labels)
return in_dim, out_dim
Expand All @@ -107,7 +114,7 @@
return one_hot


class MLP():

Check failure on line 117 in machine_learning/multilayer_perceptron_classifier_from_scratch.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP039)

machine_learning/multilayer_perceptron_classifier_from_scratch.py:117:10: UP039 Unnecessary parentheses after class definition
"""
A custom MLP class for implementing a simple multi-layer perceptron with
forward propagation, backpropagation.
Expand Down Expand Up @@ -203,9 +210,11 @@
(2, 3)
"""

in_dim, out_dim = self.dataloader.get_inout_dim() # in_dim here is image dim
w1 = rng.standard_normal((in_dim + 1, self.hidden_dim)) * np.sqrt(2.0 / in_dim)
w2 = rng.standard_normal((self.hidden_dim, out_dim)) * np.sqrt(2.0 / self.hidden_dim)
in_dim, out_dim = self.dataloader.get_inout_dim()
w1 = (rng.standard_normal((in_dim + 1, self.hidden_dim))
* np.sqrt(2.0 / in_dim))
w2 = (rng.standard_normal((self.hidden_dim, out_dim))
* np.sqrt(2.0 / self.hidden_dim))
return w1, w2

def relu(self, input_array: np.ndarray) -> np.ndarray:
Expand Down Expand Up @@ -256,7 +265,8 @@
no_gradient: If True, returns output without storing intermediates.

Returns:
Output of the network after forward pass, shape (batch_size, output_dim).
Output of the network after forward pass,

Check failure on line 268 in machine_learning/multilayer_perceptron_classifier_from_scratch.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W291)

machine_learning/multilayer_perceptron_classifier_from_scratch.py:268:54: W291 Trailing whitespace
shape (batch_size, output_dim).

Examples:
>>> mlp = MLP(None, 1, 0.1, hidden_dim=2)
Expand Down Expand Up @@ -334,11 +344,11 @@

grad_w2 = (
np.dot(a1.T, delta_k) / batch_size
) # (hidden, batch).dot(batch, output) = (hidden, output)
input_data_flat = input_data.reshape(input_data.shape[0], -1) # (batch_size, input_dim)
)

Check failure on line 347 in machine_learning/multilayer_perceptron_classifier_from_scratch.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W291)

machine_learning/multilayer_perceptron_classifier_from_scratch.py:347:10: W291 Trailing whitespace
input_data_flat = input_data.reshape(input_data.shape[0], -1)

Check failure on line 348 in machine_learning/multilayer_perceptron_classifier_from_scratch.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W291)

machine_learning/multilayer_perceptron_classifier_from_scratch.py:348:70: W291 Trailing whitespace
grad_w1 = (
np.dot(input_data_flat.T, delta_j) / batch_size
) # (input_dim, batch_size).dot(batch, hidden) = (input, hidden)
)

Check failure on line 351 in machine_learning/multilayer_perceptron_classifier_from_scratch.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W291)

machine_learning/multilayer_perceptron_classifier_from_scratch.py:351:10: W291 Trailing whitespace

return grad_w1, grad_w2

Expand All @@ -351,11 +361,14 @@
learning_rate: float
) -> tuple[np.ndarray, np.ndarray]:
"""
Updates the weight matrices using the computed gradients and learning rate.
Updates the weight matrices using

Check failure on line 364 in machine_learning/multilayer_perceptron_classifier_from_scratch.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W291)

machine_learning/multilayer_perceptron_classifier_from_scratch.py:364:42: W291 Trailing whitespace
the computed gradients and learning rate.

Args:
w1: Weight matrix for input to hidden layer, shape (input_dim + 1, hidden_dim).
w2: Weight matrix for hidden to output layer, shape (hidden_dim, output_dim).
w1: Weight matrix for input to hidden layer, shape

Check failure on line 368 in machine_learning/multilayer_perceptron_classifier_from_scratch.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W291)

machine_learning/multilayer_perceptron_classifier_from_scratch.py:368:63: W291 Trailing whitespace
(input_dim + 1, hidden_dim).
w2: Weight matrix for hidden to output layer, shape

Check failure on line 370 in machine_learning/multilayer_perceptron_classifier_from_scratch.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W291)

machine_learning/multilayer_perceptron_classifier_from_scratch.py:370:64: W291 Trailing whitespace
(hidden_dim, output_dim).
grad_w1: Gradient for w1, shape (input_dim + 1, hidden_dim).
grad_w2: Gradient for w2, shape (hidden_dim, output_dim).
learning_rate: Learning rate for weight updates.
Expand Down Expand Up @@ -405,7 +418,8 @@
@staticmethod
def accuracy(label: np.ndarray, y_hat: np.ndarray) -> float:
"""
Computes the accuracy of predictions by comparing predicted and true labels.
Computes the accuracy of predictions
by comparing predicted and true labels.

Args:
label: True labels, shape (batch_size, num_classes).
Expand All @@ -426,7 +440,8 @@
@staticmethod
def loss(output: np.ndarray, label: np.ndarray) -> float:
"""
Computes the mean squared error loss between predictions and true labels.
Computes the mean squared error loss
between predictions and true labels.

Args:
output: Predicted outputs, shape (batch_size, num_classes).
Expand Down Expand Up @@ -465,9 +480,11 @@

def train(self) -> None:
"""
Trains the MLP model using the provided dataloader for multiple folds and epochs.
Trains the MLP model using the provided dataloader
for multiple folds and epochs.

Saves the best model parameters for each fold and records accuracy/loss.
Saves the best model parameters
for each fold and records accuracy/loss.

Examples:
>>> X = [[0.0, 0.0], [1.0, 1.0], [1.0, 0.0], [0.0, 1.0]]
Expand All @@ -479,7 +496,8 @@
"""

learning_rate = self.learning_rate
train_data, train_labels, test_data, test_labels = self.dataloader.get_train_test_data()
train_data, train_labels, test_data, test_labels = (
self.dataloader.get_train_test_data())

train_data = np.c_[train_data, np.ones(train_data.shape[0])]
test_data = np.c_[test_data, np.ones(test_data.shape[0])]
Expand All @@ -498,12 +516,16 @@
batch_size = 1

for j in tqdm(range(self.epoch)):
for k in range(0, train_data.shape[0], batch_size): # retrieve every image
for k in range(0, train_data.shape[0], batch_size):

batch_imgs = train_data[k: k + batch_size]
batch_labels = train_labels[k: k + batch_size]

output = self.forward(input_data=batch_imgs, w1=w1, w2=w2, no_gradient=False)
output = self.forward(
input_data=batch_imgs,
w1=w1,
w2=w2,
no_gradient=False)

grad_w1, grad_w2 = self.back_prop(
input_data=batch_imgs,
Expand Down
Loading
0