From c5da45cf6710992d928565022f242572cc4afb93 Mon Sep 17 00:00:00 2001 From: Ankit Avinash Date: Wed, 18 Oct 2023 18:27:21 +0530 Subject: [PATCH 1/6] Implemented gradient descent without using explicit for loops --- .../gradient_descent_without_loops.py | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 machine_learning/gradient_descent_without_loops.py diff --git a/machine_learning/gradient_descent_without_loops.py b/machine_learning/gradient_descent_without_loops.py new file mode 100644 index 000000000000..36b33de29244 --- /dev/null +++ b/machine_learning/gradient_descent_without_loops.py @@ -0,0 +1,91 @@ +""" +Implementation of gradient descent algorithm for minimizing cost of a linear hypothesis +function. +""" +import numpy as np + +def random_linear_function(x0, x1, x2): + return -0.44562*x0 + 1.07831*x1 + 0.34078*x2 - 0.60752 + +''' +This is the list of inputs and outputs. +Input shape: (3, m) +Output shape: (1, n) +Each column represents a single training example. +m is the number of training examples. +''' +train_x = np.array([[ 0.013933 , 0.18614919, 0.22363674, 0.18737055, 1.49787963, 1.24865476], + [ 0.00972224, -0.51948611, -0.74649768, 0.38754526, 1.43271505, -1.74150751], + [ 0.49624539, -1.66085244, 0.58543661, 2.47361057, -0.09029329, -0.64871002]]) + +train_y = np.array([[-0.43413473, -1.81662416, -1.31262783, 0.56983487, 0.2391357 , -3.2628979 ]]) + +test_x = np.array([[ 0.28367314, 2.60050588], + [-0.20341425, -0.77734235], + [ 1.07614145, 0.4527949 ]]) + +test_y = np.array([[-0.58654656, -2.45027001]]) + +m = train_x.shape[-1] + +# Randomly initialize weights and biases +weights = np.random.randn(1,3) +bias = np.random.randn(1,1) + +def predict(data_x: np.ndarray, weights: np.ndarray, bias: np.ndarray) -> np.ndarray: + ''' + Returns an array of predictions for an array of inputs. + ''' + return weights @ data_x + bias + +def losses(y_true: np.ndarray, y_predicted: np.ndarray) -> np.ndarray: + ''' + Returns an array of losses for an array of inputs. + ''' + return np.square(y_true - y_predicted) + +def cost(y_true: np.ndarray, y_predicted: np.ndarray) -> float: + ''' + Returns cost function for a model. + Cost is the average of losses over the inputs. + ''' + return np.mean(losses(y_true, y_predicted)) + +def gradient_descent(x: np.ndarray, y: np.ndarray, weights: np.ndarray, bias: np.ndarray, learning_rate=0.001, iterations=10000) -> tuple: + ''' + Uses gradient descent to train the model. + Returns final modified parameters as a tuple (weights, biases). + Prints cost function every 1000 epochs. + ''' + for iteration in range(iterations): + yhat = predict(x, weights, bias) + dz = 2 * (yhat - y) + dw = dz @ x.T / m + db = np.mean(dz) + weights -= learning_rate * dw + bias -= learning_rate * db + + if iteration % 1000 == 0: + print(f'Cost after {iteration} iterations: {cost(y, yhat)}') + + print(f'Final cost: {cost(y, yhat)}\n') + return weights, bias + +def test_gradient_descent(): + ''' + Prints actual output and predicted output side by side for a model. + ''' + global weights, bias + weights, bias = gradient_descent(train_x, train_y, weights, bias, + learning_rate=0.001, iterations=10000) + + predictions = predict(test_x, weights, bias) + print("Testing: ") + for i in range(test_x.shape[-1]): + print(f'Actual output value: {test_y[0, i]} \tPredicted output value: {predictions[0, i]}') + print() + +if __name__ == '__main__': + # test_gradient_descent() + import doctest + doctest.testmod() \ No newline at end of file From f25a35eca367401bf133a232d1c16bcae9bd8841 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 13:03:06 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../gradient_descent_without_loops.py | 89 ++++++++++++------- 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/machine_learning/gradient_descent_without_loops.py b/machine_learning/gradient_descent_without_loops.py index 36b33de29244..ac40a7a4a586 100644 --- a/machine_learning/gradient_descent_without_loops.py +++ b/machine_learning/gradient_descent_without_loops.py @@ -4,59 +4,78 @@ """ import numpy as np + def random_linear_function(x0, x1, x2): - return -0.44562*x0 + 1.07831*x1 + 0.34078*x2 - 0.60752 + return -0.44562 * x0 + 1.07831 * x1 + 0.34078 * x2 - 0.60752 + -''' +""" This is the list of inputs and outputs. Input shape: (3, m) Output shape: (1, n) Each column represents a single training example. m is the number of training examples. -''' -train_x = np.array([[ 0.013933 , 0.18614919, 0.22363674, 0.18737055, 1.49787963, 1.24865476], - [ 0.00972224, -0.51948611, -0.74649768, 0.38754526, 1.43271505, -1.74150751], - [ 0.49624539, -1.66085244, 0.58543661, 2.47361057, -0.09029329, -0.64871002]]) +""" +train_x = np.array( + [ + [0.013933, 0.18614919, 0.22363674, 0.18737055, 1.49787963, 1.24865476], + [0.00972224, -0.51948611, -0.74649768, 0.38754526, 1.43271505, -1.74150751], + [0.49624539, -1.66085244, 0.58543661, 2.47361057, -0.09029329, -0.64871002], + ] +) -train_y = np.array([[-0.43413473, -1.81662416, -1.31262783, 0.56983487, 0.2391357 , -3.2628979 ]]) +train_y = np.array( + [[-0.43413473, -1.81662416, -1.31262783, 0.56983487, 0.2391357, -3.2628979]] +) -test_x = np.array([[ 0.28367314, 2.60050588], - [-0.20341425, -0.77734235], - [ 1.07614145, 0.4527949 ]]) +test_x = np.array( + [[0.28367314, 2.60050588], [-0.20341425, -0.77734235], [1.07614145, 0.4527949]] +) test_y = np.array([[-0.58654656, -2.45027001]]) m = train_x.shape[-1] # Randomly initialize weights and biases -weights = np.random.randn(1,3) -bias = np.random.randn(1,1) +weights = np.random.randn(1, 3) +bias = np.random.randn(1, 1) + def predict(data_x: np.ndarray, weights: np.ndarray, bias: np.ndarray) -> np.ndarray: - ''' + """ Returns an array of predictions for an array of inputs. - ''' + """ return weights @ data_x + bias + def losses(y_true: np.ndarray, y_predicted: np.ndarray) -> np.ndarray: - ''' + """ Returns an array of losses for an array of inputs. - ''' + """ return np.square(y_true - y_predicted) + def cost(y_true: np.ndarray, y_predicted: np.ndarray) -> float: - ''' + """ Returns cost function for a model. Cost is the average of losses over the inputs. - ''' + """ return np.mean(losses(y_true, y_predicted)) -def gradient_descent(x: np.ndarray, y: np.ndarray, weights: np.ndarray, bias: np.ndarray, learning_rate=0.001, iterations=10000) -> tuple: - ''' + +def gradient_descent( + x: np.ndarray, + y: np.ndarray, + weights: np.ndarray, + bias: np.ndarray, + learning_rate=0.001, + iterations=10000, +) -> tuple: + """ Uses gradient descent to train the model. Returns final modified parameters as a tuple (weights, biases). Prints cost function every 1000 epochs. - ''' + """ for iteration in range(iterations): yhat = predict(x, weights, bias) dz = 2 * (yhat - y) @@ -66,26 +85,32 @@ def gradient_descent(x: np.ndarray, y: np.ndarray, weights: np.ndarray, bias: np bias -= learning_rate * db if iteration % 1000 == 0: - print(f'Cost after {iteration} iterations: {cost(y, yhat)}') - - print(f'Final cost: {cost(y, yhat)}\n') + print(f"Cost after {iteration} iterations: {cost(y, yhat)}") + + print(f"Final cost: {cost(y, yhat)}\n") return weights, bias + def test_gradient_descent(): - ''' + """ Prints actual output and predicted output side by side for a model. - ''' + """ global weights, bias - weights, bias = gradient_descent(train_x, train_y, weights, bias, - learning_rate=0.001, iterations=10000) - + weights, bias = gradient_descent( + train_x, train_y, weights, bias, learning_rate=0.001, iterations=10000 + ) + predictions = predict(test_x, weights, bias) print("Testing: ") for i in range(test_x.shape[-1]): - print(f'Actual output value: {test_y[0, i]} \tPredicted output value: {predictions[0, i]}') + print( + f"Actual output value: {test_y[0, i]} \tPredicted output value: {predictions[0, i]}" + ) print() -if __name__ == '__main__': + +if __name__ == "__main__": # test_gradient_descent() import doctest - doctest.testmod() \ No newline at end of file + + doctest.testmod() From fbe06e3d64f162848cd9aa72a2da6f1a124a58f5 Mon Sep 17 00:00:00 2001 From: Ankit Avinash Date: Wed, 18 Oct 2023 18:42:55 +0530 Subject: [PATCH 3/6] Fixed bug --- machine_learning/gradient_descent_without_loops.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/machine_learning/gradient_descent_without_loops.py b/machine_learning/gradient_descent_without_loops.py index 36b33de29244..f45ccdaf322b 100644 --- a/machine_learning/gradient_descent_without_loops.py +++ b/machine_learning/gradient_descent_without_loops.py @@ -82,7 +82,8 @@ def test_gradient_descent(): predictions = predict(test_x, weights, bias) print("Testing: ") for i in range(test_x.shape[-1]): - print(f'Actual output value: {test_y[0, i]} \tPredicted output value: {predictions[0, i]}') + print(f'Actual output value: {test_y[0, i]}\t\ + Predicted output value: {predictions[0, i]}') print() if __name__ == '__main__': From f6b7659d589b98cace6d6fffffdbd5e78e8340b4 Mon Sep 17 00:00:00 2001 From: Ankit Avinash Date: Wed, 18 Oct 2023 18:55:53 +0530 Subject: [PATCH 4/6] Fixed issue --- machine_learning/gradient_descent_without_loops.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/machine_learning/gradient_descent_without_loops.py b/machine_learning/gradient_descent_without_loops.py index 03e8e77adc26..360715319c1e 100644 --- a/machine_learning/gradient_descent_without_loops.py +++ b/machine_learning/gradient_descent_without_loops.py @@ -5,7 +5,7 @@ import numpy as np -def random_linear_function(x0, x1, x2): +def random_linear_function(x0: float, x1: float, x2: float) -> float: return -0.44562 * x0 + 1.07831 * x1 + 0.34078 * x2 - 0.60752 @@ -68,8 +68,8 @@ def gradient_descent( y: np.ndarray, weights: np.ndarray, bias: np.ndarray, - learning_rate=0.001, - iterations=10000, + learning_rate: float = 0.001, + iterations: int = 10000, ) -> tuple: """ Uses gradient descent to train the model. @@ -91,7 +91,7 @@ def gradient_descent( return weights, bias -def test_gradient_descent(): +def test_gradient_descent() -> None: """ Prints actual output and predicted output side by side for a model. """ @@ -105,9 +105,6 @@ def test_gradient_descent(): for i in range(test_x.shape[-1]): print(f'Actual output value: {test_y[0, i]}\t\ Predicted output value: {predictions[0, i]}') - print( - f"Actual output value: {test_y[0, i]} \tPredicted output value: {predictions[0, i]}" - ) print() From 55db3c19d058a9915e7fbb56adb88088a5cfd9c9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 13:26:41 +0000 Subject: [PATCH 5/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- machine_learning/gradient_descent_without_loops.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/machine_learning/gradient_descent_without_loops.py b/machine_learning/gradient_descent_without_loops.py index 360715319c1e..37ed3315e837 100644 --- a/machine_learning/gradient_descent_without_loops.py +++ b/machine_learning/gradient_descent_without_loops.py @@ -103,8 +103,10 @@ def test_gradient_descent() -> None: predictions = predict(test_x, weights, bias) print("Testing: ") for i in range(test_x.shape[-1]): - print(f'Actual output value: {test_y[0, i]}\t\ - Predicted output value: {predictions[0, i]}') + print( + f"Actual output value: {test_y[0, i]}\t\ + Predicted output value: {predictions[0, i]}" + ) print() From 61486c6d7c1654b60ff65611233c89cf88b4edfe Mon Sep 17 00:00:00 2001 From: Ankit Avinash Date: Wed, 18 Oct 2023 18:57:38 +0530 Subject: [PATCH 6/6] Fixed issue --- machine_learning/gradient_descent_without_loops.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/machine_learning/gradient_descent_without_loops.py b/machine_learning/gradient_descent_without_loops.py index 360715319c1e..f381a121a7bb 100644 --- a/machine_learning/gradient_descent_without_loops.py +++ b/machine_learning/gradient_descent_without_loops.py @@ -64,8 +64,8 @@ def cost(y_true: np.ndarray, y_predicted: np.ndarray) -> float: def gradient_descent( - x: np.ndarray, - y: np.ndarray, + input_x: np.ndarray, + output_y: np.ndarray, weights: np.ndarray, bias: np.ndarray, learning_rate: float = 0.001, @@ -77,17 +77,17 @@ def gradient_descent( Prints cost function every 1000 epochs. """ for iteration in range(iterations): - yhat = predict(x, weights, bias) - dz = 2 * (yhat - y) - dw = dz @ x.T / m + yhat = predict(input_x, weights, bias) + dz = 2 * (yhat - output_y) + dw = dz @ input_x.T / m db = np.mean(dz) weights -= learning_rate * dw bias -= learning_rate * db if iteration % 1000 == 0: - print(f"Cost after {iteration} iterations: {cost(y, yhat)}") + print(f"Cost after {iteration} iterations: {cost(output_y, yhat)}") - print(f"Final cost: {cost(y, yhat)}\n") + print(f"Final cost: {cost(output_y, yhat)}\n") return weights, bias