@@ -38,8 +38,9 @@ def __init__(self, features: list[list[float]], labels: list[int]) -> None:
3838 self .y = np .array (labels )
3939 self .class_weights = {0 : 1.0 , 1 : 1.0 } # Example class weights, adjust as needed
4040
41- def get_train_test_data (self ) -> tuple [list [np .ndarray ],
42- list [np .ndarray ], list [np .ndarray ], list [np .ndarray ]]:
41+ def get_train_test_data (
42+ self ,
43+ ) -> tuple [list [np .ndarray ], list [np .ndarray ], list [np .ndarray ], list [np .ndarray ]]:
4344 """
4445 Splits the data into training and testing sets.
4546 Here, we manually split the data.
@@ -52,16 +53,18 @@ def get_train_test_data(self) -> tuple[list[np.ndarray],
5253 - Test labels
5354 """
5455 train_data = np .array ([self .X [0 ], self .X [1 ], self .X [2 ]])
55- train_labels = [np .array ([self .y [0 ]]), np .array ([self .y [1 ]]),
56- np .array ([self .y [2 ]])]
56+ train_labels = [
57+ np .array ([self .y [0 ]]),
58+ np .array ([self .y [1 ]]),
59+ np .array ([self .y [2 ]]),
60+ ]
5761 test_data = np .array ([self .X [3 ]])
5862 test_labels = [np .array ([self .y [3 ]])]
5963 return train_data , train_labels , test_data , test_labels
6064
6165 def shuffle_data (
62- self ,
63- paired_data : list [tuple [np .ndarray , int ]]
64- ) -> list [tuple [np .ndarray , int ]]:
66+ self , paired_data : list [tuple [np .ndarray , int ]]
67+ ) -> list [tuple [np .ndarray , int ]]:
6568 """
6669 Shuffles the data randomly.
6770
@@ -99,41 +102,43 @@ def one_hot_encode(labels: list[int], num_classes: int) -> np.ndarray:
99102
100103class MLP :
101104 """
102- A custom MLP class for implementing a simple multi-layer perceptron with
103- forward propagation, backpropagation.
104-
105- Attributes:
106- learning_rate (float): Learning rate for gradient descent.
107- gamma (float): Parameter to control learning rate adjustment.
108- epoch (int): Number of epochs for training.
109- hidden_dim (int): Dimension of the hidden layer.
110- batch_size (int): Number of samples per mini-batch.
111- train_loss (List[float]): List to store training loss for each fold.
112- train_accuracy (List[float]): List to store training accuracy for each fold.
113- test_loss (List[float]): List to store test loss for each fold.
114- test_accuracy (List[float]): List to store test accuracy for each fold.
115- dataloader (Dataloader): DataLoader object for handling training data.
116- inter_variable (dict): Dictionary to store intermediate variables
117- for backpropagation.
118- weights1_list (List[Tuple[np.ndarray, np.ndarray]]):
119- List of weights for each fold.
120-
121- Methods:
122- get_inout_dim:obtain input dimension and output dimension.
123- relu: Apply the ReLU activation function.
124- relu_derivative: Compute the derivative of the ReLU function.
125- forward: Perform a forward pass through the network.
126- back_prop: Perform backpropagation to compute gradients.
127- update_weights: Update the weights using gradients.
128- update_learning_rate: Adjust the learning rate based on test accuracy.
129- accuracy: Compute accuracy of the model.
130- loss: Compute weighted MSE loss.
131- train: Train the MLP over multiple folds with early stopping.
132-
133-
134- """
135- def __init__ (self , dataloader , epoch : int , learning_rate : float ,
136- gamma = 1 , hidden_dim = 2 ):
105+ A custom MLP class for implementing a simple multi-layer perceptron with
106+ forward propagation, backpropagation.
107+
108+ Attributes:
109+ learning_rate (float): Learning rate for gradient descent.
110+ gamma (float): Parameter to control learning rate adjustment.
111+ epoch (int): Number of epochs for training.
112+ hidden_dim (int): Dimension of the hidden layer.
113+ batch_size (int): Number of samples per mini-batch.
114+ train_loss (List[float]): List to store training loss for each fold.
115+ train_accuracy (List[float]): List to store training accuracy for each fold.
116+ test_loss (List[float]): List to store test loss for each fold.
117+ test_accuracy (List[float]): List to store test accuracy for each fold.
118+ dataloader (Dataloader): DataLoader object for handling training data.
119+ inter_variable (dict): Dictionary to store intermediate variables
120+ for backpropagation.
121+ weights1_list (List[Tuple[np.ndarray, np.ndarray]]):
122+ List of weights for each fold.
123+
124+ Methods:
125+ get_inout_dim:obtain input dimension and output dimension.
126+ relu: Apply the ReLU activation function.
127+ relu_derivative: Compute the derivative of the ReLU function.
128+ forward: Perform a forward pass through the network.
129+ back_prop: Perform backpropagation to compute gradients.
130+ update_weights: Update the weights using gradients.
131+ update_learning_rate: Adjust the learning rate based on test accuracy.
132+ accuracy: Compute accuracy of the model.
133+ loss: Compute weighted MSE loss.
134+ train: Train the MLP over multiple folds with early stopping.
135+
136+
137+ """
138+
139+ def __init__ (
140+ self , dataloader , epoch : int , learning_rate : float , gamma = 1 , hidden_dim = 2
141+ ):
137142 self .learning_rate = learning_rate
138143 self .gamma = gamma # learning_rate decay hyperparameter gamma
139144 self .epoch = epoch
@@ -216,13 +221,12 @@ def relu_derivative(self, input_array: np.ndarray) -> np.ndarray:
216221 """
217222 return (input_array > 0 ).astype (float )
218223
219-
220224 def forward (
221- self ,
222- input_data : np .ndarray ,
223- w1 : np .ndarray ,
224- w2 : np .ndarray ,
225- no_gradient : bool = False
225+ self ,
226+ input_data : np .ndarray ,
227+ w1 : np .ndarray ,
228+ w2 : np .ndarray ,
229+ no_gradient : bool = False ,
226230 ) -> np .ndarray :
227231 """
228232 Performs a forward pass through the neural network with one hidden layer.
@@ -264,10 +268,7 @@ def forward(
264268 return a2
265269
266270 def back_prop (
267- self ,
268- input_data : np .ndarray ,
269- true_labels : np .ndarray ,
270- w2 : np .ndarray
271+ self , input_data : np .ndarray , true_labels : np .ndarray , w2 : np .ndarray
271272 ) -> tuple [np .ndarray , np .ndarray ]:
272273 """
273274 Performs backpropagation to compute gradients for the weights.
@@ -315,12 +316,12 @@ def back_prop(
315316 return grad_w1 , grad_w2
316317
317318 def update_weights (
318- self ,
319- w1 : np .ndarray ,
320- w2 : np .ndarray ,
321- grad_w1 : np .ndarray ,
322- grad_w2 : np .ndarray ,
323- learning_rate : float
319+ self ,
320+ w1 : np .ndarray ,
321+ w2 : np .ndarray ,
322+ grad_w1 : np .ndarray ,
323+ grad_w2 : np .ndarray ,
324+ learning_rate : float ,
324325 ) -> tuple [np .ndarray , np .ndarray ]:
325326 """
326327 Updates the weight matrices using the computed gradients and learning rate.
@@ -359,7 +360,6 @@ def update_weights(
359360 w2 -= learning_rate * grad_w2
360361 return w1 , w2
361362
362-
363363 def update_learning_rate (self , learning_rate : float ) -> float :
364364 """
365365 Updates the learning rate by applying the decay factor gamma.
@@ -456,13 +456,13 @@ def train(self) -> None:
456456 """
457457
458458 learning_rate = self .learning_rate
459- train_data , train_labels , test_data , test_labels = \
460- self .dataloader .get_train_test_data ()
459+ train_data , train_labels , test_data , test_labels = (
460+ self .dataloader .get_train_test_data ()
461+ )
461462
462463 train_data = np .c_ [train_data , np .ones (train_data .shape [0 ])]
463464 test_data = np .c_ [test_data , np .ones (test_data .shape [0 ])]
464465
465-
466466 _ , total_label_num = self .dataloader .get_inout_dim ()
467467
468468 train_labels = self .dataloader .one_hot_encode (train_labels , total_label_num )
@@ -476,14 +476,14 @@ def train(self) -> None:
476476
477477 for _j in tqdm (range (self .epoch )):
478478 for k in range (0 , train_data .shape [0 ], batch_size ): # retrieve every image
479-
480- batch_imgs = train_data [k : k + batch_size ]
481- batch_labels = train_labels [k : k + batch_size ]
479+ batch_imgs = train_data [k : k + batch_size ]
480+ batch_labels = train_labels [k : k + batch_size ]
482481
483482 self .forward (input_data = batch_imgs , w1 = w1 , w2 = w2 , no_gradient = False )
484483
485- grad_w1 , grad_w2 = self .back_prop (input_data = batch_imgs , \
486- true_labels = batch_labels , w2 = w2 )
484+ grad_w1 , grad_w2 = self .back_prop (
485+ input_data = batch_imgs , true_labels = batch_labels , w2 = w2
486+ )
487487
488488 w1 , w2 = self .update_weights (w1 , w2 , grad_w1 , grad_w2 , learning_rate )
489489
@@ -498,7 +498,7 @@ def train(self) -> None:
498498
499499 self .test_accuracy = test_accuracy_list
500500 self .test_loss = test_loss_list
501- print ("Test accuracy:" , sum (test_accuracy_list )/ len (test_accuracy_list ))
501+ print ("Test accuracy:" , sum (test_accuracy_list ) / len (test_accuracy_list ))
502502
503503
504504if __name__ == "__main__" :
0 commit comments